@ -52,8 +52,9 @@ function Connection(config) {
this . _config = {
host : config . host || 'localhost' ,
port : config . port || 143 ,
secure : ( config . secure === true ? 'implicit' : config . secure ) ,
secureOptions : config . secureOptions ,
tls : config . tls ,
tlsOptions : config . tlsOptions ,
autotls : config . autotls ,
user : config . user ,
password : config . password ,
connTimeout : config . connTimeout || 10000 ,
@ -68,6 +69,8 @@ function Connection(config) {
this . _queue = [ ] ;
this . _box = undefined ;
this . _idle = { } ;
this . _parser = undefined ;
this . _curReq = undefined ;
this . delimiter = undefined ;
this . namespaces = undefined ;
this . state = 'disconnected' ;
@ -76,22 +79,22 @@ function Connection(config) {
inherits ( Connection , EventEmitter ) ;
Connection . prototype . connect = function ( ) {
var config = this . _config , self = this , socket , tlsSocket, parser, tlsOptions ;
var config = this . _config , self = this , socket , parser, tlsOptions ;
socket = new Socket ( ) ;
socket . setKeepAlive ( true ) ;
socket . setTimeout ( 0 ) ;
this . state = 'disconnected' ;
if ( config . secure ) {
if ( config . tl s) {
tlsOptions = { } ;
for ( var k in config . secure Options)
tlsOptions [ k ] = config . secure Options[ k ] ;
for ( var k in config . tl sOptions)
tlsOptions [ k ] = config . tl sOptions[ k ] ;
tlsOptions . socket = socket ;
}
if ( config . secure === 'implicit' )
this . _sock = tls Socket = tls . connect ( tlsOptions , onconnect ) ;
if ( config . tls )
this . _sock = tls . connect ( tlsOptions , onconnect ) ;
else {
socket . once ( 'connect' , onconnect ) ;
this . _sock = socket ;
@ -100,32 +103,33 @@ Connection.prototype.connect = function() {
function onconnect ( ) {
clearTimeout ( self . _tmrConn ) ;
self . state = 'connected' ;
self . debug && self . debug ( '[connection] Connected to host' ) ;
self . debug && self . debug ( '[connection] Connected to host' ) ;
}
this . _ sock. once ( 'error' , function ( err ) {
this . _ onError = function ( err ) {
clearTimeout ( self . _tmrConn ) ;
clearTimeout ( self . _tmrKeepalive ) ;
self . debug && self . debug ( '[connection] Error: ' + err ) ;
self . debug && self . debug ( '[connection] Error: ' + err ) ;
err . source = 'socket' ;
self . emit ( 'error' , err ) ;
} ) ;
} ;
this . _sock . once ( 'error' , this . _onError ) ;
socket . once ( 'close' , function ( had _err ) {
clearTimeout ( self . _tmrConn ) ;
clearTimeout ( self . _tmrKeepalive ) ;
self . debug && self . debug ( '[connection] Closed' ) ;
self . debug && self . debug ( '[connection] Closed' ) ;
self . emit ( 'close' , had _err ) ;
} ) ;
socket . once ( 'end' , function ( ) {
clearTimeout ( self . _tmrConn ) ;
clearTimeout ( self . _tmrKeepalive ) ;
self . debug && self . debug ( '[connection] Ended' ) ;
self . debug && self . debug ( '[connection] Ended' ) ;
self . emit ( 'end' ) ;
} ) ;
parser = new Parser ( this . _sock , this . debug ) ;
this . _parser = parser = new Parser ( this . _sock , this . debug ) ;
parser . on ( 'untagged' , function ( info ) {
self . _resUntagged ( info ) ;
@ -1189,6 +1193,12 @@ Connection.prototype._login = function() {
reentry ( ) ;
} ;
if ( self . serverSupports ( 'STARTTLS' )
&& ( self . _config . autotls === 'always'
|| ( self . _config . autotls === 'required'
&& self . serverSupports ( 'LOGINDISABLED' ) ) ) )
self . _starttls ( ) ;
if ( self . serverSupports ( 'LOGINDISABLED' ) ) {
err = new Error ( 'Logging in is disabled on this server' ) ;
err . source = 'authentication' ;
@ -1197,12 +1207,16 @@ Connection.prototype._login = function() {
if ( self . serverSupports ( 'AUTH=XOAUTH' ) && self . _config . xoauth ) {
self . _caps = undefined ;
self . _enqueue ( 'AUTHENTICATE XOAUTH ' + escape ( self . _config . xoauth ) ,
checkCaps ) ;
var cmd = 'AUTHENTICATE XOAUTH' ;
if ( self . serverSupports ( 'SASL-IR' ) )
cmd += ' ' + escape ( self . _config . xoauth ) ;
self . _enqueue ( cmd , checkCaps ) ;
} else if ( self . serverSupports ( 'AUTH=XOAUTH2' ) && self . _config . xoauth2 ) {
self . _caps = undefined ;
self . _enqueue ( 'AUTHENTICATE XOAUTH2 ' + escape ( self . _config . xoauth2 ) ,
checkCaps ) ;
var cmd = 'AUTHENTICATE XOAUTH2' ;
if ( self . serverSupports ( 'SASL-IR' ) )
cmd += ' ' + escape ( self . _config . xoauth2 ) ;
self . _enqueue ( cmd , checkCaps ) ;
} else if ( self . _config . user && self . _config . password ) {
self . _caps = undefined ;
self . _enqueue ( 'LOGIN "' + escape ( self . _config . user ) + '" "'
@ -1218,6 +1232,32 @@ Connection.prototype._login = function() {
} ) ;
} ;
Connection . prototype . _starttls = function ( ) {
var self = this ;
this . _enqueue ( 'STARTTLS' , function ( err ) {
if ( err ) {
self . emit ( 'error' , err ) ;
return self . _sock . end ( ) ;
}
self . _caps = undefined ;
self . _sock . removeAllListeners ( 'error' ) ;
var tlsOptions = { } ;
for ( var k in config . tlsOptions )
tlsOptions [ k ] = config . tlsOptions [ k ] ;
tlsOptions . socket = self . _sock ;
self . _sock = tls . connect ( tlsOptions , function ( ) {
self . _login ( ) ;
} ) ;
self . _sock . on ( 'error' , self . _onError ) ;
self . _parser . setStream ( self . _sock ) ;
} ) ;
} ;
Connection . prototype . _processQueue = function ( ) {
if ( this . _curReq || ! this . _queue . length || ! this . _sock . writable )
return ;
@ -1257,7 +1297,9 @@ Connection.prototype._enqueue = function(fullcmd, promote, cb) {
else
this . _queue . push ( info ) ;
if ( ! this . _curReq ) {
if ( ! this . _curReq
&& this . state !== 'disconnected'
&& this . state !== 'upgrading' ) {
// defer until next tick for requests like APPEND and FETCH where access to
// the request object is needed immediately after enqueueing
process . nextTick ( function ( ) { self . _processQueue ( ) ; } ) ;