Comparing version 2.0.1 to 3.0.0
@@ -1,17 +0,17 @@ | ||
/*jshint regexp:false*/ | ||
/*global unescape*/ | ||
/* jshint regexp:false */ | ||
/* global unescape */ | ||
var isUtf8RegExp = /^utf-?8$/i, | ||
isLatin1RegExp = /^(?:iso-8859-1|latin1)$/i, | ||
iconvLite = require('iconv-lite'), | ||
rfc2047 = module.exports = {}; | ||
var isUtf8RegExp = /^utf-?8$/i; | ||
var isLatin1RegExp = /^(?:iso-8859-1|latin1)$/i; | ||
var iconvLite = require('iconv-lite'); | ||
var rfc2047 = (module.exports = {}); | ||
function stringify(obj) { | ||
if (typeof obj === 'string') { | ||
return obj; | ||
} else if (obj === null || typeof obj === 'undefined') { | ||
return ''; | ||
} else { | ||
return String(obj); | ||
} | ||
if (typeof obj === 'string') { | ||
return obj; | ||
} else if (obj === null || typeof obj === 'undefined') { | ||
return ''; | ||
} else { | ||
return String(obj); | ||
} | ||
} | ||
@@ -21,35 +21,38 @@ | ||
try { | ||
iconv = require('' + 'iconv'); // Prevent browserify from detecting iconv and failing | ||
iconv = require('' + 'iconv'); // Prevent browserify from detecting iconv and failing | ||
} catch (e) {} | ||
function decodeBuffer(encodedText, encoding) { | ||
if (encoding === 'q') { | ||
encodedText = encodedText.replace(/_/g, ' '); | ||
var numValidlyEncodedBytes = 0, | ||
i; | ||
for (i = 0 ; i < encodedText.length ; i += 1) { | ||
if (encodedText[i] === '=' && /^[0-9a-f]{2}$/i.test(encodedText.slice(i + 1, i + 3))) { | ||
numValidlyEncodedBytes += 1; | ||
} | ||
if (encoding === 'q') { | ||
encodedText = encodedText.replace(/_/g, ' '); | ||
var numValidlyEncodedBytes = 0; | ||
var i; | ||
for (i = 0; i < encodedText.length; i += 1) { | ||
if ( | ||
encodedText[i] === '=' && | ||
/^[0-9a-f]{2}$/i.test(encodedText.slice(i + 1, i + 3)) | ||
) { | ||
numValidlyEncodedBytes += 1; | ||
} | ||
} | ||
var buffer = Buffer.alloc(encodedText.length - numValidlyEncodedBytes * 2); | ||
var j = 0; | ||
for (i = 0; i < encodedText.length; i += 1) { | ||
if (encodedText[i] === '=') { | ||
var hexChars = encodedText.slice(i + 1, i + 3); | ||
if (/^[0-9a-f]{2}$/i.test(hexChars)) { | ||
buffer[j] = parseInt(encodedText.substr(i + 1, 2), 16); | ||
i += 2; | ||
} else { | ||
buffer[j] = encodedText.charCodeAt(i); | ||
} | ||
var buffer = new Buffer(encodedText.length - numValidlyEncodedBytes * 2), | ||
j = 0; | ||
for (i = 0 ; i < encodedText.length ; i += 1) { | ||
if (encodedText[i] === '=') { | ||
var hexChars = encodedText.slice(i + 1, i + 3); | ||
if (/^[0-9a-f]{2}$/i.test(hexChars)) { | ||
buffer[j] = parseInt(encodedText.substr(i + 1, 2), 16); | ||
i += 2; | ||
} else { | ||
buffer[j] = encodedText.charCodeAt(i); | ||
} | ||
} else { | ||
buffer[j] = encodedText.charCodeAt(i); | ||
} | ||
j += 1; | ||
} | ||
return buffer; | ||
} else { | ||
return new Buffer(encodedText, 'base64'); | ||
} else { | ||
buffer[j] = encodedText.charCodeAt(i); | ||
} | ||
j += 1; | ||
} | ||
return buffer; | ||
} else { | ||
return Buffer.from(encodedText, 'base64'); | ||
} | ||
} | ||
@@ -59,77 +62,91 @@ | ||
function decodeEncodedWord(encodedText, encoding, charset) { | ||
if (encoding === 'q' && isLatin1RegExp.test(charset)) { | ||
return unescape(encodedText.replace(/_/g, ' ').replace(/%/g, '%25').replace(/\=(?=[0-9a-f]{2})/gi, '%')); | ||
} else { | ||
var buffer; | ||
try { | ||
buffer = decodeBuffer(encodedText, encoding); | ||
} catch (e) { | ||
return; | ||
} | ||
if (/^ks_c_5601/i.test(charset)) { | ||
charset = 'CP949'; | ||
} | ||
var decoded; | ||
if (iconv) { | ||
var converter; | ||
try { | ||
converter = new iconv.Iconv(charset, 'utf-8//TRANSLIT'); | ||
} catch (e1) { | ||
// Assume EINVAL (unsupported charset) and fall back to assuming iso-8859-1: | ||
converter = new iconv.Iconv('iso-8859-1', 'utf-8//TRANSLIT'); | ||
} | ||
try { | ||
return converter.convert(buffer).toString('utf-8'); | ||
} catch (e2) { | ||
return; | ||
} | ||
} else if (isUtf8RegExp.test(charset)) { | ||
decoded = buffer.toString('utf-8'); | ||
if (!/\ufffd/.test(decoded)) { | ||
return decoded; | ||
} | ||
} else if (/^(?:us-)?ascii$/i.test(charset)) { | ||
return buffer.toString('ascii'); | ||
} else if (iconvLite.encodingExists(charset)) { | ||
decoded = iconvLite.decode(buffer, charset); | ||
if (!/\ufffd/.test(decoded)) { | ||
return decoded; | ||
} | ||
} | ||
if (encoding === 'q' && isLatin1RegExp.test(charset)) { | ||
return unescape( | ||
encodedText | ||
.replace(/_/g, ' ') | ||
.replace(/%/g, '%25') | ||
.replace(/=(?=[0-9a-f]{2})/gi, '%') | ||
); | ||
} else { | ||
var buffer; | ||
try { | ||
buffer = decodeBuffer(encodedText, encoding); | ||
} catch (e) { | ||
return; | ||
} | ||
if (/^ks_c_5601/i.test(charset)) { | ||
charset = 'CP949'; | ||
} | ||
var decoded; | ||
if (iconv) { | ||
var converter; | ||
try { | ||
converter = new iconv.Iconv(charset, 'utf-8//TRANSLIT'); | ||
} catch (e1) { | ||
// Assume EINVAL (unsupported charset) and fall back to assuming iso-8859-1: | ||
converter = new iconv.Iconv('iso-8859-1', 'utf-8//TRANSLIT'); | ||
} | ||
try { | ||
return converter.convert(buffer).toString('utf-8'); | ||
} catch (e2) {} | ||
} else if (isUtf8RegExp.test(charset)) { | ||
decoded = buffer.toString('utf-8'); | ||
if (!/\ufffd/.test(decoded)) { | ||
return decoded; | ||
} | ||
} else if (/^(?:us-)?ascii$/i.test(charset)) { | ||
return buffer.toString('ascii'); | ||
} else if (iconvLite.encodingExists(charset)) { | ||
decoded = iconvLite.decode(buffer, charset); | ||
if (!/\ufffd/.test(decoded)) { | ||
return decoded; | ||
} | ||
} | ||
} | ||
} | ||
var encodedWordRegExp = /\=\?([^\?]+)\?([QB])\?([^\?]*)\?=/gi; | ||
var encodedWordRegExp = /=\?([^?]+)\?([QB])\?([^?]*)\?=/gi; | ||
rfc2047.decode = function (text) { | ||
text = stringify(text).replace(/\?\=\s+\=\?/g, '?==?'); // Strip whitespace between neighbouring encoded words | ||
text = stringify(text).replace(/\?=\s+=\?/g, '?==?'); // Strip whitespace between neighbouring encoded words | ||
var numEncodedWordsToIgnore = 0; | ||
var numEncodedWordsToIgnore = 0; | ||
return text.replace(encodedWordRegExp, function (encodedWord, charset, encoding, encodedText, index) { | ||
if (numEncodedWordsToIgnore > 0) { | ||
numEncodedWordsToIgnore -= 1; | ||
return ''; | ||
} | ||
encoding = encoding.toLowerCase(); | ||
var decodedTextOrBuffer = decodeEncodedWord(encodedText, encoding, charset); | ||
while (typeof decodedTextOrBuffer !== 'string') { | ||
// The encoded word couldn't be decoded because it contained a partial character in a multibyte charset. | ||
// Keep trying to look ahead and consume an additional encoded word right after this one, and if its | ||
// encoding and charsets match, try to decode the concatenation. | ||
return text.replace(encodedWordRegExp, function ( | ||
encodedWord, | ||
charset, | ||
encoding, | ||
encodedText, | ||
index | ||
) { | ||
if (numEncodedWordsToIgnore > 0) { | ||
numEncodedWordsToIgnore -= 1; | ||
return ''; | ||
} | ||
encoding = encoding.toLowerCase(); | ||
var decodedTextOrBuffer = decodeEncodedWord(encodedText, encoding, charset); | ||
while (typeof decodedTextOrBuffer !== 'string') { | ||
// The encoded word couldn't be decoded because it contained a partial character in a multibyte charset. | ||
// Keep trying to look ahead and consume an additional encoded word right after this one, and if its | ||
// encoding and charsets match, try to decode the concatenation. | ||
// The ongoing replace call is unaffected by this trick, so we don't need to reset .lastIndex afterwards: | ||
encodedWordRegExp.lastIndex = index + encodedWord.length; | ||
var matchNextEncodedWord = encodedWordRegExp.exec(text); | ||
if (matchNextEncodedWord && matchNextEncodedWord.index === index + encodedWord.length && matchNextEncodedWord[1] === charset && matchNextEncodedWord[2].toLowerCase() === encoding) { | ||
numEncodedWordsToIgnore += 1; | ||
encodedWord += matchNextEncodedWord[0]; | ||
encodedText += matchNextEncodedWord[3]; | ||
decodedTextOrBuffer = decodeEncodedWord(encodedText, encoding, charset); | ||
} else { | ||
return encodedWord; | ||
} | ||
} | ||
return decodedTextOrBuffer; | ||
}); | ||
// The ongoing replace call is unaffected by this trick, so we don't need to reset .lastIndex afterwards: | ||
encodedWordRegExp.lastIndex = index + encodedWord.length; | ||
var matchNextEncodedWord = encodedWordRegExp.exec(text); | ||
if ( | ||
matchNextEncodedWord && | ||
matchNextEncodedWord.index === index + encodedWord.length && | ||
matchNextEncodedWord[1] === charset && | ||
matchNextEncodedWord[2].toLowerCase() === encoding | ||
) { | ||
numEncodedWordsToIgnore += 1; | ||
encodedWord += matchNextEncodedWord[0]; | ||
encodedText += matchNextEncodedWord[3]; | ||
decodedTextOrBuffer = decodeEncodedWord(encodedText, encoding, charset); | ||
} else { | ||
return encodedWord; | ||
} | ||
} | ||
return decodedTextOrBuffer; | ||
}); | ||
}; | ||
@@ -143,21 +160,25 @@ | ||
// Initialize array used as lookup table (int (octet) => string) | ||
var qpTokenByOctet = new Array(256), | ||
i; | ||
var qpTokenByOctet = new Array(256); | ||
var i; | ||
for (i = 0 ; i < 256 ; i += 1) { | ||
qpTokenByOctet[i] = "=" + (i < 16 ? "0" : "") + i.toString(16).toUpperCase(); | ||
for (i = 0; i < 256; i += 1) { | ||
qpTokenByOctet[i] = `=${i < 16 ? '0' : ''}${i.toString(16).toUpperCase()}`; | ||
} | ||
"!#$%&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz{|}~".split(/(?:)/).forEach(function (encodedWordSafeAsciiChar) { | ||
qpTokenByOctet[encodedWordSafeAsciiChar.charCodeAt(0)] = encodedWordSafeAsciiChar; | ||
}); | ||
"!#$%&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^`abcdefghijklmnopqrstuvwxyz{|}~" | ||
.split(/(?:)/) | ||
.forEach(function (encodedWordSafeAsciiChar) { | ||
qpTokenByOctet[ | ||
encodedWordSafeAsciiChar.charCodeAt(0) | ||
] = encodedWordSafeAsciiChar; | ||
}); | ||
qpTokenByOctet[32] = "_"; | ||
qpTokenByOctet[32] = '_'; | ||
function bufferToQuotedPrintableString(buffer) { | ||
var result = ''; | ||
for (var i = 0 ; i < buffer.length ; i += 1) { | ||
result += qpTokenByOctet[buffer[i]]; | ||
} | ||
return result; | ||
var result = ''; | ||
for (var i = 0; i < buffer.length; i += 1) { | ||
result += qpTokenByOctet[buffer[i]]; | ||
} | ||
return result; | ||
} | ||
@@ -167,73 +188,82 @@ | ||
var headerSafeAsciiChars = " !\"#$%&'()*+-,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", | ||
headerUnsafeAsciiChars = ""; | ||
var headerSafeAsciiChars = | ||
' !"#$%&\'()*+-,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; | ||
var headerUnsafeAsciiChars = ''; | ||
for (i = 0 ; i < 128 ; i += 1) { | ||
var ch = String.fromCharCode(i); | ||
if (headerSafeAsciiChars.indexOf(ch) === -1) { // O(n^2) but only happens at startup | ||
headerUnsafeAsciiChars += ch; | ||
} | ||
for (i = 0; i < 128; i += 1) { | ||
var ch = String.fromCharCode(i); | ||
if (headerSafeAsciiChars.indexOf(ch) === -1) { | ||
// O(n^2) but only happens at startup | ||
headerUnsafeAsciiChars += ch; | ||
} | ||
} | ||
function quoteCharacterClass(chars) { | ||
return chars.replace(/[\\\|\^\*\+\?\[\]\(\)\-\.]/g, "\\$&"); | ||
return chars.replace(/[\\|^*+?[\]().-]/g, '\\$&'); | ||
} | ||
var unsafeTokenRegExp = new RegExp("[\u0080-\uffff" + quoteCharacterClass(headerUnsafeAsciiChars) + "]"), | ||
maxNumCharsPerEncodedWord = 8; // Very conservative limit to prevent creating an encoded word of more than 72 ascii chars | ||
var unsafeTokenRegExp = new RegExp( | ||
`[\u0080-\uffff${quoteCharacterClass(headerUnsafeAsciiChars)}]` | ||
); | ||
var maxNumCharsPerEncodedWord = 8; // Very conservative limit to prevent creating an encoded word of more than 72 ascii chars | ||
rfc2047.encode = function (text) { | ||
text = stringify(text) | ||
.replace(/\s/g, ' '); // Normalize whitespace | ||
var tokens = text.match(/([^\s]*\s*)/g), // Split at space, but keep trailing space as part of each token | ||
previousTokenWasEncodedWord = false, // Consecutive encoded words must have a space between them, so this state must be kept | ||
previousTokenWasWhitespaceFollowingEncodedWord = false, | ||
result = ''; | ||
if (tokens) { | ||
for (var i = 0 ; i < tokens.length ; i += 1) { | ||
var token = tokens[i]; | ||
if (unsafeTokenRegExp.test(token)) { | ||
var matchQuotesAtBeginning = token.match(/^"+/); | ||
if (matchQuotesAtBeginning) { | ||
previousTokenWasEncodedWord = false; | ||
result += matchQuotesAtBeginning[0]; | ||
tokens[i] = token = token.substr(matchQuotesAtBeginning[0].length); | ||
tokens.splice(i, 0, matchQuotesAtBeginning[0]); | ||
i += 1; | ||
} | ||
text = stringify(text).replace(/\s/g, ' '); // Normalize whitespace | ||
var tokens = text.match(/([^\s]*\s*)/g); // Split at space, but keep trailing space as part of each token | ||
var previousTokenWasEncodedWord = false; // Consecutive encoded words must have a space between them, so this state must be kept | ||
var previousTokenWasWhitespaceFollowingEncodedWord = false; | ||
var result = ''; | ||
if (tokens) { | ||
for (var i = 0; i < tokens.length; i += 1) { | ||
var token = tokens[i]; | ||
if (unsafeTokenRegExp.test(token)) { | ||
var matchQuotesAtBeginning = token.match(/^"+/); | ||
if (matchQuotesAtBeginning) { | ||
previousTokenWasEncodedWord = false; | ||
result += matchQuotesAtBeginning[0]; | ||
tokens[i] = token = token.substr(matchQuotesAtBeginning[0].length); | ||
tokens.splice(i, 0, matchQuotesAtBeginning[0]); | ||
i += 1; | ||
} | ||
var matchWhitespaceOrQuotesAtEnd = token.match(/\\?[\s"]+$/); | ||
if (matchWhitespaceOrQuotesAtEnd) { | ||
tokens.splice(i + 1, 0, matchWhitespaceOrQuotesAtEnd[0]); | ||
token = token.substr(0, token.length - matchWhitespaceOrQuotesAtEnd[0].length); | ||
} | ||
var matchWhitespaceOrQuotesAtEnd = token.match(/\\?[\s"]+$/); | ||
if (matchWhitespaceOrQuotesAtEnd) { | ||
tokens.splice(i + 1, 0, matchWhitespaceOrQuotesAtEnd[0]); | ||
token = token.substr( | ||
0, | ||
token.length - matchWhitespaceOrQuotesAtEnd[0].length | ||
); | ||
} | ||
// Word contains at least one header unsafe char, an encoded word must be created. | ||
if (token.length > maxNumCharsPerEncodedWord) { | ||
tokens.splice(i + 1, 0, token.substr(maxNumCharsPerEncodedWord)); | ||
token = token.substr(0, maxNumCharsPerEncodedWord); | ||
} | ||
// Word contains at least one header unsafe char, an encoded word must be created. | ||
if (token.length > maxNumCharsPerEncodedWord) { | ||
tokens.splice(i + 1, 0, token.substr(maxNumCharsPerEncodedWord)); | ||
token = token.substr(0, maxNumCharsPerEncodedWord); | ||
} | ||
if (previousTokenWasWhitespaceFollowingEncodedWord) { | ||
token = " " + token; | ||
} | ||
if (previousTokenWasWhitespaceFollowingEncodedWord) { | ||
token = ` ${token}`; | ||
} | ||
var charset = 'utf-8'; | ||
// Around 25% faster than encodeURIComponent(token.replace(/ /g, "_")).replace(/%/g, "="): | ||
var encodedWordBody = bufferToQuotedPrintableString(new Buffer(token, 'utf-8')); | ||
if (previousTokenWasEncodedWord) { | ||
result += ' '; | ||
} | ||
result += "=?" + charset + "?Q?" + encodedWordBody + "?="; | ||
previousTokenWasWhitespaceFollowingEncodedWord = false; | ||
previousTokenWasEncodedWord = true; | ||
} else { | ||
// Word only contains header safe chars, no need to encode: | ||
result += token; | ||
previousTokenWasWhitespaceFollowingEncodedWord = /^\s*$/.test(token) && previousTokenWasEncodedWord; | ||
previousTokenWasEncodedWord = false; | ||
} | ||
var charset = 'utf-8'; | ||
// Around 25% faster than encodeURIComponent(token.replace(/ /g, "_")).replace(/%/g, "="): | ||
var encodedWordBody = bufferToQuotedPrintableString( | ||
Buffer.from(token, 'utf-8') | ||
); | ||
if (previousTokenWasEncodedWord) { | ||
result += ' '; | ||
} | ||
result += `=?${charset}?Q?${encodedWordBody}?=`; | ||
previousTokenWasWhitespaceFollowingEncodedWord = false; | ||
previousTokenWasEncodedWord = true; | ||
} else { | ||
// Word only contains header safe chars, no need to encode: | ||
result += token; | ||
previousTokenWasWhitespaceFollowingEncodedWord = | ||
/^\s*$/.test(token) && previousTokenWasEncodedWord; | ||
previousTokenWasEncodedWord = false; | ||
} | ||
} | ||
return result; | ||
} | ||
return result; | ||
}; |
{ | ||
"name": "rfc2047", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "Encode and decode rfc2047 (MIME encoded words)", | ||
@@ -10,6 +10,6 @@ "main": "lib/rfc2047.js", | ||
"scripts": { | ||
"lint": "jshint .", | ||
"test": "mocha && npm run lint", | ||
"travis": "npm test && npm run coverage && <coverage/lcov.info coveralls", | ||
"coverage": "NODE_ENV=development istanbul cover _mocha -- --reporter dot && echo google-chrome coverage/lcov-report/index.html" | ||
"lint": "eslint . && prettier --check '**/*.{js,md,json}'", | ||
"test": "mocha", | ||
"test:ci": "npm run coverage", | ||
"coverage": "nyc --reporter=lcov --reporter=text --all -- npm test && echo google-chrome coverage/lcov-report/index.html" | ||
}, | ||
@@ -30,3 +30,3 @@ "repository": { | ||
], | ||
"author": "Andreas Lind <andreas@one.com>", | ||
"author": "Andreas Lind <andreaslindpetersen@gmail.com>", | ||
"license": "BSD", | ||
@@ -38,7 +38,15 @@ "bugs": { | ||
"devDependencies": { | ||
"coveralls": "2.11.2", | ||
"iconv": "2.2.1", | ||
"istanbul": "0.3.5", | ||
"jshint": "2.5.11", | ||
"coveralls": "^2.11.2", | ||
"eslint": "^7.10.0", | ||
"eslint-config-prettier": "^6.12.0", | ||
"eslint-config-standard": "^14.1.1", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-mocha": "^8.0.0", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-promise": "^4.2.1", | ||
"eslint-plugin-standard": "^4.0.1", | ||
"iconv": "^3.0.0", | ||
"mocha": "2.1.0", | ||
"nyc": "^15.1.0", | ||
"prettier": "^2.1.2", | ||
"unexpected": "10.20.0" | ||
@@ -48,3 +56,8 @@ }, | ||
"iconv-lite": "0.4.5" | ||
}, | ||
"nyc": { | ||
"include": [ | ||
"lib/**" | ||
] | ||
} | ||
} |
@@ -1,3 +0,2 @@ | ||
rfc2047 | ||
======= | ||
# rfc2047 | ||
@@ -12,3 +11,5 @@ Encode and decode [rfc2047](https://www.ietf.org/rfc/rfc2047.txt) (MIME encoded words). | ||
console.log(rfc2047.decode('=?iso-8859-1?Q?=A1?=Hola, se=?iso-8859-1?Q?=F1?=or!')); | ||
console.log( | ||
rfc2047.decode('=?iso-8859-1?Q?=A1?=Hola, se=?iso-8859-1?Q?=F1?=or!') | ||
); | ||
// ¡Hola, señor! | ||
@@ -15,0 +16,0 @@ ``` |
@@ -1,212 +0,344 @@ | ||
/*global describe, it*/ | ||
var unexpected = require('unexpected'), | ||
rfc2047 = require('../lib/rfc2047'); | ||
/* global describe, it */ | ||
var unexpected = require('unexpected'); | ||
var rfc2047 = require('../lib/rfc2047'); | ||
describe('rfc2047', function () { | ||
var expect = unexpected.clone().addAssertion('to encode to', function (expect, subject, value) { | ||
expect(rfc2047.encode(subject), 'to equal', value); | ||
}).addAssertion('to decode to', function (expect, subject, value) { | ||
expect(rfc2047.decode(subject), 'to equal', value); | ||
}).addAssertion('to encode back and forth to', function (expect, subject, value) { | ||
expect(subject, 'to encode to', value); | ||
expect(value, 'to decode to', subject); | ||
var expect = unexpected | ||
.clone() | ||
.addAssertion('to encode to', function (expect, subject, value) { | ||
expect(rfc2047.encode(subject), 'to equal', value); | ||
}) | ||
.addAssertion('to decode to', function (expect, subject, value) { | ||
expect(rfc2047.decode(subject), 'to equal', value); | ||
}) | ||
.addAssertion('to encode back and forth to', function ( | ||
expect, | ||
subject, | ||
value | ||
) { | ||
expect(subject, 'to encode to', value); | ||
expect(value, 'to decode to', subject); | ||
}); | ||
describe('#encode() and #decode()', function () { | ||
it('should handle the empty string', function () { | ||
expect('', 'to encode back and forth to', ''); | ||
}); | ||
describe('#encode() and #decode()', function () { | ||
it('should handle the empty string', function () { | ||
expect('', 'to encode back and forth to', ''); | ||
}); | ||
it('should handle a string only containing a space', function () { | ||
expect(' ', 'to encode back and forth to', ' '); | ||
}); | ||
it('should handle a string only containing a space', function () { | ||
expect(' ', 'to encode back and forth to', ' '); | ||
}); | ||
it('should not encode an equals sign', function () { | ||
expect('=', 'to encode back and forth to', '='); | ||
}); | ||
it('should not encode an equals sign', function () { | ||
expect('=', 'to encode back and forth to', '='); | ||
}); | ||
it('should handle a string that does not need to be encoded', function () { | ||
expect('Andreas Lind <andreas@one.com>', 'to encode back and forth to', 'Andreas Lind <andreas@one.com>'); | ||
}); | ||
it('should handle a string that does not need to be encoded', function () { | ||
expect( | ||
'Andreas Lind <andreas@one.com>', | ||
'to encode back and forth to', | ||
'Andreas Lind <andreas@one.com>' | ||
); | ||
}); | ||
it('should handle a multi-word string where the middle word has to be encoded', function () { | ||
expect('Andreas Lindø <andreas@one.com>', 'to encode back and forth to', 'Andreas =?utf-8?Q?Lind=C3=B8?= <andreas@one.com>'); | ||
}); | ||
it('should handle a multi-word string where the middle word has to be encoded', function () { | ||
expect( | ||
'Andreas Lindø <andreas@one.com>', | ||
'to encode back and forth to', | ||
'Andreas =?utf-8?Q?Lind=C3=B8?= <andreas@one.com>' | ||
); | ||
}); | ||
it('should use an UTF-8 encoded word when a character is not in iso-8859-1', function () { | ||
expect('Mr. Smiley face aka ☺ <smiley@face.dk>', 'to encode back and forth to', 'Mr. Smiley face aka =?utf-8?Q?=E2=98=BA?= <smiley@face.dk>'); | ||
}); | ||
it('should use an UTF-8 encoded word when a character is not in iso-8859-1', function () { | ||
expect( | ||
'Mr. Smiley face aka ☺ <smiley@face.dk>', | ||
'to encode back and forth to', | ||
'Mr. Smiley face aka =?utf-8?Q?=E2=98=BA?= <smiley@face.dk>' | ||
); | ||
}); | ||
it('should handle two neighbouring words that have to be encoded', function () { | ||
expect('¡Hola, señor!', 'to encode back and forth to', '=?utf-8?Q?=C2=A1Hola=2C?= =?utf-8?Q?_se=C3=B1or!?='); | ||
expect('På lördag', 'to encode back and forth to', '=?utf-8?Q?P=C3=A5?= =?utf-8?Q?_l=C3=B6rdag?='); | ||
}); | ||
it('should handle two neighbouring words that have to be encoded', function () { | ||
expect( | ||
'¡Hola, señor!', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?=C2=A1Hola=2C?= =?utf-8?Q?_se=C3=B1or!?=' | ||
); | ||
expect( | ||
'På lördag', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?P=C3=A5?= =?utf-8?Q?_l=C3=B6rdag?=' | ||
); | ||
}); | ||
it('should not rely on the space between neighbouring encoded words to be preserved', function () { | ||
expect('☺ ☺', 'to encode back and forth to', '=?utf-8?Q?=E2=98=BA?= =?utf-8?Q?_=E2=98=BA?='); | ||
}); | ||
it('should not rely on the space between neighbouring encoded words to be preserved', function () { | ||
expect( | ||
'☺ ☺', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?=E2=98=BA?= =?utf-8?Q?_=E2=98=BA?=' | ||
); | ||
}); | ||
it('should handle some dreamed up edge cases', function () { | ||
expect('lördag', 'to encode back and forth to', '=?utf-8?Q?l=C3=B6rdag?='); | ||
}); | ||
it('should handle some dreamed up edge cases', function () { | ||
expect( | ||
'lördag', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?l=C3=B6rdag?=' | ||
); | ||
}); | ||
it('should handle a multi-word string where the middle word has to be left unencoded', function () { | ||
expect('Så er fødselen i gang', 'to encode back and forth to', '=?utf-8?Q?S=C3=A5?= er =?utf-8?Q?f=C3=B8dselen?= i gang'); | ||
}); | ||
it('should handle a multi-word string where the middle word has to be left unencoded', function () { | ||
expect( | ||
'Så er fødselen i gang', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?S=C3=A5?= er =?utf-8?Q?f=C3=B8dselen?= i gang' | ||
); | ||
}); | ||
it('should place leading quotes correctly', function () { | ||
expect('"ÅÄÖ" <sss@example.com>', 'to encode back and forth to', '"=?utf-8?Q?=C3=85=C3=84=C3=96?=" <sss@example.com>'); | ||
}); | ||
it('should place leading quotes correctly', function () { | ||
expect( | ||
'"ÅÄÖ" <sss@example.com>', | ||
'to encode back and forth to', | ||
'"=?utf-8?Q?=C3=85=C3=84=C3=96?=" <sss@example.com>' | ||
); | ||
}); | ||
it('should place trailing quotes correctly', function () { | ||
expect('"TEST ÅÄÖ" <sss@example.com>', 'to encode back and forth to', '"TEST =?utf-8?Q?=C3=85=C3=84=C3=96?=" <sss@example.com>'); | ||
}); | ||
it('should place trailing quotes correctly', function () { | ||
expect( | ||
'"TEST ÅÄÖ" <sss@example.com>', | ||
'to encode back and forth to', | ||
'"TEST =?utf-8?Q?=C3=85=C3=84=C3=96?=" <sss@example.com>' | ||
); | ||
}); | ||
// Regression test for #2: | ||
it('should handle an emoji test case', function () { | ||
expect('{"tags":"","fullName":"😬"}', 'to encode back and forth to', '=?utf-8?Q?{=22tags=22=3A?=""=?utf-8?Q?=2C=22fullNa?= =?utf-8?Q?me=22=3A=22=F0=9F=98=AC=22?=}'); | ||
}); | ||
// Regression test for #2: | ||
it('should handle an emoji test case', function () { | ||
expect( | ||
'{"tags":"","fullName":"😬"}', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?{=22tags=22=3A?=""=?utf-8?Q?=2C=22fullNa?= =?utf-8?Q?me=22=3A=22=F0=9F=98=AC=22?=}' | ||
); | ||
}); | ||
describe('#encode()', function () { | ||
it('should handle non-string values correctly', function () { | ||
expect(-1, 'to encode to', '-1'); | ||
expect(Infinity, 'to encode to', 'Infinity'); | ||
expect(false, 'to encode to', 'false'); | ||
expect(true, 'to encode to', 'true'); | ||
expect(/bla/, 'to encode to', '/bla/'); | ||
expect(undefined, 'to encode to', ''); | ||
expect(null, 'to encode to', ''); | ||
}); | ||
it('should handle the replacement character', function () { | ||
expect( | ||
'test_�.docx', | ||
'to encode back and forth to', | ||
'=?utf-8?Q?test=5F=EF=BF=BD=2Ed?=ocx' | ||
); | ||
}); | ||
}); | ||
it('should handle a tab character at the beginning of a word', function () { | ||
expect('\tfoo', 'to encode to', ' foo'); | ||
}); | ||
describe('#encode()', function () { | ||
it('should handle non-string values correctly', function () { | ||
expect(-1, 'to encode to', '-1'); | ||
expect(Infinity, 'to encode to', 'Infinity'); | ||
expect(false, 'to encode to', 'false'); | ||
expect(true, 'to encode to', 'true'); | ||
expect(/bla/, 'to encode to', '/bla/'); | ||
expect(undefined, 'to encode to', ''); | ||
expect(null, 'to encode to', ''); | ||
}); | ||
it('should handle control chars', function () { | ||
expect( | ||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f', | ||
'to encode to', | ||
'=?utf-8?Q?=00=01=02=03=04=05=06=07?= =?utf-8?Q?=08?= =?utf-8?Q?_=0E=0F=10=11=12=13=14=15?= =?utf-8?Q?=16=17=18=19=1A=1B=1C=1D?= =?utf-8?Q?=1E=1F?=' | ||
); | ||
}); | ||
it('should handle a tab character at the beginning of a word', function () { | ||
expect('\tfoo', 'to encode to', ' foo'); | ||
}); | ||
it('should handle a tab character at the end of a word', function () { | ||
expect('foo\t', 'to encode to', 'foo '); | ||
}); | ||
it('should handle control chars', function () { | ||
expect( | ||
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f', | ||
'to encode to', | ||
'=?utf-8?Q?=00=01=02=03=04=05=06=07?= =?utf-8?Q?=08?= =?utf-8?Q?_=0E=0F=10=11=12=13=14=15?= =?utf-8?Q?=16=17=18=19=1A=1B=1C=1D?= =?utf-8?Q?=1E=1F?=' | ||
); | ||
}); | ||
it('should handle a tab character with spaces around it', function () { | ||
expect('bar \t foo', 'to encode to', 'bar foo'); | ||
}); | ||
it('should handle a tab character at the end of a word', function () { | ||
expect('foo\t', 'to encode to', 'foo '); | ||
}); | ||
it('should not split a backslash from the doublequote it is escaping', function () { | ||
expect('"Öland\\""', 'to encode to', '"=?utf-8?Q?=C3=96land?=\\""'); | ||
}); | ||
it('should handle a tab character with spaces around it', function () { | ||
expect('bar \t foo', 'to encode to', 'bar foo'); | ||
}); | ||
describe('#decode()', function () { | ||
it('should handle non-string values correctly', function () { | ||
expect(-1, 'to decode to', '-1'); | ||
expect(Infinity, 'to decode to', 'Infinity'); | ||
expect(false, 'to decode to', 'false'); | ||
expect(true, 'to decode to', 'true'); | ||
expect(/bla/, 'to decode to', '/bla/'); | ||
expect(undefined, 'to decode to', ''); | ||
expect(null, 'to decode to', ''); | ||
}); | ||
it('should not split a backslash from the doublequote it is escaping', function () { | ||
expect('"Öland\\""', 'to encode to', '"=?utf-8?Q?=C3=96land?=\\""'); | ||
}); | ||
}); | ||
it('should decode encoded word with invalid quoted-printable, decodeURIComponent case', function () { | ||
expect('=?UTF-8?Q?=xxfoo?=', 'to decode to', '=xxfoo'); | ||
}); | ||
describe('#decode()', function () { | ||
it('should handle non-string values correctly', function () { | ||
expect(-1, 'to decode to', '-1'); | ||
expect(Infinity, 'to decode to', 'Infinity'); | ||
expect(false, 'to decode to', 'false'); | ||
expect(true, 'to decode to', 'true'); | ||
expect(/bla/, 'to decode to', '/bla/'); | ||
expect(undefined, 'to decode to', ''); | ||
expect(null, 'to decode to', ''); | ||
}); | ||
it('should decode encoded word with invalid quoted-printable, unescape case', function () { | ||
expect('=?iso-8859-1?Q?=xxfoo?=', 'to decode to', '=xxfoo'); | ||
}); | ||
it('should decode encoded word with invalid quoted-printable, decodeURIComponent case', function () { | ||
expect('=?UTF-8?Q?=xxfoo?=', 'to decode to', '=xxfoo'); | ||
}); | ||
it('should decode encoded word with invalid base64', function () { | ||
expect('=?iso-8859-1?B?\u0000``?=', 'to decode to', ''); | ||
}); | ||
it('should decode encoded word with invalid quoted-printable, unescape case', function () { | ||
expect('=?iso-8859-1?Q?=xxfoo?=', 'to decode to', '=xxfoo'); | ||
}); | ||
it('should decode separated encoded words', function () { | ||
expect( | ||
'=?utf-8?Q?One.com=E2=80?= =?utf-8?Q?=99s_=E2=80=9CDon=E2=80=99t_screw_it_up=E2=80=9D_?= =?utf-8?Q?code?=', | ||
'to decode to', | ||
'One.com’s “Don’t screw it up” code' | ||
); | ||
}); | ||
it('should decode encoded word with invalid base64', function () { | ||
expect('=?iso-8859-1?B?\u0000``?=', 'to decode to', ''); | ||
}); | ||
it('should handle the test cases listed in RFC 2047', function () { | ||
expect('=?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>', 'to decode to', 'Olle Järnefors <ojarnef@admin.kth.se>'); | ||
expect('=?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>', 'to decode to', 'Patrik Fältström <paf@nada.kth.se>'); | ||
expect('Nathaniel Borenstein <nsb@thumper.bellcore.com> (=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=)', 'to decode to', 'Nathaniel Borenstein <nsb@thumper.bellcore.com> (םולש ןב ילטפנ)'); | ||
expect('(=?ISO-8859-1?Q?a?=)', 'to decode to', '(a)'); | ||
expect('(=?ISO-8859-1?Q?a?= b)', 'to decode to', '(a b)'); | ||
expect('(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)', 'to decode to', '(ab)'); | ||
expect('(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)', 'to decode to', '(ab)'); | ||
expect('(=?ISO-8859-1?Q?a_b?=)', 'to decode to', '(a b)'); | ||
expect('(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)', 'to decode to', '(a b)'); | ||
}); | ||
it('should decode separated encoded words', function () { | ||
expect( | ||
'=?utf-8?Q?One.com=E2=80?= =?utf-8?Q?=99s_=E2=80=9CDon=E2=80=99t_screw_it_up=E2=80=9D_?= =?utf-8?Q?code?=', | ||
'to decode to', | ||
'One.com’s “Don’t screw it up” code' | ||
); | ||
}); | ||
it('should handle subject found in mail with X-Mailer: MailChimp Mailer', function () { | ||
expect('=?utf-8?Q?Spar=2020=20%=20p=C3=A5=20de=20bedste=20businessb=C3=B8ger=20fra=20Gyldendal=21?=', 'to decode to', 'Spar 20 % på de bedste businessbøger fra Gyldendal!'); | ||
expect('=?iso-8859-1?Q?Spar 20 %...?=', 'to decode to', 'Spar 20 %...'); | ||
}); | ||
it('should handle the test cases listed in RFC 2047', function () { | ||
expect( | ||
'=?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>', | ||
'to decode to', | ||
'Olle Järnefors <ojarnef@admin.kth.se>' | ||
); | ||
expect( | ||
'=?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>', | ||
'to decode to', | ||
'Patrik Fältström <paf@nada.kth.se>' | ||
); | ||
expect( | ||
'Nathaniel Borenstein <nsb@thumper.bellcore.com> (=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=)', | ||
'to decode to', | ||
'Nathaniel Borenstein <nsb@thumper.bellcore.com> (םולש ןב ילטפנ)' | ||
); | ||
expect('(=?ISO-8859-1?Q?a?=)', 'to decode to', '(a)'); | ||
expect('(=?ISO-8859-1?Q?a?= b)', 'to decode to', '(a b)'); | ||
expect('(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)', 'to decode to', '(ab)'); | ||
expect( | ||
'(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)', | ||
'to decode to', | ||
'(ab)' | ||
); | ||
expect('(=?ISO-8859-1?Q?a_b?=)', 'to decode to', '(a b)'); | ||
expect( | ||
'(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)', | ||
'to decode to', | ||
'(a b)' | ||
); | ||
}); | ||
it('should handle multiple base64 encoded words issued by Thunderbird', function () { | ||
expect( | ||
'=?UTF-8?B?Rm9vw6YsIEZvbyDDpiwgw6bDuMOmw7jDpsO4w6bDuMOmw7jDpsO4LCA=?==?UTF-8?B?4pi6IE1y4pi6IOKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYug==?= =?UTF-8?B?4pi64pi64pi64pi64pi64pi64pi6?=', | ||
'to decode to', | ||
'Fooæ, Foo æ, æøæøæøæøæøæø, ☺ Mr☺ ☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺' | ||
); | ||
}); | ||
it('should handle subject found in mail with X-Mailer: MailChimp Mailer', function () { | ||
expect( | ||
'=?utf-8?Q?Spar=2020=20%=20p=C3=A5=20de=20bedste=20businessb=C3=B8ger=20fra=20Gyldendal=21?=', | ||
'to decode to', | ||
'Spar 20 % på de bedste businessbøger fra Gyldendal!' | ||
); | ||
expect('=?iso-8859-1?Q?Spar 20 %...?=', 'to decode to', 'Spar 20 %...'); | ||
}); | ||
it('should handle two back-to-back UTF-8 encoded words from the subject in a raygun mail', function () { | ||
expect('=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?==?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?=', 'to decode to', 'webmail production - new error - Geçersiz değişken.'); | ||
}); | ||
it('should handle multiple base64 encoded words issued by Thunderbird', function () { | ||
expect( | ||
'=?UTF-8?B?Rm9vw6YsIEZvbyDDpiwgw6bDuMOmw7jDpsO4w6bDuMOmw7jDpsO4LCA=?==?UTF-8?B?4pi6IE1y4pi6IOKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYuuKYug==?= =?UTF-8?B?4pi64pi64pi64pi64pi64pi64pi6?=', | ||
'to decode to', | ||
'Fooæ, Foo æ, æøæøæøæøæøæø, ☺ Mr☺ ☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺' | ||
); | ||
}); | ||
it('should keep encoded words with partial sequences separate if there is text between them', function () { | ||
expect('=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?=foo=?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?=', 'to decode to', '=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?=foo=?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?='); | ||
}); | ||
it('should handle two back-to-back UTF-8 encoded words from the subject in a raygun mail', function () { | ||
expect( | ||
'=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?==?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?=', | ||
'to decode to', | ||
'webmail production - new error - Geçersiz değişken.' | ||
); | ||
}); | ||
it('should decode a UTF-8 smiley (illegally) split up into 2 encoded words', function () { | ||
expect('=?utf-8?Q?=E2=98?= =?utf-8?Q?=BA?=', 'to decode to', '☺'); | ||
}); | ||
it('should keep encoded words with partial sequences separate if there is text between them', function () { | ||
expect( | ||
'=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?=foo=?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?=', | ||
'to decode to', | ||
'=?utf-8?B?d2VibWFpbCBwcm9kdWN0aW9uIC0gbmV3IGVycm9yIC0gR2XD?=foo=?utf-8?B?p2Vyc2l6IGRlxJ9pxZ9rZW4u?=' | ||
); | ||
}); | ||
it('should decode a UTF-8 smiley (illegally) split up into 3 encoded words', function () { | ||
expect('=?utf-8?Q?=E2?= =?utf-8?Q?=98?= =?utf-8?Q?=BA?=', 'to decode to', '☺'); | ||
}); | ||
it('should decode a UTF-8 smiley (illegally) split up into 2 encoded words', function () { | ||
expect('=?utf-8?Q?=E2=98?= =?utf-8?Q?=BA?=', 'to decode to', '☺'); | ||
}); | ||
it('should give up decoding a UTF-8 smiley (illegally) split up into 3 encoded words if there is regular text between the encoded words', function () { | ||
expect('=?utf-8?Q?=E2?= =?utf-8?Q?=98?=a=?utf-8?Q?=BA?==?utf-8?Q?=BA?=a', 'to decode to', '=?utf-8?Q?=E2?==?utf-8?Q?=98?=a=?utf-8?Q?=BA?==?utf-8?Q?=BA?=a'); | ||
}); | ||
it('should decode a UTF-8 smiley (illegally) split up into 3 encoded words', function () { | ||
expect( | ||
'=?utf-8?Q?=E2?= =?utf-8?Q?=98?= =?utf-8?Q?=BA?=', | ||
'to decode to', | ||
'☺' | ||
); | ||
}); | ||
it('should decode an encoded word following a undecodable sequence of encoded words', function () { | ||
expect('=?utf-8?Q?=E2?= =?utf-8?Q?=98?= =?iso-8859-1?Q?=A1?=Hola, se=?iso-8859-1?Q?=F1?=or!', 'to decode to', '=?utf-8?Q?=E2?==?utf-8?Q?=98?=¡Hola, señor!'); | ||
}); | ||
it('should give up decoding a UTF-8 smiley (illegally) split up into 3 encoded words if there is regular text between the encoded words', function () { | ||
expect( | ||
'=?utf-8?Q?=E2?= =?utf-8?Q?=98?=a=?utf-8?Q?=BA?==?utf-8?Q?=BA?=a', | ||
'to decode to', | ||
'=?utf-8?Q?=E2?==?utf-8?Q?=98?=a=?utf-8?Q?=BA?==?utf-8?Q?=BA?=a' | ||
); | ||
}); | ||
it('should handle test cases from the MIME tools package', function () { | ||
// From http://search.cpan.org/~dskoll/MIME-tools-5.502/lib/MIME/Words.pm: | ||
expect('=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>', 'to decode to', 'Keld Jørn Simonsen <keld@dkuug.dk>'); | ||
expect('=?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>', 'to decode to', 'Keith Moore <moore@cs.utk.edu>'); | ||
expect('=?ISO-8859-1?Q?Andr=E9_?= Pirard <PIRARD@vm1.ulg.ac.be>', 'to decode to', 'André Pirard <PIRARD@vm1.ulg.ac.be>'); | ||
expect('=?iso-8859-1?Q?J=F8rgen_Nellemose?=', 'to decode to', 'Jørgen Nellemose'); | ||
expect( | ||
'=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?==?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?==?US-ASCII?Q?.._cool!?=', | ||
'to decode to', | ||
'If you can read this you understand the example... cool!' | ||
); | ||
}); | ||
it('should decode an encoded word following a undecodable sequence of encoded words', function () { | ||
expect( | ||
'=?utf-8?Q?=E2?= =?utf-8?Q?=98?= =?iso-8859-1?Q?=A1?=Hola, se=?iso-8859-1?Q?=F1?=or!', | ||
'to decode to', | ||
'=?utf-8?Q?=E2?==?utf-8?Q?=98?=¡Hola, señor!' | ||
); | ||
}); | ||
it('should handle a file name found in a Korean mail', function () { | ||
expect('=?ks_c_5601-1987?B?MTMwMTE3X8HWwvfA5V+1tcDlX7jetLq+8y5wZGY=?=', 'to decode to', '130117_주차장_도장_메뉴얼.pdf'); | ||
}); | ||
it('should handle test cases from the MIME tools package', function () { | ||
// From http://search.cpan.org/~dskoll/MIME-tools-5.502/lib/MIME/Words.pm: | ||
expect( | ||
'=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>', | ||
'to decode to', | ||
'Keld Jørn Simonsen <keld@dkuug.dk>' | ||
); | ||
expect( | ||
'=?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>', | ||
'to decode to', | ||
'Keith Moore <moore@cs.utk.edu>' | ||
); | ||
expect( | ||
'=?ISO-8859-1?Q?Andr=E9_?= Pirard <PIRARD@vm1.ulg.ac.be>', | ||
'to decode to', | ||
'André Pirard <PIRARD@vm1.ulg.ac.be>' | ||
); | ||
expect( | ||
'=?iso-8859-1?Q?J=F8rgen_Nellemose?=', | ||
'to decode to', | ||
'Jørgen Nellemose' | ||
); | ||
expect( | ||
'=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?==?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?==?US-ASCII?Q?.._cool!?=', | ||
'to decode to', | ||
'If you can read this you understand the example... cool!' | ||
); | ||
}); | ||
it('should handle bogus encoded words (spotted in the wild)', function () { | ||
expect('=?utf-8?Q??= <andreas@one.com>', 'to decode to', ' <andreas@one.com>'); | ||
}); | ||
it('should handle a file name found in a Korean mail', function () { | ||
expect( | ||
'=?ks_c_5601-1987?B?MTMwMTE3X8HWwvfA5V+1tcDlX7jetLq+8y5wZGY=?=', | ||
'to decode to', | ||
'130117_주차장_도장_메뉴얼.pdf' | ||
); | ||
}); | ||
it('should decode a character set not in iconv-lite', function () { | ||
expect('=?iso-2022-jp?B?GyRCRnxLXDhsJE4lNSVWJTglJyUvJUghXRsoQnRlc3Q=?=', 'to decode to', '日本語のサブジェクト−test'); | ||
}); | ||
it('should handle bogus encoded words (spotted in the wild)', function () { | ||
expect( | ||
'=?utf-8?Q??= <andreas@one.com>', | ||
'to decode to', | ||
' <andreas@one.com>' | ||
); | ||
}); | ||
it('should decode a character set not in iconv-lite', function () { | ||
expect( | ||
'=?iso-2022-jp?B?GyRCRnxLXDhsJE4lNSVWJTglJyUvJUghXRsoQnRlc3Q=?=', | ||
'to decode to', | ||
'日本語のサブジェクト−test' | ||
); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
10
544
21
24197
14