Comparing version 0.2.1 to 0.2.2
var convert = require("encoding").convert, | ||
addressparser = require("addressparser"); | ||
/** | ||
* Folds a long line according to the RFC 5322 http://tools.ietf.org/html/rfc5322#section-2.1.1 | ||
* | ||
* @param {String} str Mime string that might need folding | ||
* @param {Number} [maxLength=76] max length for a line | ||
* @param {Boolean} [foldAnywhere] If true, can fold at any location (ie. in base64) | ||
* @param {Boolean} [afterSpace] If true fold after the space (default is before) | ||
* @return {String} Folded string | ||
*/ | ||
this.foldLine = function(str, maxLength, foldAnywhere, afterSpace){ | ||
@@ -11,6 +20,34 @@ if(foldAnywhere){ | ||
module.exports.encodeMimeWord = function(str, encoding, charset){ | ||
return module.exports.mimeFunctions.encodeMimeWord(str, encoding, charset); | ||
/** | ||
* Encodes a string into mime encoded word format http://en.wikipedia.org/wiki/MIME#Encoded-Word | ||
* | ||
* @param {String} str String to be encoded | ||
* @param {String} encoding Encoding Q for quoted printable or B for base64 | ||
* @param {String} [charset="UTF-8"] Charset to be used | ||
* @param {Number} [maxLength] If set, split on maxLength | ||
* @return {String} Mime word encoded string | ||
*/ | ||
module.exports.encodeMimeWord = function(str, encoding, charset, maxLength){ | ||
return module.exports.mimeFunctions.encodeMimeWord(str, encoding, maxLength || 0, charset); | ||
}; | ||
/** | ||
* Encodes need parts of a string to mime word format | ||
* | ||
* @param {String} str String to be encoded | ||
* @param {String} encoding Encoding Q for quoted printable or B for base64 | ||
* @param {Number} [maxLength] If set, split on maxLength | ||
* @param {String} [charset="UTF-8"] Charset to be used | ||
* @return {String} String with possible mime word encoded parts | ||
*/ | ||
module.exports.encodeMimeWords = function(str, encoding, maxLength, charset){ | ||
return module.exports.mimeFunctions.encodeMimeWords(str, encoding, maxLength || 0, charset); | ||
}; | ||
/** | ||
* Decodes a string from mime encoded word | ||
* | ||
* @param {String} str Mime word encoded string | ||
* @return {String} Decoded string | ||
*/ | ||
module.exports.decodeMimeWord = function(str){ | ||
@@ -20,2 +57,8 @@ return module.exports.mimeFunctions.decodeMimeWord(str).toString("utf-8"); | ||
/** | ||
* Decodes all mime words from a string to an unencoded string | ||
* | ||
* @param {String} str String that may include mime words | ||
* @return {String} Unencoded string | ||
*/ | ||
module.exports.parseMimeWords = function(str){ | ||
@@ -25,7 +68,32 @@ return module.exports.mimeFunctions.decodeMimeWords(str).toString("utf-8"); | ||
/** | ||
* Encodes a string into Quoted-printable format. Maximum line length for the | ||
* encoded string is always 76+2 bytes | ||
* | ||
* @param {String} str String to be encoded into Quoted-printable | ||
* @param {Boolean} [mimeWord] legacy parameter, not used | ||
* @param {String} [charset="UTF-8"] Destination charset | ||
* @return {String} Quoted printable encoded string | ||
*/ | ||
module.exports.encodeQuotedPrintable = function(str, mimeWord, charset){ | ||
if(typeof mimeWord == "string" && !charset){ | ||
charset = mimeWord; | ||
mimeWord = undefined; | ||
} | ||
return module.exports.mimeFunctions.encodeQuotedPrintable(str, charset); | ||
}; | ||
/** | ||
* Decodes a string from Quoted-printable format | ||
* | ||
* @param {String} str String to be decoded from Quoted-printable | ||
* @param {Boolean} [mimeWord] legacy parameter, not used | ||
* @param {String} [charset="UTF-8"] Source charset | ||
* @return {String} Decoded string | ||
*/ | ||
module.exports.decodeQuotedPrintable = function(str, mimeWord, charset){ | ||
if(typeof mimeWord == "string" && !charset){ | ||
charset = mimeWord; | ||
mimeWord = undefined; | ||
} | ||
charset = (charset || "").toString().toUpperCase().trim(); | ||
@@ -36,2 +104,9 @@ var decodedString = module.exports.mimeFunctions.decodeQuotedPrintable(str, "utf-8", charset); | ||
/** | ||
* Encodes a string into Base64 format. Base64 is mime-word safe | ||
* | ||
* @param {String} str String to be encoded into Base64 | ||
* @param {String} [charset="UTF-8"] Destination charset | ||
* @return {String} Base64 encoded string | ||
*/ | ||
module.exports.encodeBase64 = function(str, charset){ | ||
@@ -41,2 +116,9 @@ return module.exports.mimeFunctions.encodeBase64(str, charset); | ||
/** | ||
* Decodes a string from Base64 format | ||
* | ||
* @param {String} str String to be decoded from Base64 | ||
* @param {String} [charset="UTF-8"] Source charset | ||
* @return {String} Decoded string | ||
*/ | ||
module.exports.decodeBase64 = function(str, charset){ | ||
@@ -46,2 +128,10 @@ return module.exports.mimeFunctions.decodeBase64(str, "utf-8", charset).toString("utf-8"); | ||
/** | ||
* Parses names and addresses from a from, to, cc or bcc line | ||
* For example: 'Andris Reinman <andris@tr.ee>, someone@else.com' | ||
* will be parsed into: [{name:"Andris Reinman", address:"andris@tr.ee"}, {address: "someone@else.com"}] | ||
* | ||
* @param {String|Array} addresses Address line string or an array of strings | ||
* @return {Array} An array of parsed e-mails addresses in the form of [{name, address}] | ||
*/ | ||
module.exports.parseAddresses = function(addresses){ | ||
@@ -51,2 +141,8 @@ return [].concat.apply([], [].concat(addresses).map(addressparser)); | ||
/** | ||
* Parses header lines into an array of objects. Output: {'x-header': ['value']} | ||
* | ||
* @param {String} headers Full header part to be parsed | ||
* @return {Object} Parsed headers | ||
*/ | ||
module.exports.parseHeaders = function(headers){ | ||
@@ -56,2 +152,11 @@ return module.exports.mimeFunctions.parseHeaders(headers); | ||
/** | ||
* Parses a header line to search for additional parameters. For example | ||
* parseHeaderLine('text/plain; charset=utf-8') | ||
* will be parsed into | ||
* {defaultValue: 'text/plain', charset: 'utf-8'} | ||
* | ||
* @param {String} line Single header value without key part to be parsed | ||
* @return {Object} Parsed value | ||
*/ | ||
module.exports.parseHeaderLine = function(line){ | ||
@@ -157,3 +262,3 @@ if(!line) | ||
encodeMimeWord: function(str, encoding, toCharset, fromCharset){ | ||
encodeMimeWord: function(str, encoding, maxLength, toCharset, fromCharset){ | ||
toCharset = (toCharset || "utf-8").toString().toUpperCase().trim(); | ||
@@ -163,2 +268,6 @@ encoding = (encoding || "Q").toString().toUpperCase().trim().charAt(0); | ||
if(maxLength && maxLength > 7 + toCharset.length){ | ||
maxLength -= (7 + toCharset.length); | ||
} | ||
if(encoding == "Q"){ | ||
@@ -174,3 +283,17 @@ encodedStr = this.mimeEncode(str, toCharset, fromCharset); | ||
return "=?"+toCharset+"?"+encoding+"?"+encodedStr+"?="; | ||
if(maxLength && encodedStr.length > maxLength){ | ||
if(encoding == "Q"){ | ||
encodedStr = this.splitEncodedString(encodedStr, maxLength).join("?= =?"+toCharset+"?"+encoding+"?") | ||
}else{ | ||
encodedStr = encodedStr.replace(new RegExp(".{"+maxLength+"}","g"),"$&?= =?"+toCharset+"?"+encoding+"?"); | ||
if(encodedStr.substr(-(" =?"+toCharset+"?"+encoding+"?=").length) == " =?"+toCharset+"?"+encoding+"?="){ | ||
encodedStr = encodedStr.substr(0, encodedStr.length -(" =?"+toCharset+"?"+encoding+"?=").length); | ||
} | ||
if(encodedStr.substr(-(" =?"+toCharset+"?"+encoding+"?").length) == " =?"+toCharset+"?"+encoding+"?"){ | ||
encodedStr = encodedStr.substr(0, encodedStr.length -(" =?"+toCharset+"?"+encoding+"?").length); | ||
} | ||
} | ||
} | ||
return "=?"+toCharset+"?"+encoding+"?"+encodedStr+ (encodedStr.substr(-2)=="?="?"":"?="); | ||
}, | ||
@@ -204,6 +327,23 @@ | ||
decodeMimeWords: function(str, toCharset){ | ||
var remainder = "", lastCharset, curCharset; | ||
str = (str || "").toString(); | ||
str = str.replace(/(\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)\s+(?=\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)/g,"$1"). | ||
replace(/\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=/g, (function(mimeWord){ | ||
while(str.match(/(\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)\s+(?=\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)/g)){ | ||
str = str.replace(/(\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)\s+(\=\?[\w_\-]+\?[QB]\?[^\?]+\?\=)/g,function(original, first, second){ | ||
var match1 = (first || "").trim().match(/^\=\?([\w_\-]+)\?([QB])\?([^\?]+)\?\=$/), | ||
match2 = (second || "").trim().match(/^\=\?([\w_\-]+)\?([QB])\?([^\?]+)\?\=$/); | ||
if(match1[1] == match2[1] && match1[2] == match2[2]){ | ||
return "=?"+match1[1]+"?"+match1[2]+"?"+match1[3] + match2[3]+"?="; | ||
}else{ | ||
return first+second; | ||
} | ||
}); | ||
} | ||
str = str.replace(/\=\?([\w_\-]+)\?([QB])\?[^\?]+\?\=/g, (function(mimeWord, charset, encoding){ | ||
curCharset = charset + encoding; | ||
return this.decodeMimeWord(mimeWord); | ||
@@ -247,10 +387,15 @@ }).bind(this)); | ||
encodeHeaderLine: function(key, value, toCharset, fromCharset){ | ||
encodeMimeWords: function(value, encoding, maxLength, toCharset, fromCharset){ | ||
var decodedValue = convert((value || ""), "utf-8", fromCharset).toString("utf-8"), | ||
encodedValue; | ||
encodedValue = decodedValue.replace(/\w*[\u0080-\uFFFF]+\w*(?:\s+\w*[\u0080-\uFFFF]+\w*)?/g, (function(str){ | ||
return this.encodeMimeWord(str, "Q", toCharset); | ||
encodedValue = decodedValue.replace(/(\w*[\u0080-\uFFFF]+\w*(?:\s+\w*[\u0080-\uFFFF]+\w*\s*)?)+/g, (function(str, o){ | ||
return str.length?this.encodeMimeWord(str, encoding || "Q", maxLength, toCharset):""; | ||
}).bind(this)); | ||
return encodedValue; | ||
}, | ||
encodeHeaderLine: function(key, value, toCharset, fromCharset){ | ||
var encodedValue = this.encodeMimeWords(value, 52, toCharset, fromCharset); | ||
return this.foldLine(key+": "+encodedValue, 76); | ||
@@ -300,2 +445,37 @@ }, | ||
splitEncodedString: function(str, maxlen){ | ||
var curLine, match, chr, done, | ||
lines = []; | ||
while(str.length){ | ||
curLine = str.substr(0, maxlen); | ||
// move incomplete escaped char back to main | ||
if((match = curLine.match(/\=[0-9A-F]?$/i))){ | ||
curLine = curLine.substr(0, match.index); | ||
} | ||
done = false; | ||
while(!done){ | ||
done = true; | ||
// check if not middle of a unicode char sequence | ||
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){ | ||
curLine = curLine.substr(0, curLine.length-3); | ||
done = false; | ||
} | ||
} | ||
} | ||
if(curLine.length){ | ||
lines.push(curLine); | ||
} | ||
str = str.substr(curLine.length); | ||
} | ||
return lines; | ||
}, | ||
parseAddresses: addressparser | ||
@@ -302,0 +482,0 @@ |
{ | ||
"name": "mimelib", | ||
"description": "MIME functions to encode/decode e-mails etc.", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"author" : "Andris Reinman", | ||
@@ -6,0 +6,0 @@ "homepage":"http://github.com/andris9/mimelib", |
@@ -28,3 +28,3 @@ # mimelib | ||
mimelib.foldLine(str [, maxLength][, foldAnywhere]) -> String | ||
mimelib.foldLine(str [, maxLength][, foldAnywhere][, afterSpace]) -> String | ||
@@ -87,3 +87,3 @@ - `str` (String): mime string that might need folding | ||
- `str` (String): String to be encoded into Quoted-printable | ||
- `mimeWord` (Boolean): Use mime-word mode (defaults to false) | ||
- `mimeWord` (Boolean): Deprecated, has no effect, ignore it | ||
- `charset` (String): Destination charset, defaults to UTF-8 | ||
@@ -95,6 +95,6 @@ | ||
mimelib.deccodeQuotedPrintable(str [, mimeWord][, charset]) -> String | ||
mimelib.decodeQuotedPrintable(str [, mimeWord][, charset]) -> String | ||
- `str` (String): String to be decoded | ||
- `mimeWord` (Boolean): Use mime-word mode (defaults to false) | ||
- `mimeWord` (Boolean): Deprecated, has no effect, ignore it | ||
- `charset` (String): Charset to be used, defaults to UTF-8 | ||
@@ -101,0 +101,0 @@ |
@@ -51,2 +51,9 @@ var testCase = require('nodeunit').testCase, | ||
test.done(); | ||
}, | ||
"Surrogate pair": function(test){ | ||
// 💩 pile of poo | ||
test.equal("=F0=9F=92=A9", mimelib.encodeQuotedPrintable('\ud83d\udca9')) | ||
test.equal("\ud83d\udca9", mimelib.decodeQuotedPrintable('=F0=9F=92=A9')) | ||
test.done(); | ||
} | ||
@@ -81,4 +88,24 @@ } | ||
test.done(); | ||
}, | ||
"Split on maxLength QP": function(test){ | ||
var inputStr = "Jõgeva Jõgeva Jõgeva mugeva Jõgeva Jõgeva Jõgeva Jõgeva Jõgeva", | ||
outputStr = "=?ISO-8859-1?Q?J=F5geva_J=F5gev?= =?ISO-8859-1?Q?a_J=F5geva?= mugeva =?ISO-8859-1?Q?J=F5geva_J=F5gev?= =?ISO-8859-1?Q?a_J=F5geva_J=F5g?= =?ISO-8859-1?Q?eva_J=F5geva?=", | ||
encoded = mimelib.encodeMimeWords(inputStr, "Q", 16, "ISO-8859-1"); | ||
test.equal(outputStr, encoded) | ||
test.equal(inputStr, mimelib.parseMimeWords(encoded)); | ||
test.done(); | ||
}, | ||
"Split on maxLength Base64": function(test){ | ||
var inputStr = "Jõgeva Jõgeva Jõgeva mugeva Jõgeva Jõgeva Jõgeva Jõgeva Jõgeva", | ||
outputStr = "=?ISO-8859-1?B?SvVnZXZhIEr1Z2V2?= =?ISO-8859-1?B?YSBK9WdldmE=?= mugeva =?ISO-8859-1?B?SvVnZXZhIEr1Z2V2?= =?ISO-8859-1?B?YSBK9WdldmEgSvVn?= =?ISO-8859-1?B?ZXZhIEr1Z2V2YQ==?=", | ||
encoded = mimelib.encodeMimeWords(inputStr,"B", 16, "ISO-8859-1"); | ||
test.equal(outputStr, encoded) | ||
test.equal(inputStr, mimelib.parseMimeWords(encoded)); | ||
test.done(); | ||
} | ||
} | ||
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
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
646629
11
756
1