diff --git a/README.md b/README.md index 4ccde4e..c6eb7ed 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ ImapConnection Properties * **delim** - A String containing the (top-level) mailbox hierarchy delimiter. If the server does not support mailbox hierarchies and only a flat list, this value will be Boolean false. -* **namespaces** - An Object containing 3 properties, one for each namespace type: personal (mailboxes that belong to the logged in user), other (mailboxes that belong to other users that the logged in user has access to), and shared (mailboxes that are accessible by any logged in user). The value of each of these properties is an Array of namespace Objects containing necessary information for each available namespace. There should always be one entry (although the IMAP spec allows for more, it doesn't seem to be very common) in the personal namespace list (if the server supports namespaces) with a blank namespace prefix. Each namespace Object has the following format (with example values): +* **namespaces** - An Object containing 3 properties, one for each namespace type: personal (mailboxes that belong to the logged in user), other (mailboxes that belong to other users that the logged in user has access to), and shared (mailboxes that are accessible by any logged in user). The value of each of these properties is an Array of namespace Objects containing necessary information about each available namespace. There should always be one entry (although the IMAP spec allows for more, it doesn't seem to be very common) in the personal namespace list (if the server supports namespaces) with a blank namespace prefix. Each namespace Object has the following format (with example values): { prefix: '' // A String containing the prefix to use to access mailboxes in this namespace , delimiter: '/' // A String containing the hierarchy delimiter for this namespace, or Boolean false for a flat namespace with no hierarchy @@ -357,7 +357,7 @@ A bunch of things not yet implemented in no particular order: * Support AUTH=CRAM-MD5/AUTH=CRAM_MD5 authentication * Support additional IMAP commands/extensions: - * STATUS addition to LIST (via LISTA-STATUS extension -- http://tools.ietf.org/html/rfc5819) + * STATUS addition to LIST (via LIST-STATUS extension -- http://tools.ietf.org/html/rfc5819) * GETQUOTA (via QUOTA extension -- http://tools.ietf.org/html/rfc2087) * UNSELECT (via UNSELECT extension -- http://tools.ietf.org/html/rfc3691) * SORT (via SORT extension -- http://tools.ietf.org/html/rfc5256) diff --git a/imap.js b/imap.js index 4416e2a..ed644c9 100644 --- a/imap.js +++ b/imap.js @@ -1,5 +1,5 @@ var sys = require('sys'), net = require('net'), EventEmitter = require('events').EventEmitter; -var emptyFn = function() {}, CRLF = "\r\n", debug=emptyFn/*sys.debug*/, STATES = { NOCONNECT: 0, NOAUTH: 1, AUTH: 2, BOXSELECTING: 3, BOXSELECTED: 4 }, BOX_ATTRIBS = ['NOINFERIORS', 'NOSELECT', 'MARKED', 'UNMARKED']; +var emptyFn = function() {}, CRLF = "\r\n", debug=emptyFn, STATES = { NOCONNECT: 0, NOAUTH: 1, AUTH: 2, BOXSELECTING: 3, BOXSELECTED: 4 }, BOX_ATTRIBS = ['NOINFERIORS', 'NOSELECT', 'MARKED', 'UNMARKED']; function ImapConnection (options) { if (!(this instanceof ImapConnection)) @@ -12,7 +12,8 @@ function ImapConnection (options) { host: 'localhost', port: 143, secure: false, - connTimeout: 10000 // connection timeout in msecs + connTimeout: 10000, // connection timeout in msecs + debug: false }; this._state = { status: STATES.NOCONNECT, @@ -32,6 +33,8 @@ function ImapConnection (options) { }; this._options = extend(true, this._options, options); + if (typeof this._options.debug === 'function') + debug = this._options.debug; this.delim = null; this.namespaces = { personal: [], other: [], shared: [] }; }; @@ -88,7 +91,7 @@ ImapConnection.prototype.connect = function(loginCb) { fnInit(); }); this._state.conn.on('data', function(data) { - var literalData = ''; + var literalData = '', trailingCRLF = false; debug('RECEIVED: ' + data); if (data.indexOf(CRLF) === -1) { @@ -96,8 +99,11 @@ ImapConnection.prototype.connect = function(loginCb) { self._state.curData += data; else self._state.curData = data; - return; + + if (self._state.curData.indexOf(CRLF) === -1) + return; } + if (self._state.curData) data = self._state.curData + data; self._state.curData = undefined; @@ -122,12 +128,21 @@ ImapConnection.prototype.connect = function(loginCb) { } } + if (data.test(/\r\n$/)) + trailingCRLF = true; + data = data.split(CRLF).filter(isNotEmpty); // Defer any extra server responses found in the incoming data if (data.length > 1) { + data.slice(1).forEach(function(line) { - process.nextTick(function() { self._state.conn.emit('data', line + CRLF); }); + process.nextTick(function() { + if (trailingCRLF) + self._state.conn.emit('data', line + CRLF); + else + self._state.conn.emit('data', line); + }); }); } @@ -160,6 +175,7 @@ ImapConnection.prototype.connect = function(loginCb) { case 'FLAGS': if (self._state.status === STATES.BOXSELECTING) self._state.box._flags = data[2].substr(1, data[2].length-2).split(' ').map(function(flag) {return flag.substr(1);});; + break; case 'OK': if ((result = /^\[ALERT\] (.*)$/i.exec(data[2])) !== null) self.emit('alert', result[1]); @@ -257,7 +273,9 @@ ImapConnection.prototype.connect = function(loginCb) { clearTimeout(self._state.tmrKeepalive); self._state.tmrKeepalive = setTimeout(self._idleCheck.bind(self), self._state.tmoKeepalive); - if (self._state.status === STATES.BOXSELECTING) { + if (data[2] === 'NOOP completed.') + return; + else if (self._state.status === STATES.BOXSELECTING) { if (data[1] === 'OK') { sendBox = true; self._state.status = STATES.BOXSELECTED; @@ -885,7 +903,7 @@ function parseFetch(str, literalData, fetchData) { default: var result = /^BODY\[(.*)\](?:\<[\d]+\>)?$/.exec(key); idxNext = str.indexOf("}")+1; - if (result[1].indexOf('HEADER') === 0) { // either full or selective headers + if (result && result[1].indexOf('HEADER') === 0) { // either full or selective headers var headers = literalData.split(/\r\n(?=[\w])/), header; fetchData.headers = {}; for (var i=0,len=headers.length; i