Comparing version 0.8.2 to 0.8.3
@@ -882,3 +882,3 @@ var tls = require('tls'), | ||
cb(err, quotalist[0]); | ||
cb(err, quotalist ? quotalist[0] : limits); | ||
} | ||
@@ -1144,4 +1144,3 @@ ); | ||
--this._box.messages.total; | ||
if (!this._curReq) | ||
this.emit('expunge', info.num); | ||
this.emit('expunge', info.num); | ||
} | ||
@@ -1334,6 +1333,6 @@ } else if (type === 'ok') { | ||
var errtext; | ||
if (req.oauthError) | ||
if (info.text) | ||
errtext = info.text; | ||
else | ||
errtext = req.oauthError; | ||
else | ||
errtext = info.text; | ||
err = new Error(errtext); | ||
@@ -1470,4 +1469,6 @@ err.type = info.type; | ||
|| (self._config.autotls === 'required' | ||
&& self.serverSupports('LOGINDISABLED')))) | ||
&& self.serverSupports('LOGINDISABLED')))) { | ||
self._starttls(); | ||
return; | ||
} | ||
@@ -1599,2 +1600,3 @@ if (self.serverSupports('LOGINDISABLED')) { | ||
} | ||
function validateUIDList(uids, noThrow) { | ||
@@ -1622,12 +1624,11 @@ for (var i = 0, len = uids.length, intval; i < len; ++i) { | ||
} | ||
function hasNonASCII(str) { | ||
var ret = false; | ||
for (var i = 0, len = str.length; i < len; ++i) { | ||
if (str.charCodeAt(i) > 0x7F) { | ||
ret = true; | ||
break; | ||
} | ||
if (str.charCodeAt(i) > 0x7F) | ||
return true; | ||
} | ||
return ret; | ||
return false; | ||
} | ||
function buildString(str) { | ||
@@ -1643,2 +1644,3 @@ if (typeof str !== 'string') | ||
} | ||
function buildSearchQuery(options, extensions, info, isOrChild) { | ||
@@ -1645,0 +1647,0 @@ var searchargs = '', err, val; |
@@ -6,4 +6,3 @@ var EventEmitter = require('events').EventEmitter, | ||
utf7 = require('utf7').imap, | ||
iconv = require('iconv-lite'), | ||
jsencoding/*lazy-loaded*/; | ||
jsencoding; // lazy-loaded | ||
@@ -28,3 +27,4 @@ var CH_LF = 10, | ||
RE_QENC = /(?:=([a-fA-F0-9]{2}))|_/g, | ||
RE_SEARCH_MODSEQ = /^(.+) \(MODSEQ (.+?)\)$/i; | ||
RE_SEARCH_MODSEQ = /^(.+) \(MODSEQ (.+?)\)$/i, | ||
RE_LWS_ONLY = /^[ \t]*$/; | ||
@@ -42,8 +42,9 @@ function Parser(stream, debug) { | ||
this._buffer = ''; | ||
this._ignoreReadable = false; | ||
this.debug = debug; | ||
this.setStream(stream); | ||
var self = this; | ||
this._cbReadable = function() { | ||
if (self._ignoreReadable) | ||
return; | ||
if (self._literallen > 0 && !self._body) | ||
@@ -54,3 +55,5 @@ self._tryread(self._literallen); | ||
}; | ||
this._stream.on('readable', this._cbReadable); | ||
this.setStream(stream); | ||
process.nextTick(this._cbReadable); | ||
@@ -61,2 +64,6 @@ } | ||
Parser.prototype.setStream = function(stream) { | ||
if (this._stream) { | ||
this._stream.removeListener('readable', this._cbReadable); | ||
} | ||
if (/^v0\.8\./.test(process.version)) { | ||
@@ -71,2 +78,4 @@ this._stream = (new ReadableStream()).wrap(stream); | ||
this._stream = stream; | ||
this._stream.on('readable', this._cbReadable); | ||
}; | ||
@@ -87,4 +96,3 @@ | ||
var litlen = this._literallen; | ||
i = this._literallen; | ||
i = litlen; | ||
this._literallen = 0; | ||
@@ -138,4 +146,6 @@ body.push(data.slice(0, litlen)); | ||
if (this._literallen > 0 && i < datalen) { | ||
this._ignoreReadable = true; | ||
// literal data included in this chunk -- put it back onto stream | ||
this._stream.unshift(data.slice(i)); | ||
this._ignoreReadable = false; | ||
i = datalen; | ||
@@ -685,36 +695,136 @@ if (!this._body) { | ||
function decodeBytes(buf, encoding) { | ||
if (iconv.encodingExists(encoding)) | ||
return iconv.decode(buf, encoding); | ||
else { | ||
if (!jsencoding) | ||
jsencoding = require('../deps/encoding/encoding'); | ||
if (jsencoding.encodingExists(encoding)) | ||
return jsencoding.TextDecoder(encoding).decode(buf); | ||
else | ||
return buf.toString('binary'); | ||
} | ||
function repeat(chr, len) { | ||
var s = ''; | ||
for (var i = 0; i < len; ++i) | ||
s += chr; | ||
return s; | ||
} | ||
function decodeWords(str) { | ||
return str.replace(RE_ENCWORD, | ||
function(match, charset, encoding, word) { | ||
encoding = encoding.toLowerCase(); | ||
if (encoding === 'q') { | ||
// q-encoding, similar to quoted-printable | ||
return decodeBytes(new Buffer(word.replace(RE_QENC, | ||
function(match2, byte) { | ||
if (match2 === '_') | ||
return ' '; | ||
else | ||
return String.fromCharCode(parseInt(byte, 16)); | ||
} | ||
), 'binary'), charset); | ||
function decodeBytes(buf, encoding, offset, mlen, state) { | ||
if (!jsencoding) | ||
jsencoding = require('../deps/encoding/encoding'); | ||
if (jsencoding.encodingExists(encoding)) { | ||
if (state.buffer !== undefined) { | ||
if (state.encoding === encoding && state.consecutive) { | ||
// concatenate buffer + current bytes in hopes of finally having | ||
// something that's decodable | ||
var newbuf = new Buffer(state.buffer.length + buf.length); | ||
state.buffer.copy(newbuf, 0); | ||
buf.copy(newbuf, state.buffer.length); | ||
buf = newbuf; | ||
} else { | ||
// base64 | ||
return decodeBytes(new Buffer(word, 'base64'), charset); | ||
// either: | ||
// - the current encoded word is not separated by the previous partial | ||
// encoded word by linear whitespace, OR | ||
// - the current encoded word and the previous partial encoded word | ||
// use different encodings | ||
state.buffer = state.encoding = undefined; | ||
state.curReplace = undefined; | ||
} | ||
} | ||
var ret, isPartial = false; | ||
try { | ||
ret = jsencoding.TextDecoder(encoding).decode(buf); | ||
} catch (e) { | ||
if (e.message.indexOf('Seeking') === 0) | ||
isPartial = true; | ||
} | ||
if (ret !== undefined) { | ||
if (state.curReplace) { | ||
// we have some previous partials which were finally "satisfied" by the | ||
// current encoded word, so replace from the beginning of the first | ||
// partial to the end of the current encoded word | ||
state.replaces.push({ | ||
fromOffset: state.curReplace[0].fromOffset, | ||
toOffset: offset + mlen, | ||
val: ret | ||
}); | ||
state.replaces.splice(state.replaces.indexOf(state.curReplace), 1); | ||
state.curReplace = undefined; | ||
} else { | ||
// normal case where there are no previous partials and we successfully | ||
// decoded a single encoded word | ||
state.replaces.push({ | ||
fromOffset: offset, | ||
toOffset: offset + mlen, | ||
val: ret | ||
}); | ||
} | ||
state.buffer = state.encoding = undefined; | ||
return; | ||
} else if (isPartial) { | ||
// RFC2047 says that each decoded encoded word "MUST represent an integral | ||
// number of characters. A multi-octet character may not be split across | ||
// adjacent encoded-words." However, some MUAs appear to go against this, | ||
// so we join broken encoded words separated by linear white space until | ||
// we can successfully decode or we see a change in encoding | ||
state.encoding = encoding; | ||
state.buffer = buf; | ||
if (!state.curReplace) | ||
state.replaces.push(state.curReplace = []); | ||
state.curReplace.push({ | ||
fromOffset: offset, | ||
toOffset: offset + mlen, | ||
// the value we replace this encoded word with if it doesn't end up | ||
// becoming part of a successful decode | ||
val: repeat('\uFFFD', buf.length) | ||
}); | ||
return; | ||
} | ||
} | ||
// in case of unexpected error or unsupported encoding, just substitute the | ||
// raw bytes | ||
state.replaces.push({ | ||
fromOffset: offset, | ||
toOffset: offset + mlen, | ||
val: buf.toString('binary') | ||
}); | ||
} | ||
function qEncReplacer(match, byte) { | ||
if (match === '_') | ||
return ' '; | ||
else | ||
return String.fromCharCode(parseInt(byte, 16)); | ||
} | ||
function decodeWords(str, state) { | ||
var pendoffset = -1; | ||
state.replaces = []; | ||
var bytes, m, i, len, j, lenj, seq; | ||
// generate replacement substrings and their positions | ||
while (m = RE_ENCWORD.exec(str)) { | ||
state.consecutive = (pendoffset > -1 | ||
? RE_LWS_ONLY.test(str.substring(pendoffset, m.index)) | ||
: false); | ||
pendoffset = m.index + m[0].length; | ||
if (m[2].toLowerCase() === 'q') { | ||
// q-encoding, similar to quoted-printable | ||
bytes = new Buffer(m[3].replace(RE_QENC, qEncReplacer), 'binary'); | ||
} else { | ||
// base64 | ||
bytes = new Buffer(m[3], 'base64'); | ||
} | ||
decodeBytes(bytes, m[1].toLowerCase(), m.index, m[0].length, state); | ||
} | ||
// perform the actual replacements | ||
for (i = state.replaces.length - 1; i >= 0; --i) { | ||
seq = state.replaces[i]; | ||
if (Array.isArray(seq)) { | ||
for (j = 0, lenj = seq.length; j < lenj; ++j) { | ||
str = str.substring(0, seq[j].fromOffset) | ||
+ seq[j].val | ||
+ str.substring(seq[j].toOffset); | ||
} | ||
} else { | ||
str = str.substring(0, seq.fromOffset) | ||
+ seq.val | ||
+ str.substring(seq.toOffset); | ||
} | ||
} | ||
return str; | ||
} | ||
function parseHeader(str, noDecode) { | ||
@@ -724,5 +834,12 @@ var lines = str.split(RE_CRLF), | ||
header = {}, | ||
m, h, val; | ||
state = { | ||
buffer: undefined, | ||
encoding: undefined, | ||
consecutive: false, | ||
replaces: undefined, | ||
curReplace: undefined | ||
}, | ||
m, h, i, val; | ||
for (var i = 0; i < len; ++i) { | ||
for (i = 0; i < len; ++i) { | ||
if (lines[i].length === 0) | ||
@@ -740,3 +857,2 @@ break; // empty line separates message's header and body | ||
} | ||
val = decodeWords(val); | ||
} | ||
@@ -749,5 +865,2 @@ header[h][header[h].length - 1] += val; | ||
if (m[2]) { | ||
if (!noDecode) | ||
m[2] = decodeWords(m[2]); | ||
if (header[h] === undefined) | ||
@@ -763,2 +876,10 @@ header[h] = [m[2]]; | ||
} | ||
if (!noDecode) { | ||
var hvs; | ||
for (h in header) { | ||
hvs = header[h]; | ||
for (i = 0, len = header[h].length; i < len; ++i) | ||
hvs[i] = decodeWords(hvs[i], state); | ||
} | ||
} | ||
@@ -765,0 +886,0 @@ return header; |
{ "name": "imap", | ||
"version": "0.8.2", | ||
"version": "0.8.3", | ||
"author": "Brian White <mscdex@mscdex.net>", | ||
@@ -8,4 +8,3 @@ "description": "An IMAP module for node.js that makes communicating with IMAP servers easy", | ||
"utf7": "1.0.0", | ||
"iconv-lite": "0.2.11", | ||
"readable-stream": "1.0.15" | ||
"readable-stream": "1.1.7" | ||
}, | ||
@@ -12,0 +11,0 @@ "scripts": { |
Sorry, the diff of this file is too big to display
2
769061
7549
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddebuglog@0.0.2(transitive)
+ Addedreadable-stream@1.1.7(transitive)
- Removediconv-lite@0.2.11
- Removediconv-lite@0.2.11(transitive)
- Removedreadable-stream@1.0.15(transitive)
Updatedreadable-stream@1.1.7