Comparing version 3.1.0 to 4.0.0
# Changelog | ||
## v3.1.0 2017-01-08 | ||
## v4.0.0 2018-06-11 | ||
* Updated charset name detection, should work better on strange encoded words | ||
* Refactored decoding of mime encoded words and parameter continuation strings | ||
## v3.0.0 2016-12-08 | ||
* Updated encoded-word generation. Previously a minimal value was encoded, so it was possible to have multiple encoded words in a string separated by non encoded-words. This was an issue with some webmail clients that stripped out the non-encoded parts between encoded-words so the updated method uses wide match by encoding from the first word with unicode characters to the last word. "a =?b?= c =?d?= e" -> "a =?bcd?= e" | ||
* Updated encoded-word generation. Previously a minimal value was encoded, so it was possible to have multiple encoded words in a string separated by non encoded-words. This was an issue with some webmail clients that stripped out the non-encoded parts between encoded-words so the updated method uses wide match by encoding from the first word with unicode characters to the last word. "a =?b?= c =?d?= e" -> "a =?bcd?= e" | ||
## v2.1.3 2016-12-08 | ||
* Revert dot as a special symbol | ||
* Revert dot as a special symbol | ||
## v2.1.2 2016-11-21 | ||
* Quote special symbols as defined in RFC (surajwy) | ||
* Quote special symbols as defined in RFC (surajwy) | ||
## v2.1.1 2016-11-15 | ||
* Fixed issue with special symbols in attachment filenames | ||
* Fixed issue with special symbols in attachment filenames | ||
## v2.1.0 2016-07-24 | ||
* Changed handling of base64 encoded mime words where multiple words are joined together if possible. This fixes issues with multi byte characters getting split into different mime words (against the RFC but occurs) | ||
* Changed handling of base64 encoded mime words where multiple words are joined together if possible. This fixes issues with multi byte characters getting split into different mime words (against the RFC but occurs) | ||
## v2.0.3 2016-02-29 | ||
* Fixed an issue with rfc2231 filenames | ||
* Fixed an issue with rfc2231 filenames | ||
## v2.0.2 2016-02-11 | ||
* Fixed an issue with base64 mime words encoding | ||
* Fixed an issue with base64 mime words encoding | ||
## v2.0.1 2016-02-11 | ||
* Fix base64 mime-word encoding. Final string length was calculated invalidly | ||
* Fix base64 mime-word encoding. Final string length was calculated invalidly | ||
## v2.0.0 2016-01-04 | ||
* Replaced jshint with eslint | ||
* Refactored file structure | ||
* Replaced jshint with eslint | ||
* Refactored file structure | ||
@@ -44,0 +44,0 @@ ## v1.2.1 2015-10-05 |
'use strict'; | ||
var iconv = require('iconv-lite'); | ||
var charsets = require('./charsets'); | ||
const iconv = require('iconv-lite'); | ||
const charsets = require('./charsets'); | ||
@@ -9,4 +9,3 @@ /** | ||
*/ | ||
var charset = module.exports = { | ||
const charset = (module.exports = { | ||
/** | ||
@@ -20,4 +19,4 @@ * Encodes an unicode string into an Buffer object as UTF-8 | ||
*/ | ||
encode: function (str) { | ||
return new Buffer(str, 'utf-8'); | ||
encode(str) { | ||
return Buffer.from(str, 'utf-8'); | ||
}, | ||
@@ -33,6 +32,6 @@ | ||
*/ | ||
decode: function (buf, fromCharset) { | ||
decode(buf, fromCharset) { | ||
fromCharset = charset.normalizeCharset(fromCharset || 'UTF-8'); | ||
if (/^(us\-)?ascii|utf\-8|7bit$/i.test(fromCharset)) { | ||
if (/^(us-)?ascii|utf-8|7bit$/i.test(fromCharset)) { | ||
return buf.toString('utf-8'); | ||
@@ -51,9 +50,9 @@ } | ||
*/ | ||
convert: function (data, fromCharset) { | ||
convert(data, fromCharset) { | ||
fromCharset = charset.normalizeCharset(fromCharset || 'UTF-8'); | ||
var bufString; | ||
let bufString; | ||
if (typeof data !== 'string') { | ||
if (/^(us\-)?ascii|utf\-8|7bit$/i.test(fromCharset)) { | ||
if (/^(us-)?ascii|utf-8|7bit$/i.test(fromCharset)) { | ||
return data; | ||
@@ -74,3 +73,3 @@ } | ||
*/ | ||
normalizeCharset: function (charset) { | ||
normalizeCharset(charset) { | ||
charset = charset.toLowerCase().trim(); | ||
@@ -83,8 +82,8 @@ | ||
charset = charset. | ||
replace(/^utf[\-_]?(\d+)/, 'utf-$1'). | ||
replace(/^(?:us[\-_]?)ascii/, 'windows-1252'). | ||
replace(/^win(?:dows)?[\-_]?(\d+)/, 'windows-$1'). | ||
replace(/^(?:latin|iso[\-_]?8859)?[\-_]?(\d+)/, 'iso-8859-$1'). | ||
replace(/^l[\-_]?(\d+)/, 'iso-8859-$1'); | ||
charset = charset | ||
.replace(/^utf[-_]?(\d+)/, 'utf-$1') | ||
.replace(/^(?:us[-_]?)ascii/, 'windows-1252') | ||
.replace(/^win(?:dows)?[-_]?(\d+)/, 'windows-$1') | ||
.replace(/^(?:latin|iso[-_]?8859)?[-_]?(\d+)/, 'iso-8859-$1') | ||
.replace(/^l[-_]?(\d+)/, 'iso-8859-$1'); | ||
@@ -99,2 +98,2 @@ // updated pass | ||
} | ||
}; | ||
}); |
@@ -9,46 +9,46 @@ /* eslint quote-props: 0*/ | ||
'utf-8': 'UTF-8', | ||
'utf8': 'UTF-8', | ||
'cp866': 'IBM866', | ||
'csibm866': 'IBM866', | ||
'ibm866': 'IBM866', | ||
'csisolatin2': 'ISO-8859-2', | ||
utf8: 'UTF-8', | ||
cp866: 'IBM866', | ||
csibm866: 'IBM866', | ||
ibm866: 'IBM866', | ||
csisolatin2: 'ISO-8859-2', | ||
'iso-8859-2': 'ISO-8859-2', | ||
'iso-ir-101': 'ISO-8859-2', | ||
'iso8859-2': 'ISO-8859-2', | ||
'iso88592': 'ISO-8859-2', | ||
iso88592: 'ISO-8859-2', | ||
'iso_8859-2': 'ISO-8859-2', | ||
'iso_8859-2:1987': 'ISO-8859-2', | ||
'l2': 'ISO-8859-2', | ||
'latin2': 'ISO-8859-2', | ||
'csisolatin3': 'ISO-8859-3', | ||
l2: 'ISO-8859-2', | ||
latin2: 'ISO-8859-2', | ||
csisolatin3: 'ISO-8859-3', | ||
'iso-8859-3': 'ISO-8859-3', | ||
'iso-ir-109': 'ISO-8859-3', | ||
'iso8859-3': 'ISO-8859-3', | ||
'iso88593': 'ISO-8859-3', | ||
iso88593: 'ISO-8859-3', | ||
'iso_8859-3': 'ISO-8859-3', | ||
'iso_8859-3:1988': 'ISO-8859-3', | ||
'l3': 'ISO-8859-3', | ||
'latin3': 'ISO-8859-3', | ||
'csisolatin4': 'ISO-8859-4', | ||
l3: 'ISO-8859-3', | ||
latin3: 'ISO-8859-3', | ||
csisolatin4: 'ISO-8859-4', | ||
'iso-8859-4': 'ISO-8859-4', | ||
'iso-ir-110': 'ISO-8859-4', | ||
'iso8859-4': 'ISO-8859-4', | ||
'iso88594': 'ISO-8859-4', | ||
iso88594: 'ISO-8859-4', | ||
'iso_8859-4': 'ISO-8859-4', | ||
'iso_8859-4:1988': 'ISO-8859-4', | ||
'l4': 'ISO-8859-4', | ||
'latin4': 'ISO-8859-4', | ||
'csisolatincyrillic': 'ISO-8859-5', | ||
'cyrillic': 'ISO-8859-5', | ||
l4: 'ISO-8859-4', | ||
latin4: 'ISO-8859-4', | ||
csisolatincyrillic: 'ISO-8859-5', | ||
cyrillic: 'ISO-8859-5', | ||
'iso-8859-5': 'ISO-8859-5', | ||
'iso-ir-144': 'ISO-8859-5', | ||
'iso8859-5': 'ISO-8859-5', | ||
'iso88595': 'ISO-8859-5', | ||
iso88595: 'ISO-8859-5', | ||
'iso_8859-5': 'ISO-8859-5', | ||
'iso_8859-5:1988': 'ISO-8859-5', | ||
'arabic': 'ISO-8859-6', | ||
arabic: 'ISO-8859-6', | ||
'asmo-708': 'ISO-8859-6', | ||
'csiso88596e': 'ISO-8859-6', | ||
'csiso88596i': 'ISO-8859-6', | ||
'csisolatinarabic': 'ISO-8859-6', | ||
csiso88596e: 'ISO-8859-6', | ||
csiso88596i: 'ISO-8859-6', | ||
csisolatinarabic: 'ISO-8859-6', | ||
'ecma-114': 'ISO-8859-6', | ||
@@ -60,20 +60,20 @@ 'iso-8859-6': 'ISO-8859-6', | ||
'iso8859-6': 'ISO-8859-6', | ||
'iso88596': 'ISO-8859-6', | ||
iso88596: 'ISO-8859-6', | ||
'iso_8859-6': 'ISO-8859-6', | ||
'iso_8859-6:1987': 'ISO-8859-6', | ||
'csisolatingreek': 'ISO-8859-7', | ||
csisolatingreek: 'ISO-8859-7', | ||
'ecma-118': 'ISO-8859-7', | ||
'elot_928': 'ISO-8859-7', | ||
'greek': 'ISO-8859-7', | ||
'greek8': 'ISO-8859-7', | ||
elot_928: 'ISO-8859-7', | ||
greek: 'ISO-8859-7', | ||
greek8: 'ISO-8859-7', | ||
'iso-8859-7': 'ISO-8859-7', | ||
'iso-ir-126': 'ISO-8859-7', | ||
'iso8859-7': 'ISO-8859-7', | ||
'iso88597': 'ISO-8859-7', | ||
iso88597: 'ISO-8859-7', | ||
'iso_8859-7': 'ISO-8859-7', | ||
'iso_8859-7:1987': 'ISO-8859-7', | ||
'sun_eu_greek': 'ISO-8859-7', | ||
'csiso88598e': 'ISO-8859-8', | ||
'csisolatinhebrew': 'ISO-8859-8', | ||
'hebrew': 'ISO-8859-8', | ||
sun_eu_greek: 'ISO-8859-7', | ||
csiso88598e: 'ISO-8859-8', | ||
csisolatinhebrew: 'ISO-8859-8', | ||
hebrew: 'ISO-8859-8', | ||
'iso-8859-8': 'ISO-8859-8', | ||
@@ -83,36 +83,36 @@ 'iso-8859-8-e': 'ISO-8859-8', | ||
'iso8859-8': 'ISO-8859-8', | ||
'iso88598': 'ISO-8859-8', | ||
iso88598: 'ISO-8859-8', | ||
'iso_8859-8': 'ISO-8859-8', | ||
'iso_8859-8:1988': 'ISO-8859-8', | ||
'visual': 'ISO-8859-8', | ||
'csisolatin6': 'ISO-8859-10', | ||
visual: 'ISO-8859-8', | ||
csisolatin6: 'ISO-8859-10', | ||
'iso-8859-10': 'ISO-8859-10', | ||
'iso-ir-157': 'ISO-8859-10', | ||
'iso8859-10': 'ISO-8859-10', | ||
'iso885910': 'ISO-8859-10', | ||
'l6': 'ISO-8859-10', | ||
'latin6': 'ISO-8859-10', | ||
iso885910: 'ISO-8859-10', | ||
l6: 'ISO-8859-10', | ||
latin6: 'ISO-8859-10', | ||
'iso-8859-13': 'ISO-8859-13', | ||
'iso8859-13': 'ISO-8859-13', | ||
'iso885913': 'ISO-8859-13', | ||
iso885913: 'ISO-8859-13', | ||
'iso-8859-14': 'ISO-8859-14', | ||
'iso8859-14': 'ISO-8859-14', | ||
'iso885914': 'ISO-8859-14', | ||
'csisolatin9': 'ISO-8859-15', | ||
iso885914: 'ISO-8859-14', | ||
csisolatin9: 'ISO-8859-15', | ||
'iso-8859-15': 'ISO-8859-15', | ||
'iso8859-15': 'ISO-8859-15', | ||
'iso885915': 'ISO-8859-15', | ||
iso885915: 'ISO-8859-15', | ||
'iso_8859-15': 'ISO-8859-15', | ||
'l9': 'ISO-8859-15', | ||
l9: 'ISO-8859-15', | ||
'iso-8859-16': 'ISO-8859-16', | ||
'cskoi8r': 'KOI8-R', | ||
'koi': 'KOI8-R', | ||
'koi8': 'KOI8-R', | ||
cskoi8r: 'KOI8-R', | ||
koi: 'KOI8-R', | ||
koi8: 'KOI8-R', | ||
'koi8-r': 'KOI8-R', | ||
'koi8_r': 'KOI8-R', | ||
koi8_r: 'KOI8-R', | ||
'koi8-ru': 'KOI8-U', | ||
'koi8-u': 'KOI8-U', | ||
'csmacintosh': 'macintosh', | ||
'mac': 'macintosh', | ||
'macintosh': 'macintosh', | ||
csmacintosh: 'macintosh', | ||
mac: 'macintosh', | ||
macintosh: 'macintosh', | ||
'x-mac-roman': 'macintosh', | ||
@@ -122,90 +122,90 @@ 'dos-874': 'windows-874', | ||
'iso8859-11': 'windows-874', | ||
'iso885911': 'windows-874', | ||
iso885911: 'windows-874', | ||
'tis-620': 'windows-874', | ||
'windows-874': 'windows-874', | ||
'cp1250': 'windows-1250', | ||
cp1250: 'windows-1250', | ||
'windows-1250': 'windows-1250', | ||
'x-cp1250': 'windows-1250', | ||
'cp1251': 'windows-1251', | ||
cp1251: 'windows-1251', | ||
'windows-1251': 'windows-1251', | ||
'x-cp1251': 'windows-1251', | ||
'ansi_x3.4-1968': 'windows-1252', | ||
'ascii': 'windows-1252', | ||
'cp1252': 'windows-1252', | ||
'cp819': 'windows-1252', | ||
'csisolatin1': 'windows-1252', | ||
'ibm819': 'windows-1252', | ||
ascii: 'windows-1252', | ||
cp1252: 'windows-1252', | ||
cp819: 'windows-1252', | ||
csisolatin1: 'windows-1252', | ||
ibm819: 'windows-1252', | ||
'iso-8859-1': 'windows-1252', | ||
'iso-ir-100': 'windows-1252', | ||
'iso8859-1': 'windows-1252', | ||
'iso88591': 'windows-1252', | ||
iso88591: 'windows-1252', | ||
'iso_8859-1': 'windows-1252', | ||
'iso_8859-1:1987': 'windows-1252', | ||
'l1': 'windows-1252', | ||
'latin1': 'windows-1252', | ||
l1: 'windows-1252', | ||
latin1: 'windows-1252', | ||
'us-ascii': 'windows-1252', | ||
'windows-1252': 'windows-1252', | ||
'x-cp1252': 'windows-1252', | ||
'cp1253': 'windows-1253', | ||
cp1253: 'windows-1253', | ||
'windows-1253': 'windows-1253', | ||
'x-cp1253': 'windows-1253', | ||
'cp1254': 'windows-1254', | ||
'csisolatin5': 'windows-1254', | ||
cp1254: 'windows-1254', | ||
csisolatin5: 'windows-1254', | ||
'iso-8859-9': 'windows-1254', | ||
'iso-ir-148': 'windows-1254', | ||
'iso8859-9': 'windows-1254', | ||
'iso88599': 'windows-1254', | ||
iso88599: 'windows-1254', | ||
'iso_8859-9': 'windows-1254', | ||
'iso_8859-9:1989': 'windows-1254', | ||
'l5': 'windows-1254', | ||
'latin5': 'windows-1254', | ||
l5: 'windows-1254', | ||
latin5: 'windows-1254', | ||
'windows-1254': 'windows-1254', | ||
'x-cp1254': 'windows-1254', | ||
'cp1255': 'windows-1255', | ||
cp1255: 'windows-1255', | ||
'windows-1255': 'windows-1255', | ||
'x-cp1255': 'windows-1255', | ||
'cp1256': 'windows-1256', | ||
cp1256: 'windows-1256', | ||
'windows-1256': 'windows-1256', | ||
'x-cp1256': 'windows-1256', | ||
'cp1257': 'windows-1257', | ||
cp1257: 'windows-1257', | ||
'windows-1257': 'windows-1257', | ||
'x-cp1257': 'windows-1257', | ||
'cp1258': 'windows-1258', | ||
cp1258: 'windows-1258', | ||
'windows-1258': 'windows-1258', | ||
'x-cp1258': 'windows-1258', | ||
'chinese': 'GBK', | ||
'csgb2312': 'GBK', | ||
'csiso58gb231280': 'GBK', | ||
'gb2312': 'GBK', | ||
'gb_2312': 'GBK', | ||
chinese: 'GBK', | ||
csgb2312: 'GBK', | ||
csiso58gb231280: 'GBK', | ||
gb2312: 'GBK', | ||
gb_2312: 'GBK', | ||
'gb_2312-80': 'GBK', | ||
'gbk': 'GBK', | ||
gbk: 'GBK', | ||
'iso-ir-58': 'GBK', | ||
'x-gbk': 'GBK', | ||
'gb18030': 'gb18030', | ||
'big5': 'Big5', | ||
gb18030: 'gb18030', | ||
big5: 'Big5', | ||
'big5-hkscs': 'Big5', | ||
'cn-big5': 'Big5', | ||
'csbig5': 'Big5', | ||
csbig5: 'Big5', | ||
'x-x-big5': 'Big5', | ||
'cseucpkdfmtjapanese': 'EUC-JP', | ||
cseucpkdfmtjapanese: 'EUC-JP', | ||
'euc-jp': 'EUC-JP', | ||
'x-euc-jp': 'EUC-JP', | ||
'csshiftjis': 'Shift_JIS', | ||
'ms932': 'Shift_JIS', | ||
'ms_kanji': 'Shift_JIS', | ||
csshiftjis: 'Shift_JIS', | ||
ms932: 'Shift_JIS', | ||
ms_kanji: 'Shift_JIS', | ||
'shift-jis': 'Shift_JIS', | ||
'shift_jis': 'Shift_JIS', | ||
'sjis': 'Shift_JIS', | ||
shift_jis: 'Shift_JIS', | ||
sjis: 'Shift_JIS', | ||
'windows-31j': 'Shift_JIS', | ||
'x-sjis': 'Shift_JIS', | ||
'cseuckr': 'EUC-KR', | ||
'csksc56011987': 'EUC-KR', | ||
cseuckr: 'EUC-KR', | ||
csksc56011987: 'EUC-KR', | ||
'euc-kr': 'EUC-KR', | ||
'iso-ir-149': 'EUC-KR', | ||
'korean': 'EUC-KR', | ||
korean: 'EUC-KR', | ||
'ks_c_5601-1987': 'EUC-KR', | ||
'ks_c_5601-1989': 'EUC-KR', | ||
'ksc5601': 'EUC-KR', | ||
'ksc_5601': 'EUC-KR', | ||
ksc5601: 'EUC-KR', | ||
ksc_5601: 'EUC-KR', | ||
'windows-949': 'EUC-KR', | ||
@@ -212,0 +212,0 @@ 'utf-16be': 'UTF-16BE', |
@@ -0,10 +1,13 @@ | ||
/* eslint no-control-regex: 0, no-div-regex: 0, quotes: 0 */ | ||
'use strict'; | ||
var libcharset = require('./charset'); | ||
var libbase64 = require('libbase64'); | ||
var libqp = require('libqp'); | ||
var mimetypes = require('./mimetypes'); | ||
const libcharset = require('./charset'); | ||
const libbase64 = require('libbase64'); | ||
const libqp = require('libqp'); | ||
const mimetypes = require('./mimetypes'); | ||
var libmime = module.exports = { | ||
const STAGE_KEY = 0x1001; | ||
const STAGE_VALUE = 0x1002; | ||
let libmime = (module.exports = { | ||
/** | ||
@@ -16,3 +19,3 @@ * Checks if a value is plaintext string (uses only printable 7bit chars) | ||
*/ | ||
isPlainText: function (value) { | ||
isPlainText(value) { | ||
if (typeof value !== 'string' || /[\x00-\x08\x0b\x0c\x0e-\x1f\u0080-\uFFFF]/.test(value)) { | ||
@@ -36,3 +39,3 @@ return false; | ||
*/ | ||
hasLongerLines: function (str, lineLength) { | ||
hasLongerLines(str, lineLength) { | ||
return new RegExp('^.{' + (lineLength + 1) + ',}', 'm').test(str); | ||
@@ -48,12 +51,12 @@ }, | ||
*/ | ||
decodeFlowed: function (str, delSp) { | ||
decodeFlowed(str, delSp) { | ||
str = (str || '').toString(); | ||
return str. | ||
split(/\r?\n/). | ||
// remove soft linebreaks | ||
// soft linebreaks are added after space symbols | ||
reduce( | ||
function (previousValue, currentValue, index) { | ||
var body = previousValue; | ||
return ( | ||
str | ||
.split(/\r?\n/) | ||
// remove soft linebreaks | ||
// soft linebreaks are added after space symbols | ||
.reduce((previousValue, currentValue, index) => { | ||
let body = previousValue; | ||
if (delSp) { | ||
@@ -64,3 +67,3 @@ // delsp adds spaces to text to be able to fold it | ||
} | ||
if (/ $/.test(previousValue) && !/(^|\n)\-\- $/.test(previousValue) || index === 1) { | ||
if ((/ $/.test(previousValue) && !/(^|\n)-- $/.test(previousValue)) || index === 1) { | ||
return body + currentValue; | ||
@@ -70,7 +73,7 @@ } else { | ||
} | ||
} | ||
). | ||
// remove whitespace stuffing | ||
// http://tools.ietf.org/html/rfc3676#section-4.4 | ||
replace(/^ /gm, ''); | ||
}) | ||
// remove whitespace stuffing | ||
// http://tools.ietf.org/html/rfc3676#section-4.4 | ||
.replace(/^ /gm, '') | ||
); | ||
}, | ||
@@ -86,11 +89,16 @@ | ||
*/ | ||
encodeFlowed: function (str, lineLength) { | ||
encodeFlowed(str, lineLength) { | ||
lineLength = lineLength || 76; | ||
var flowed = []; | ||
str.split(/\r?\n/).forEach(function (line) { | ||
flowed.push(libmime.foldLines(line. | ||
// space stuffing http://tools.ietf.org/html/rfc3676#section-4.2 | ||
replace(/^( |From|>)/igm, ' $1'), | ||
lineLength, true)); | ||
let flowed = []; | ||
str.split(/\r?\n/).forEach(line => { | ||
flowed.push( | ||
libmime.foldLines( | ||
line | ||
// space stuffing http://tools.ietf.org/html/rfc3676#section-4.2 | ||
.replace(/^( |From|>)/gim, ' $1'), | ||
lineLength, | ||
true | ||
) | ||
); | ||
}); | ||
@@ -108,12 +116,15 @@ return flowed.join('\r\n'); | ||
*/ | ||
encodeWord: function (data, mimeWordEncoding, maxLength) { | ||
mimeWordEncoding = (mimeWordEncoding || 'Q').toString().toUpperCase().trim().charAt(0); | ||
encodeWord(data, mimeWordEncoding, maxLength) { | ||
mimeWordEncoding = (mimeWordEncoding || 'Q') | ||
.toString() | ||
.toUpperCase() | ||
.trim() | ||
.charAt(0); | ||
maxLength = maxLength || 0; | ||
var encodedStr, | ||
toCharset = 'UTF-8', | ||
i, len, parts, lpart, chr; | ||
let encodedStr; | ||
let toCharset = 'UTF-8'; | ||
if (maxLength && maxLength > 7 + toCharset.length) { | ||
maxLength -= (7 + toCharset.length); | ||
maxLength -= 7 + toCharset.length; | ||
} | ||
@@ -123,4 +134,7 @@ | ||
// https://tools.ietf.org/html/rfc2047#section-5 rule (3) | ||
encodedStr = libqp.encode(data).replace(/[^a-z0-9!*+\-\/=]/ig, function (chr) { | ||
var ord = chr.charCodeAt(0).toString(16).toUpperCase(); | ||
encodedStr = libqp.encode(data).replace(/[^a-z0-9!*+\-/=]/gi, chr => { | ||
let ord = chr | ||
.charCodeAt(0) | ||
.toString(16) | ||
.toUpperCase(); | ||
if (chr === ' ') { | ||
@@ -142,6 +156,6 @@ return '_'; | ||
// RFC2047 6.3 (2) states that encoded-word must include an integral number of characters, so no chopping unicode sequences | ||
parts = []; | ||
lpart = ''; | ||
for (i = 0, len = encodedStr.length; i < len; i++) { | ||
chr = encodedStr.charAt(i); | ||
let parts = []; | ||
let lpart = ''; | ||
for (let i = 0, len = encodedStr.length; i < len; i++) { | ||
let chr = encodedStr.charAt(i); | ||
// check if we can add this character to the existing string | ||
@@ -180,35 +194,46 @@ // without breaking byte length limit | ||
*/ | ||
decodeWord: function (str) { | ||
str = (str || '').toString().trim(); | ||
var fromCharset, encoding, match; | ||
match = str.match(/^\=\?([\w_\-\*]+)\?([QqBb])\?([^\?]+)\?\=$/i); | ||
if (!match) { | ||
return str; | ||
} | ||
decodeWord(charset, encoding, str) { | ||
// RFC2231 added language tag to the encoding | ||
// see: https://tools.ietf.org/html/rfc2231#section-5 | ||
// this implementation silently ignores this tag | ||
fromCharset = match[1].split('*').shift(); | ||
let splitPos = charset.indexOf('*'); | ||
if (splitPos >= 0) { | ||
charset = charset.substr(0, splitPos); | ||
} | ||
charset = libcharset.normalizeCharset(charset); | ||
encoding = (match[2] || 'Q').toString().toUpperCase(); | ||
str = (match[3] || ''); | ||
encoding = encoding.toUpperCase(); | ||
if (encoding === 'Q') { | ||
// remove spaces between = and hex char, this might indicate invalidly applied line splitting | ||
str = str.replace(/=\s+([0-9a-fA-F])/, '=$1'); | ||
} | ||
str = str | ||
// remove spaces between = and hex char, this might indicate invalidly applied line splitting | ||
.replace(/=\s+([0-9a-fA-F])/g, '=$1') | ||
// convert all underscores to spaces | ||
.replace(/[_\s]/g, ' '); | ||
// convert all underscores to spaces | ||
str = str.replace(/_/g, ' ').replace(/ $/, '=20'); | ||
if (encoding === 'B') { | ||
return libcharset.decode(libbase64.decode(str), fromCharset); | ||
} else if (encoding === 'Q') { | ||
return libcharset.decode(libqp.decode(str), fromCharset); | ||
let buf = Buffer.from(str); | ||
let bytes = []; | ||
for (let i = 0, len = buf.length; i < len; i++) { | ||
let c = buf[i]; | ||
if (i <= len - 2 && c === 0x3d /* = */) { | ||
let c1 = this.getHex(buf[i + 1]); | ||
let c2 = this.getHex(buf[i + 2]); | ||
if (c1 && c2) { | ||
let c = parseInt(c1 + c2, 16); | ||
bytes.push(c); | ||
i += 2; | ||
continue; | ||
} | ||
} | ||
bytes.push(c); | ||
} | ||
str = Buffer.from(bytes); | ||
} else if (encoding === 'B') { | ||
str = Buffer.from(str, 'base64'); | ||
} else { | ||
return str; | ||
// keep as is, convert Buffer to unicode string, assume utf8 | ||
str = Buffer.from(str); | ||
} | ||
return libcharset.decode(str, charset); | ||
}, | ||
@@ -225,3 +250,3 @@ | ||
*/ | ||
encodeWords: function (data, mimeWordEncoding, maxLength, fromCharset) { | ||
encodeWords(data, mimeWordEncoding, maxLength, fromCharset) { | ||
if (!fromCharset && typeof maxLength === 'string' && !maxLength.match(/^[0-9]+$/)) { | ||
@@ -234,10 +259,10 @@ fromCharset = maxLength; | ||
var decodedValue = libcharset.decode(libcharset.convert((data || ''), fromCharset)); | ||
var encodedValue; | ||
let decodedValue = libcharset.decode(libcharset.convert(data || '', fromCharset)); | ||
let encodedValue; | ||
var firstMatch = decodedValue.match(/(?:^|\s)([^\s]*[\u0080-\uFFFF])/); | ||
let firstMatch = decodedValue.match(/(?:^|\s)([^\s]*[\u0080-\uFFFF])/); | ||
if (!firstMatch) { | ||
return decodedValue; | ||
} | ||
var lastMatch = decodedValue.match(/([\u0080-\uFFFF][^\s]*)[^\u0080-\uFFFF]*$/); | ||
let lastMatch = decodedValue.match(/([\u0080-\uFFFF][^\s]*)[^\u0080-\uFFFF]*$/); | ||
if (!lastMatch) { | ||
@@ -247,6 +272,10 @@ // should not happen | ||
} | ||
var startIndex = firstMatch.index + (firstMatch[0].match(/[^\s]/) || { | ||
index: 0 | ||
}).index; | ||
var endIndex = lastMatch.index + (lastMatch[1] || '').length; | ||
let startIndex = | ||
firstMatch.index + | ||
( | ||
firstMatch[0].match(/[^\s]/) || { | ||
index: 0 | ||
} | ||
).index; | ||
let endIndex = lastMatch.index + (lastMatch[1] || '').length; | ||
@@ -267,37 +296,38 @@ encodedValue = | ||
*/ | ||
decodeWords: function (str) { | ||
return (str || '').toString(). | ||
decodeWords(str) { | ||
return ( | ||
(str || '') | ||
.toString() | ||
// find base64 words that can be joined | ||
.replace(/(=\?([^?]+)\?[Bb]\?[^?]+[^^=]\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]+\?=)/g, (match, left, chLeft, chRight) => { | ||
// only mark b64 chunks to be joined if charsets match | ||
if (libcharset.normalizeCharset(chLeft || '') === libcharset.normalizeCharset(chRight || '')) { | ||
// set a joiner marker | ||
return left + '__\x00JOIN\x00__'; | ||
} | ||
return match; | ||
}) | ||
// find QP words that can be joined | ||
.replace(/(=\?([^?]+)\?[Qq]\?[^?]+\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]+\?=)/g, (match, left, chLeft, chRight) => { | ||
// only mark QP chunks to be joined if charsets match | ||
if (libcharset.normalizeCharset(chLeft || '') === libcharset.normalizeCharset(chRight || '')) { | ||
// set a joiner marker | ||
return left + '__\x00JOIN\x00__'; | ||
} | ||
return match; | ||
}) | ||
// join base64 encoded words | ||
.replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[QqBb]\?)?/g, '') | ||
// remove spaces between mime encoded words | ||
.replace(/(=\?[^?]+\?[QqBb]\?[^?]+\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]+\?=)/g, '$1') | ||
// decode words | ||
.replace(/=\?([\w_\-*]+)\?([QqBb])\?([^?]+)\?=/g, (m, charset, encoding, text) => this.decodeWord(charset, encoding, text)) | ||
); | ||
}, | ||
// find base64 words that can be joined | ||
replace(/(=\?([^?]+)\?[Bb]\?[^?]+[^^=]\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]+\?=)/g, | ||
function (match, left, chLeft, chRight) { | ||
// only mark b64 chunks to be joined if charsets match | ||
if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) { | ||
// set a joiner marker | ||
return left + '__\x00JOIN\x00__'; | ||
} | ||
return match; | ||
}). | ||
// find QP words that can be joined | ||
replace(/(=\?([^?]+)\?[Qq]\?[^?]+\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]+\?=)/g, | ||
function (match, left, chLeft, chRight) { | ||
// only mark QP chunks to be joined if charsets match | ||
if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) { | ||
// set a joiner marker | ||
return left + '__\x00JOIN\x00__'; | ||
} | ||
return match; | ||
}). | ||
// join base64 encoded words | ||
replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[QqBb]\?)?/g, ''). | ||
// remove spaces between mime encoded words | ||
replace(/(=\?[^?]+\?[QqBb]\?[^?]+\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]+\?=)/g, '$1'). | ||
// decode words | ||
replace(/\=\?([\w_\-\*]+)\?([QqBb])\?[^\?]+\?\=/g, function (mimeWord) { | ||
return libmime.decodeWord(mimeWord); | ||
}); | ||
getHex(c) { | ||
if ((c >= 0x30 /* 0 */ && c <= 0x39) /* 9 */ || (c >= 0x61 /* a */ && c <= 0x66) /* f */ || (c >= 0x41 /* A */ && c <= 0x46) /* F */) { | ||
return String.fromCharCode(c); | ||
} | ||
return false; | ||
}, | ||
@@ -313,11 +343,14 @@ | ||
*/ | ||
decodeHeader: function (headerLine) { | ||
var line = (headerLine || '').toString().replace(/(?:\r?\n|\r)[ \t]*/g, ' ').trim(), | ||
decodeHeader(headerLine) { | ||
let line = (headerLine || '') | ||
.toString() | ||
.replace(/(?:\r?\n|\r)[ \t]*/g, ' ') | ||
.trim(), | ||
match = line.match(/^\s*([^:]+):(.*)$/), | ||
key = (match && match[1] || '').trim().toLowerCase(), | ||
value = (match && match[2] || '').trim(); | ||
key = ((match && match[1]) || '').trim().toLowerCase(), | ||
value = ((match && match[2]) || '').trim(); | ||
return { | ||
key: key, | ||
value: value | ||
key, | ||
value | ||
}; | ||
@@ -333,7 +366,8 @@ }, | ||
*/ | ||
decodeHeaders: function (headers) { | ||
var lines = headers.split(/\r?\n|\r/), | ||
decodeHeaders(headers) { | ||
let lines = headers.split(/\r?\n|\r/), | ||
headersObj = {}, | ||
header, | ||
i, len; | ||
i, | ||
len; | ||
@@ -366,11 +400,11 @@ for (i = lines.length - 1; i >= 0; i--) { | ||
*/ | ||
buildHeaderValue: function (structured) { | ||
var paramsArray = []; | ||
buildHeaderValue(structured) { | ||
let paramsArray = []; | ||
Object.keys(structured.params || {}).forEach(function (param) { | ||
Object.keys(structured.params || {}).forEach(param => { | ||
// filename might include unicode characters so it is a special case | ||
var value = structured.params[param]; | ||
let value = structured.params[param]; | ||
if (!libmime.isPlainText(value) || value.length >= 75) { | ||
libmime.buildHeaderParam(param, value, 50).forEach(function (encodedParam) { | ||
if (!/[\s"\\;:\/=\(\),<>@\[\]\?]|^[\-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') { | ||
libmime.buildHeaderParam(param, value, 50).forEach(encodedParam => { | ||
if (!/[\s"\\;:/=(),<>@[\]?]|^[-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') { | ||
paramsArray.push(encodedParam.key + '=' + encodedParam.value); | ||
@@ -381,3 +415,3 @@ } else { | ||
}); | ||
} else if (/[\s'"\\;:\/=\(\),<>@\[\]\?]|^\-/.test(value)) { | ||
} else if (/[\s'"\\;:/=(),<>@[\]?]|^-/.test(value)) { | ||
paramsArray.push(param + '=' + JSON.stringify(value)); | ||
@@ -387,3 +421,3 @@ } else { | ||
} | ||
}.bind(this)); | ||
}); | ||
@@ -408,58 +442,67 @@ return structured.value + (paramsArray.length ? '; ' + paramsArray.join('; ') : ''); | ||
*/ | ||
parseHeaderValue: function (str) { | ||
var response = { | ||
value: false, | ||
params: {} | ||
}, | ||
key = false, | ||
value = '', | ||
type = 'value', | ||
quote = false, | ||
escaped = false, | ||
chr; | ||
parseHeaderValue(str) { | ||
let response = { | ||
value: false, | ||
params: {} | ||
}; | ||
let key = false; | ||
let value = ''; | ||
let stage = STAGE_VALUE; | ||
for (var i = 0, len = str.length; i < len; i++) { | ||
let quote = false; | ||
let escaped = false; | ||
let chr; | ||
for (let i = 0, len = str.length; i < len; i++) { | ||
chr = str.charAt(i); | ||
if (type === 'key') { | ||
if (chr === '=') { | ||
key = value.trim().toLowerCase(); | ||
type = 'value'; | ||
value = ''; | ||
continue; | ||
} | ||
value += chr; | ||
} else { | ||
if (escaped) { | ||
switch (stage) { | ||
case STAGE_KEY: | ||
if (chr === '=') { | ||
key = value.trim().toLowerCase(); | ||
stage = STAGE_VALUE; | ||
value = ''; | ||
break; | ||
} | ||
value += chr; | ||
} else if (chr === '\\') { | ||
escaped = true; | ||
continue; | ||
} else if (quote && chr === quote) { | ||
quote = false; | ||
} else if (!quote && chr === '"') { | ||
quote = chr; | ||
} else if (!quote && chr === ';') { | ||
if (key === false) { | ||
response.value = value.trim(); | ||
break; | ||
case STAGE_VALUE: | ||
if (escaped) { | ||
value += chr; | ||
} else if (chr === '\\') { | ||
escaped = true; | ||
continue; | ||
} else if (quote && chr === quote) { | ||
quote = false; | ||
} else if (!quote && chr === '"') { | ||
quote = chr; | ||
} else if (!quote && chr === ';') { | ||
if (key === false) { | ||
response.value = value.trim(); | ||
} else { | ||
response.params[key] = value.trim(); | ||
} | ||
stage = STAGE_KEY; | ||
value = ''; | ||
} else { | ||
response.params[key] = value.trim(); | ||
value += chr; | ||
} | ||
type = 'key'; | ||
value = ''; | ||
} else { | ||
value += chr; | ||
} | ||
escaped = false; | ||
escaped = false; | ||
break; | ||
} | ||
} | ||
if (type === 'value') { | ||
// finalize remainder | ||
value = value.trim(); | ||
if (stage === STAGE_VALUE) { | ||
if (key === false) { | ||
response.value = value.trim(); | ||
// default value | ||
response.value = value; | ||
} else { | ||
response.params[key] = value.trim(); | ||
// subkey value | ||
response.params[key] = value; | ||
} | ||
} else if (value.trim()) { | ||
response.params[value.trim().toLowerCase()] = ''; | ||
} else if (value) { | ||
// treat as key without value, see emptykey: | ||
// Header-Key: somevalue; key=value; emptykey | ||
response.params[value.toLowerCase()] = ''; | ||
} | ||
@@ -471,62 +514,71 @@ | ||
// preprocess values | ||
Object.keys(response.params).forEach(function (key) { | ||
var actualKey, nr, match, value; | ||
if ((match = key.match(/(\*(\d+)|\*(\d+)\*|\*)$/))) { | ||
actualKey = key.substr(0, match.index); | ||
nr = Number(match[2] || match[3]) || 0; | ||
Object.keys(response.params).forEach(key => { | ||
let actualKey; | ||
let nr; | ||
let value; | ||
if (!response.params[actualKey] || typeof response.params[actualKey] !== 'object') { | ||
response.params[actualKey] = { | ||
charset: false, | ||
values: [] | ||
}; | ||
} | ||
let match = key.match(/\*((\d+)\*?)?$/); | ||
value = response.params[key]; | ||
if (!match) { | ||
// nothing to do here, does not seem like a continuation param | ||
return; | ||
} | ||
if (nr === 0 && match[0].substr(-1) === '*' && (match = value.match(/^([^']*)'[^']*'(.*)$/))) { | ||
response.params[actualKey].charset = match[1] || 'iso-8859-1'; | ||
value = match[2]; | ||
} | ||
actualKey = key.substr(0, match.index).toLowerCase(); | ||
nr = Number(match[2]) || 0; | ||
response.params[actualKey].values[nr] = value; | ||
if (!response.params[actualKey] || typeof response.params[actualKey] !== 'object') { | ||
response.params[actualKey] = { | ||
charset: false, | ||
values: [] | ||
}; | ||
} | ||
// remove the old reference | ||
delete response.params[key]; | ||
value = response.params[key]; | ||
if (nr === 0 && match[0].charAt(match[0].length - 1) === '*' && (match = value.match(/^([^']*)'[^']*'(.*)$/))) { | ||
response.params[actualKey].charset = match[1] || 'utf-8'; | ||
value = match[2]; | ||
} | ||
response.params[actualKey].values.push({ nr, value }); | ||
// remove the old reference | ||
delete response.params[key]; | ||
}); | ||
// concatenate split rfc2231 strings and convert encoded strings to mime encoded words | ||
Object.keys(response.params).forEach(function (key) { | ||
var value; | ||
Object.keys(response.params).forEach(key => { | ||
let value; | ||
if (response.params[key] && Array.isArray(response.params[key].values)) { | ||
value = response.params[key].values.map(function (val) { | ||
return val || ''; | ||
}).join(''); | ||
value = response.params[key].values | ||
.sort((a, b) => a.nr - b.nr) | ||
.map(val => (val && val.value) || '') | ||
.join(''); | ||
if (response.params[key].charset) { | ||
// convert "%AB" to "=?charset?Q?=AB?=" | ||
response.params[key] = '=?' + | ||
response.params[key].charset + | ||
'?Q?' + | ||
value. | ||
// fix invalidly encoded chars | ||
replace(/[=\?_\s]/g, | ||
function (s) { | ||
var c = s.charCodeAt(0).toString(16); | ||
if (s === ' ') { | ||
return '_'; | ||
} else { | ||
return '%' + (c.length < 2 ? '0' : '') + c; | ||
} | ||
} | ||
). | ||
// change from urlencoding to percent encoding | ||
replace(/%/g, '=') + | ||
'?='; | ||
// convert "%AB" to "=?charset?Q?=AB?=" and then to unicode | ||
response.params[key] = this.decodeWords( | ||
'=?' + | ||
response.params[key].charset + | ||
'?Q?' + | ||
value | ||
// fix invalidly encoded chars | ||
.replace(/[=?_\s]/g, s => { | ||
let c = s.charCodeAt(0).toString(16); | ||
if (s === ' ') { | ||
return '_'; | ||
} else { | ||
return '%' + (c.length < 2 ? '0' : '') + c; | ||
} | ||
}) | ||
// change from urlencoding to percent encoding | ||
.replace(/%/g, '=') + | ||
'?=' | ||
); | ||
} else { | ||
response.params[key] = value; | ||
response.params[key] = this.decodeWords(value); | ||
} | ||
} | ||
}.bind(this)); | ||
}); | ||
@@ -551,11 +603,11 @@ return response; | ||
*/ | ||
buildHeaderParam: function (key, data, maxLength, fromCharset) { | ||
var list = []; | ||
var encodedStr = typeof data === 'string' ? data : libmime.decode(data, fromCharset); | ||
var encodedStrArr; | ||
var chr, ord; | ||
var line; | ||
var startPos = 0; | ||
var isEncoded = false; | ||
var i, len; | ||
buildHeaderParam(key, data, maxLength, fromCharset) { | ||
let list = []; | ||
let encodedStr = typeof data === 'string' ? data : libmime.decode(data, fromCharset); | ||
let encodedStrArr; | ||
let chr, ord; | ||
let line; | ||
let startPos = 0; | ||
let isEncoded = false; | ||
let i, len; | ||
@@ -566,12 +618,13 @@ maxLength = maxLength || 50; | ||
if (libmime.isPlainText(data)) { | ||
// check if conversion is even needed | ||
if (encodedStr.length <= maxLength) { | ||
return [{ | ||
key: key, | ||
value: encodedStr | ||
}]; | ||
return [ | ||
{ | ||
key, | ||
value: encodedStr | ||
} | ||
]; | ||
} | ||
encodedStr = encodedStr.replace(new RegExp('.{' + maxLength + '}', 'g'), function (str) { | ||
encodedStr = encodedStr.replace(new RegExp('.{' + maxLength + '}', 'g'), str => { | ||
list.push({ | ||
@@ -588,5 +641,3 @@ line: str | ||
} | ||
} else { | ||
if (/[\uD800-\uDBFF]/.test(encodedStr)) { | ||
@@ -598,3 +649,3 @@ // string containts surrogate pairs, so normalize it to an array of bytes | ||
ord = chr.charCodeAt(0); | ||
if (ord >= 0xD800 && ord <= 0xDBFF && i < len - 1) { | ||
if (ord >= 0xd800 && ord <= 0xdbff && i < len - 1) { | ||
chr += encodedStr.charAt(i + 1); | ||
@@ -612,3 +663,3 @@ encodedStrArr.push(chr); | ||
// even if it does not contain any unicode characters | ||
line = 'utf-8\'\''; | ||
line = "utf-8''"; | ||
isEncoded = true; | ||
@@ -619,3 +670,2 @@ startPos = 0; | ||
for (i = 0, len = encodedStr.length; i < len; i++) { | ||
chr = encodedStr[i]; | ||
@@ -637,3 +687,3 @@ | ||
list.push({ | ||
line: line, | ||
line, | ||
encoded: isEncoded | ||
@@ -655,3 +705,3 @@ }); | ||
list.push({ | ||
line: line, | ||
line, | ||
encoded: isEncoded | ||
@@ -673,3 +723,3 @@ }); | ||
list.push({ | ||
line: line, | ||
line, | ||
encoded: isEncoded | ||
@@ -680,14 +730,11 @@ }); | ||
return list.map(function (item, i) { | ||
return { | ||
// encoded lines: {name}*{part}* | ||
// unencoded lines: {name}*{part} | ||
// if any line needs to be encoded then the first line (part==0) is always encoded | ||
key: key + '*' + i + (item.encoded ? '*' : ''), | ||
value: item.line | ||
}; | ||
}); | ||
return list.map((item, i) => ({ | ||
// encoded lines: {name}*{part}* | ||
// unencoded lines: {name}*{part} | ||
// if any line needs to be encoded then the first line (part==0) is always encoded | ||
key: key + '*' + i + (item.encoded ? '*' : ''), | ||
value: item.line | ||
})); | ||
}, | ||
/** | ||
@@ -700,4 +747,7 @@ * Returns file extension for a content type string. If no suitable extensions | ||
*/ | ||
detectExtension: function (mimeType) { | ||
mimeType = (mimeType || '').toString().toLowerCase().replace(/\s/g, ''); | ||
detectExtension(mimeType) { | ||
mimeType = (mimeType || '') | ||
.toString() | ||
.toLowerCase() | ||
.replace(/\s/g, ''); | ||
if (!(mimeType in mimetypes.list)) { | ||
@@ -711,6 +761,6 @@ return 'bin'; | ||
var mimeParts = mimeType.split('/'); | ||
let mimeParts = mimeType.split('/'); | ||
// search for name match | ||
for (var i = 0, len = mimetypes.list[mimeType].length; i < len; i++) { | ||
for (let i = 0, len = mimetypes.list[mimeType].length; i < len; i++) { | ||
if (mimeParts[1] === mimetypes.list[mimeType][i]) { | ||
@@ -732,4 +782,10 @@ return mimetypes.list[mimeType][i]; | ||
*/ | ||
detectMimeType: function (extension) { | ||
extension = (extension || '').toString().toLowerCase().replace(/\s/g, '').replace(/^\./g, '').split('.').pop(); | ||
detectMimeType(extension) { | ||
extension = (extension || '') | ||
.toString() | ||
.toLowerCase() | ||
.replace(/\s/g, '') | ||
.replace(/^\./g, '') | ||
.split('.') | ||
.pop(); | ||
@@ -744,6 +800,6 @@ if (!(extension in mimetypes.extensions)) { | ||
var mimeParts; | ||
let mimeParts; | ||
// search for name match | ||
for (var i = 0, len = mimetypes.extensions[extension].length; i < len; i++) { | ||
for (let i = 0, len = mimetypes.extensions[extension].length; i < len; i++) { | ||
mimeParts = mimetypes.extensions[extension][i].split('/'); | ||
@@ -768,10 +824,11 @@ if (mimeParts[1] === extension) { | ||
*/ | ||
foldLines: function (str, lineLength, afterSpace) { | ||
foldLines(str, lineLength, afterSpace) { | ||
str = (str || '').toString(); | ||
lineLength = lineLength || 76; | ||
var pos = 0, | ||
let pos = 0, | ||
len = str.length, | ||
result = '', | ||
line, match; | ||
line, | ||
match; | ||
@@ -804,3 +861,3 @@ while (pos < len) { | ||
} | ||
}; | ||
}); | ||
@@ -815,3 +872,6 @@ /** | ||
function splitMimeEncodedString(str, maxlen) { | ||
var curLine, match, chr, done, | ||
let curLine, | ||
match, | ||
chr, | ||
done, | ||
lines = []; | ||
@@ -826,3 +886,3 @@ | ||
// move incomplete escaped char back to main | ||
if ((match = curLine.match(/\=[0-9A-F]?$/i))) { | ||
if ((match = curLine.match(/[=][0-9A-F]?$/i))) { | ||
curLine = curLine.substr(0, match.index); | ||
@@ -835,6 +895,6 @@ } | ||
// check if not middle of a unicode char sequence | ||
if ((match = str.substr(curLine.length).match(/^\=([0-9A-F]{2})/i))) { | ||
if ((match = str.substr(curLine.length).match(/^[=]([0-9A-F]{2})/i))) { | ||
chr = parseInt(match[1], 16); | ||
// invalid sequence, move one char back anc recheck | ||
if (chr < 0xC2 && chr > 0x7F) { | ||
if (chr < 0xc2 && chr > 0x7f) { | ||
curLine = curLine.substr(0, curLine.length - 3); | ||
@@ -856,11 +916,14 @@ done = false; | ||
function encodeURICharComponent(chr) { | ||
var i, len, ord; | ||
var res = ''; | ||
let res = ''; | ||
let ord = chr | ||
.charCodeAt(0) | ||
.toString(16) | ||
.toUpperCase(); | ||
ord = chr.charCodeAt(0).toString(16).toUpperCase(); | ||
if (ord.length % 2) { | ||
ord = '0' + ord; | ||
} | ||
if (ord.length > 2) { | ||
for (i = 0, len = ord.length / 2; i < len; i++) { | ||
for (let i = 0, len = ord.length / 2; i < len; i++) { | ||
res += '%' + ord.substr(i, 2); | ||
@@ -883,7 +946,7 @@ } | ||
// should never run | ||
return str.replace(/[^\x00-\x1F *'()<>@,;:\\"\[\]?=\u007F-\uFFFF]+/g, ''); | ||
return str.replace(/[^\x00-\x1F *'()<>@,;:\\"[\]?=\u007F-\uFFFF]+/g, ''); | ||
} | ||
// ensure chars that are not handled by encodeURICompent are converted as well | ||
return str.replace(/[\x00-\x1F *'()<>@,;:\\"\[\]?=\u007F-\uFFFF]/g, encodeURICharComponent); | ||
return str.replace(/[\x00-\x1F *'()<>@,;:\\"[\]?=\u007F-\uFFFF]/g, chr => encodeURICharComponent(chr)); | ||
} |
{ | ||
"name": "libmime", | ||
"description": "Encode and decode quoted printable and base64 strings", | ||
"version": "3.1.0", | ||
"main": "lib/libmime", | ||
"homepage": "https://github.com/andris9/libmime", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/andris9/libmime.git" | ||
}, | ||
"license": "MIT", | ||
"keywords": [ | ||
"MIME", | ||
"Base64", | ||
"Quoted-Printable" | ||
], | ||
"author": "Andris Reinman <andris@kreata.ee>", | ||
"scripts": { | ||
"test": "grunt mochaTest" | ||
}, | ||
"dependencies": { | ||
"iconv-lite": "0.4.15", | ||
"libbase64": "0.1.0", | ||
"libqp": "1.1.0" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"grunt": "^1.0.1", | ||
"grunt-cli": "^1.2.0", | ||
"grunt-eslint": "^19.0.0", | ||
"grunt-mocha-test": "^0.13.2", | ||
"mocha": "^3.2.0" | ||
} | ||
"name": "libmime", | ||
"description": "Encode and decode quoted printable and base64 strings", | ||
"version": "4.0.0", | ||
"main": "lib/libmime", | ||
"homepage": "https://github.com/andris9/libmime", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/andris9/libmime.git" | ||
}, | ||
"license": "MIT", | ||
"keywords": ["MIME", "Base64", "Quoted-Printable"], | ||
"author": "Andris Reinman <andris@kreata.ee>", | ||
"scripts": { | ||
"test": "grunt" | ||
}, | ||
"dependencies": { | ||
"iconv-lite": "0.4.23", | ||
"libbase64": "1.0.2", | ||
"libqp": "1.1.0" | ||
}, | ||
"devDependencies": { | ||
"eslint-config-nodemailer": "^1.2.0", | ||
"chai": "^4.1.2", | ||
"grunt": "^1.0.3", | ||
"grunt-cli": "^1.2.0", | ||
"grunt-eslint": "^20.2.0", | ||
"grunt-mocha-test": "^0.13.3", | ||
"mocha": "^5.2.0" | ||
} | ||
} |
@@ -17,4 +17,2 @@ # libmime | ||
**NB!** charset decoding methods (eg. `decodeWords`) throw if an unknown charset is used | ||
### Encoded Words | ||
@@ -28,5 +26,5 @@ | ||
* **str** - String or Buffer to be encoded | ||
* **mimeWordEncoding** - Encoding for the mime word, either Q or B (default is 'Q') | ||
* **maxLength** - If set, split mime words into several chunks if needed | ||
* **str** - String or Buffer to be encoded | ||
* **mimeWordEncoding** - Encoding for the mime word, either Q or B (default is 'Q') | ||
* **maxLength** - If set, split mime words into several chunks if needed | ||
@@ -41,18 +39,2 @@ **Example** | ||
#### #decodeWord | ||
Decodes a string from mime encoded word format. | ||
libmime.decodeWord(str) → String | ||
* **str** - String to be decoded | ||
**Example** | ||
libmime.decodeWord('=?UTF-8?Q?See_on_=C3=B5hin_test?='); | ||
will become | ||
See on õhin test | ||
#### #encodeWords | ||
@@ -64,5 +46,5 @@ | ||
* **str** - String or Buffer to be encoded | ||
* **mimeWordEncoding** - Encoding for the mime word, either Q or B (default is 'Q') | ||
* **maxLength** - If set, split mime words into several chunks if needed | ||
* **str** - String or Buffer to be encoded | ||
* **mimeWordEncoding** - Encoding for the mime word, either Q or B (default is 'Q') | ||
* **maxLength** - If set, split mime words into several chunks if needed | ||
@@ -75,3 +57,3 @@ #### #decodeWords | ||
* **str** - String to be decoded | ||
* **str** - String to be decoded | ||
@@ -86,5 +68,5 @@ ### Folding | ||
* **str** - String to be folded | ||
* **lineLength** - Maximum length of a line (defaults to 76) | ||
* **afterSpace** - If true, leave a space in the end of a line | ||
* **str** - String to be folded | ||
* **lineLength** - Maximum length of a line (defaults to 76) | ||
* **afterSpace** - If true, leave a space in the end of a line | ||
@@ -100,3 +82,2 @@ **Example** | ||
#### #encodeFlowed | ||
@@ -108,4 +89,4 @@ | ||
* **str** Plaintext string that requires wrapping | ||
* **lineLength** (defaults to 76) Maximum length of a line | ||
* **str** Plaintext string that requires wrapping | ||
* **lineLength** (defaults to 76) Maximum length of a line | ||
@@ -118,4 +99,4 @@ #### #decodeFlowed | ||
* **str** Plaintext string with format=flowed to decode | ||
* **delSp** If true, delete leading spaces (delsp=yes) | ||
* **str** Plaintext string with format=flowed to decode | ||
* **delSp** If true, delete leading spaces (delsp=yes) | ||
@@ -130,3 +111,3 @@ ### Headers | ||
* **headerLine** - Single header line, might include linebreaks as well if folded | ||
* **headerLine** - Single header line, might include linebreaks as well if folded | ||
@@ -141,3 +122,3 @@ #### #decodeHeaders | ||
* **headers** - Headers string | ||
* **headers** - Headers string | ||
@@ -151,3 +132,3 @@ #### #parseHeaderValue | ||
* **valueString** - a header value without the key | ||
* **valueString** - a header value without the key | ||
@@ -177,3 +158,3 @@ **Example** | ||
* **structuredHeader** - a header value formatted with `parseHeaderValue` | ||
* **structuredHeader** - a header value formatted with `parseHeaderValue` | ||
@@ -188,5 +169,5 @@ `filename` argument is encoded with continuation encoding if needed | ||
* **key** - Parameter key (eg. `filename`) | ||
* **str** - String or an Buffer value to encode | ||
* **maxLength** - Maximum length of the encoded string part (not line length). Defaults to 50 | ||
* **key** - Parameter key (eg. `filename`) | ||
* **str** - String or an Buffer value to encode | ||
* **maxLength** - Maximum length of the encoded string part (not line length). Defaults to 50 | ||
@@ -220,3 +201,3 @@ The method returns an array of encoded parts with the following structure: `[{key:'...', value: '...'}]` | ||
* **mimeType** - Content type to be checked for | ||
* **mimeType** - Content type to be checked for | ||
@@ -233,3 +214,3 @@ **Example** | ||
* **extension** Extension (or filename) to be checked for | ||
* **extension** Extension (or filename) to be checked for | ||
@@ -236,0 +217,0 @@ **Example** |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10
3149
143230
7
208
+ Addediconv-lite@0.4.23(transitive)
+ Addedlibbase64@1.0.2(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
- Removediconv-lite@0.4.15(transitive)
- Removedlibbase64@0.1.0(transitive)
Updatediconv-lite@0.4.23
Updatedlibbase64@1.0.2