diff --git a/lib/imap.js b/lib/imap.js index ab8d25c..d282a10 100644 --- a/lib/imap.js +++ b/lib/imap.js @@ -1,4 +1,5 @@ var assert = require('assert'), + tls = require('tls'), isDate = require('util').isDate, inspect = require('util').inspect, inherits = require('util').inherits, @@ -118,26 +119,22 @@ ImapConnection.prototype.connect = function(loginCb) { requests = state.requests, indata = state.indata; - state.conn = new Socket(); - state.conn.setKeepAlive(true); + var socket = state.conn = new Socket(); + socket.setKeepAlive(true); + socket.setTimeout(0); - if (this._options.secure) { - // TODO: support STARTTLS - state.conn.cleartext = utils.setSecure(state.conn); - state.conn.on('secure', function() { - state.connected = true; - self.debug&&self.debug('[connection] Secure connection made.'); - }); - } else - state.conn.cleartext = state.conn; + if (this._options.secure) + socket = tls.connect({ socket: state.conn }, onconnect); + else + state.conn.once('connect', onconnect); - state.conn.on('connect', function() { + function onconnect() { + state.conn = socket; // re-assign for secure connections state.connected = true; state.authenticated = false; self.debug&&self.debug('[connection] Connected to host.'); - state.conn.cleartext.write(''); state.status = STATES.NOAUTH; - }); + }; state.conn.on('end', function() { state.connected = false; @@ -146,16 +143,6 @@ ImapConnection.prototype.connect = function(loginCb) { self.emit('end'); }); - function errorHandler(err) { - clearTimeout(state.tmrConn); - if (state.status === STATES.NOCONNECT) - loginCb(new Error('Unable to connect. Reason: ' + err)); - self.emit('error', err); - self.debug&&self.debug('[connection] Error occurred: ' + err); - } - - state.conn.cleartext.on('error', errorHandler); - state.conn.on('close', function(had_error) { self._reset(); requests = state.requests; @@ -165,7 +152,15 @@ ImapConnection.prototype.connect = function(loginCb) { self.emit('close', had_error); }); - state.conn.on('ready', function() { + state.conn.on('error', function(err) { + clearTimeout(state.tmrConn); + if (state.status === STATES.NOCONNECT) + loginCb(new Error('Unable to connect. Reason: ' + err)); + self.emit('error', err); + self.debug&&self.debug('[connection] Error occurred: ' + err); + }); + + socket.on('ready', function() { var checkedNS = false; var reentry = function(err) { if (err) { @@ -236,6 +231,8 @@ ImapConnection.prototype.connect = function(loginCb) { } } + socket.on('data', ondata); + function ondata(b) { b.p || (b.p = 0); if (b.length === 0 || b.p >= b.length) return; @@ -705,24 +702,23 @@ ImapConnection.prototype.connect = function(loginCb) { } } - state.conn.cleartext.on('data', ondata); - state.conn.connect(this._options.port, this._options.host); state.tmrConn = setTimeout(function() { state.conn.destroy(); + state.conn = undefined; loginCb(new Error('Connection timed out')); }, this._options.connTimeout); }; -ImapConnection.prototype.isAuthenticated = function() { - return this.authenticated; -}; - ImapConnection.prototype.logout = function(cb) { + var self = this; if (this._state.status >= STATES.NOAUTH) { - this._send('LOGOUT', cb); - this._state.conn.end(); + this._send('LOGOUT', function(err) { + self._state.conn.end(); + if (typeof cb === 'function') + cb(err); + }); if (cb === true) this._state.conn.removeAllListeners(); } else @@ -851,8 +847,8 @@ ImapConnection.prototype.append = function(data, options, cb) { this._send(cmd, function(err) { if (err || step++ === 2) return cb(err); - self._state.conn.cleartext.write(data); - self._state.conn.cleartext.write(CRLF); + self._state.conn.write(data); + self._state.conn.write(CRLF); self.debug&&self.debug('\n==> ' + inspect(data.toString()) + '\n'); }); }; @@ -1484,9 +1480,9 @@ ImapConnection.prototype._send = function(cmdstr, cb, bypass) { } if (cmd !== 'IDLE' && cmd !== 'DONE') prefix = 'A' + (++this._state.curId) + ' '; - this._state.conn.cleartext.write(prefix); - this._state.conn.cleartext.write(cmd); - this._state.conn.cleartext.write(CRLF); + this._state.conn.write(prefix); + this._state.conn.write(cmd); + this._state.conn.write(CRLF); this.debug&&this.debug('\n==> ' + prefix + cmd + '\n'); if (this._state.requests[0] && (this._state.requests[0].cmd === 'EXAMINE' diff --git a/lib/imap.utilities.js b/lib/imap.utilities.js index a07e62f..26a161e 100644 --- a/lib/imap.utilities.js +++ b/lib/imap.utilities.js @@ -1,41 +1,6 @@ -var tls = require('tls'); - exports.MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -exports.setSecure = function(tcpSocket) { - var pair = tls.createSecurePair(), - cleartext; - - pair.encrypted.pipe(tcpSocket); - tcpSocket.pipe(pair.encrypted); - pair.fd = tcpSocket.fd; - - cleartext = pair.cleartext; - cleartext.socket = tcpSocket; - cleartext.encrypted = pair.encrypted; - - function onerror(e) { - if (cleartext._controlReleased) - cleartext.emit('error', e); - } - - function onclose() { - tcpSocket.removeListener('error', onerror); - tcpSocket.removeListener('close', onclose); - } - - tcpSocket.on('error', onerror); - tcpSocket.on('close', onclose); - - pair.on('secure', function() { - process.nextTick(function() { cleartext.socket.emit('secure'); }); - }); - - cleartext._controlReleased = true; - return cleartext; -}; - exports.isNotEmpty = function(str) { return str.trim().length > 0; };