|
|
|
@ -85,31 +85,7 @@ util.inherits(ImapConnection, EventEmitter);
|
|
|
|
|
exports.ImapConnection = ImapConnection;
|
|
|
|
|
|
|
|
|
|
ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
var self = this,
|
|
|
|
|
fnInit = function() {
|
|
|
|
|
// First get pre-auth capabilities, including server-supported auth
|
|
|
|
|
// mechanisms
|
|
|
|
|
self._send('CAPABILITY', function() {
|
|
|
|
|
// Next, attempt to login
|
|
|
|
|
self._login(function(err, reentry) {
|
|
|
|
|
if (err) {
|
|
|
|
|
loginCb(err);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Next, get the list of available namespaces if supported (RFC2342)
|
|
|
|
|
if (!reentry && self._supports('NAMESPACE')) {
|
|
|
|
|
var fnMe = arguments.callee;
|
|
|
|
|
// Re-enter this function after we've obtained the available
|
|
|
|
|
// namespaces
|
|
|
|
|
self._send('NAMESPACE', function(e) { fnMe.call(this, e, true); });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Lastly, get the top-level mailbox hierarchy delimiter used by the
|
|
|
|
|
// server
|
|
|
|
|
self._send('LIST "" ""', loginCb);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
|
|
this._reset();
|
|
|
|
|
|
|
|
|
@ -154,7 +130,28 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
self.emit('close', had_error);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._state.conn.on('ready', fnInit);
|
|
|
|
|
this._state.conn.on('ready', function() {
|
|
|
|
|
// First get pre-auth capabilities, including server-supported auth
|
|
|
|
|
// mechanisms
|
|
|
|
|
self._send('CAPABILITY', function() {
|
|
|
|
|
// Next, attempt to login
|
|
|
|
|
var checkedNS = false;
|
|
|
|
|
self._login(function redo(err) {
|
|
|
|
|
if (err)
|
|
|
|
|
return loginCb(err);
|
|
|
|
|
// Next, get the list of available namespaces if supported (RFC2342)
|
|
|
|
|
if (!checkedNS && self._supports('NAMESPACE')) {
|
|
|
|
|
// Re-enter this function after we've obtained the available
|
|
|
|
|
// namespaces
|
|
|
|
|
checkedNS = true;
|
|
|
|
|
return self._send('NAMESPACE', redo);
|
|
|
|
|
}
|
|
|
|
|
// Lastly, get the top-level mailbox hierarchy delimiter used by the
|
|
|
|
|
// server
|
|
|
|
|
self._send('LIST "" ""', loginCb);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._state.conn.cleartext.on('data', function(data) {
|
|
|
|
|
if (data.length === 0) return;
|
|
|
|
@ -268,12 +265,11 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self._state.conn.cleartext.emit('data', data.slice(idxCRLF + 2));
|
|
|
|
|
return;
|
|
|
|
|
return self._state.conn.cleartext.emit('data', data.slice(idxCRLF + 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.length === 0)
|
|
|
|
|
return;
|
|
|
|
|
if (data.length === 0) return;
|
|
|
|
|
|
|
|
|
|
var endsInCRLF = (data[data.length-2] === 13 && data[data.length-1] === 10);
|
|
|
|
|
data = utils.bufferSplit(data, CRLF);
|
|
|
|
|
|
|
|
|
@ -286,12 +282,12 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
b = new Buffer(needsCRLF ? line.length + 2 : line.length);
|
|
|
|
|
line.copy(b, 0, 0);
|
|
|
|
|
if (needsCRLF) {
|
|
|
|
|
b[b.length-2] = 13;
|
|
|
|
|
b[b.length-1] = 10;
|
|
|
|
|
b[b.length - 2] = 13;
|
|
|
|
|
b[b.length - 1] = 10;
|
|
|
|
|
}
|
|
|
|
|
self._state.conn.cleartext.emit('data', b);
|
|
|
|
|
});
|
|
|
|
|
})(data[i], i === len-1);
|
|
|
|
|
})(data[i], i === len - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -303,17 +299,14 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
self._state.status = STATES.AUTH;
|
|
|
|
|
if (self._state.numCapRecvs === 0)
|
|
|
|
|
self._state.numCapRecvs = 1;
|
|
|
|
|
} else if (data[1] === 'NO' || data[1] === 'BAD' || data[1] === 'BYE') {
|
|
|
|
|
self._state.conn.end();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (data[1] === 'NO' || data[1] === 'BAD' || data[1] === 'BYE')
|
|
|
|
|
return self._state.conn.end();
|
|
|
|
|
if (!self._state.isReady) {
|
|
|
|
|
self._state.isReady = true;
|
|
|
|
|
self._state.conn.emit('ready');
|
|
|
|
|
}
|
|
|
|
|
// Restrict the type of server responses when unauthenticated
|
|
|
|
|
if (data[1] !== 'CAPABILITY' && data[1] !== 'ALERT')
|
|
|
|
|
return;
|
|
|
|
|
if (data[1] !== 'CAPABILITY' && data[1] !== 'ALERT') return;
|
|
|
|
|
}
|
|
|
|
|
switch (data[1]) {
|
|
|
|
|
case 'CAPABILITY':
|
|
|
|
@ -326,8 +319,9 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
break;
|
|
|
|
|
case 'FLAGS':
|
|
|
|
|
if (self._state.status === STATES.BOXSELECTING) {
|
|
|
|
|
self._state.box._flags = data[2].substr(1, data[2].length-2)
|
|
|
|
|
.split(' ').map(function(flag) {
|
|
|
|
|
self._state.box._flags = data[2].substr(1, data[2].length - 2)
|
|
|
|
|
.split(' ')
|
|
|
|
|
.map(function(flag) {
|
|
|
|
|
return flag.substr(1);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -371,10 +365,11 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
case 'LIST':
|
|
|
|
|
case 'XLIST':
|
|
|
|
|
var result;
|
|
|
|
|
if (self.delim === null
|
|
|
|
|
&& (result = /^\(\\No[sS]elect\) (.+?) .*$/.exec(data[2])))
|
|
|
|
|
if (self.delim === null &&
|
|
|
|
|
(result = /^\(\\No[sS]elect(?:[^)]*)\) (.+?) .*$/.exec(data[2])))
|
|
|
|
|
self.delim = (result[1] === 'NIL'
|
|
|
|
|
? false : result[1].substring(1, result[1].length-1));
|
|
|
|
|
? false
|
|
|
|
|
: result[1].substring(1, result[1].length - 1));
|
|
|
|
|
else if (self.delim !== null) {
|
|
|
|
|
if (self._state.requests[0].args.length === 0)
|
|
|
|
|
self._state.requests[0].args.push({});
|
|
|
|
@ -384,12 +379,14 @@ ImapConnection.prototype.connect = function(loginCb) {
|
|
|
|
|
return attrib.substr(1).toUpperCase();
|
|
|
|
|
}),
|
|
|
|
|
delim: (result[2] === 'NIL'
|
|
|
|
|
? false : result[2].substring(1, result[2].length-1)),
|
|
|
|
|
? false
|
|
|
|
|
: result[2].substring(1, result[2].length-1)),
|
|
|
|
|
children: null,
|
|
|
|
|
parent: null
|
|
|
|
|
},
|
|
|
|
|
name = result[3],
|
|
|
|
|
curChildren = self._state.requests[0].args[0];
|
|
|
|
|
|
|
|
|
|
if (name[0] === '"' && name[name.length-1] === '"')
|
|
|
|
|
name = name.substring(1, name.length - 1);
|
|
|
|
|
|
|
|
|
@ -727,7 +724,8 @@ ImapConnection.prototype._fetch = function(which, uids, options) {
|
|
|
|
|
headers: true,
|
|
|
|
|
body: false
|
|
|
|
|
}
|
|
|
|
|
}, toFetch, useParser = false, bodyRange = '', self = this;
|
|
|
|
|
}, toFetch, bodyRange, extensions, useParser, self = this;
|
|
|
|
|
|
|
|
|
|
if (typeof options !== 'object')
|
|
|
|
|
options = {};
|
|
|
|
|
utils.extend(true, opts, options);
|
|
|
|
@ -775,26 +773,38 @@ ImapConnection.prototype._fetch = function(which, uids, options) {
|
|
|
|
|
useParser = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var extensions = '';
|
|
|
|
|
// always fetch GMail-specific bits of information when on GMail
|
|
|
|
|
if (this._supports('X-GM-EXT-1'))
|
|
|
|
|
extensions = 'X-GM-THRID X-GM-MSGID X-GM-LABELS ';
|
|
|
|
|
|
|
|
|
|
this._send(which + 'FETCH ' + uids.join(',') + ' (' + extensions
|
|
|
|
|
+ 'UID FLAGS INTERNALDATE'
|
|
|
|
|
+ (opts.request.struct ? ' BODYSTRUCTURE' : '')
|
|
|
|
|
+ (typeof toFetch === 'string' ? ' BODY'
|
|
|
|
|
+ (!opts.markSeen ? '.PEEK' : '')
|
|
|
|
|
+ '[' + toFetch + ']' + bodyRange : '') + ')', function(e) {
|
|
|
|
|
var fetcher = self._state.requests[0]._fetcher;
|
|
|
|
|
if (e && fetcher)
|
|
|
|
|
fetcher.emit('error', e);
|
|
|
|
|
else if (e && !fetcher)
|
|
|
|
|
self.emit('error', e);
|
|
|
|
|
else if (fetcher)
|
|
|
|
|
fetcher.emit('end');
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
var cmd = which;
|
|
|
|
|
cmd += 'FETCH ';
|
|
|
|
|
cmd += uids.join(',');
|
|
|
|
|
cmd += ' (';
|
|
|
|
|
if (extensions)
|
|
|
|
|
cmd += extensions;
|
|
|
|
|
cmd += 'UID FLAGS INTERNALDATE';
|
|
|
|
|
if (toFetch !== undefined) {
|
|
|
|
|
cmd += ' BODY';
|
|
|
|
|
if (!opts.markSeen)
|
|
|
|
|
cmd += '.PEEK';
|
|
|
|
|
cmd += '[';
|
|
|
|
|
cmd += toFetch;
|
|
|
|
|
cmd += ']';
|
|
|
|
|
if (bodyRange)
|
|
|
|
|
cmd += bodyRange;
|
|
|
|
|
}
|
|
|
|
|
cmd += ')';
|
|
|
|
|
|
|
|
|
|
this._send(cmd, function(e) {
|
|
|
|
|
var fetcher = self._state.requests[0]._fetcher;
|
|
|
|
|
if (e && fetcher)
|
|
|
|
|
fetcher.emit('error', e);
|
|
|
|
|
else if (e && !fetcher)
|
|
|
|
|
self.emit('error', e);
|
|
|
|
|
else if (fetcher)
|
|
|
|
|
fetcher.emit('end');
|
|
|
|
|
});
|
|
|
|
|
var imapFetcher = new ImapFetch(),
|
|
|
|
|
req = this._state.requests[this._state.requests.length - 1];
|
|
|
|
|
req._fetcher = imapFetcher;
|
|
|
|
|