Skip to content

Commit

Permalink
Migrate to node 0.4 APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
aredridel committed Jun 1, 2011
1 parent 87cd210 commit 9f12dbd
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 66 deletions.
142 changes: 78 additions & 64 deletions lib/smtp.js
@@ -1,13 +1,12 @@
/* License: See the COPYING file in this distribution.
*
* Copyright (c) 2010 Terry Riegel <riegel@clearimageonline.com>
* Copyright (c) 2010 Aria Stewart <aredridel@nbtsc.org>
* Copyright (c) 2011 Aria Stewart <aredridel@nbtsc.org>
*/

var net = require('net');
var events = require('events')
var sys = require('sys');
var linebuffer = require('linebuffer');
var util = require('util');

var left = function (str, n) {
if (n <= 0) {return "";}
Expand All @@ -20,7 +19,7 @@ function MessageStream() {
this.hasErred = false
this.started = false
}
sys.inherits(MessageStream, events.EventEmitter)
util.inherits(MessageStream, events.EventEmitter)

exports.MessageStream = MessageStream

Expand Down Expand Up @@ -50,19 +49,42 @@ MessageStream.prototype.start = function() {
var debug;
var debugLevel = parseInt(process.env.NODE_DEBUG, 16);
if (debugLevel & 0x4) {
debug = function (x) { sys.error('SMTP: ' + x); };
debug = function (x) { util.error('SMTP: ' + x); };
} else {
debug = function () { };
}

function lineBuffer(socket) {
var buffer = ''
var paused = false
socket.on('pause', function() {
paused = true
})
socket.on('resume', function() {
paused = false
unspool()
})
var unspool = function unspool() {
var i
while(!paused && (i = buffer.indexOf("\n")) != -1) {
socket.emit('line', buffer.slice(0, i))
buffer = buffer.slice(i + 1)
}
}
socket.on('data', function(data) {
buffer += data
unspool()
})
}

function Server(clientListener) {
net.Server.call(this);
this.allowPipelining = true
this.hostname = 'hostname.unconfigured'
this.addListener('connection', connectionListener);
if(clientListener) this.addListener('connection', clientListener);
this.on('connection', connectionListener);
if(clientListener) this.on('connection', clientListener);
}
sys.inherits(Server, net.Server);
util.inherits(Server, net.Server);

exports.Server = Server;

Expand All @@ -71,50 +93,48 @@ exports.createServer = function(clientListener) {
}

function connectionListener(socket) {
var In = new linebuffer.LineBuffer()
var Out = socket
var self = this

sys.pump(socket, In, function() {
In.end()
})
lineBuffer(socket)

debug("new smtp connection");

socket.setTimeout(2*60*1000); // 2 minute timeout
socket.addListener('timeout', function () {

socket.on('timeout', function () {
socket.destroy();
});

In.setEncoding('utf8');
Out.out = function(a){
socket.setEncoding('utf8');

socket.out = function(a){
try {
Out.write(a+'\r\n')
socket.write(a+'\r\n')
} catch(e) {
Out.emit('error', e)
socket.emit('error', e)
}
console.info('>'+a.replace("\n", ">\n"));
}

socket.on('connect', function () {
Out.out('220 ' + self.hostname + ' ESMTP node.js');
socket.out('220 ' + this.hostname + ' ESMTP node.js');
socket.state = 'welcome';
resetSMTPState(socket)
});
In.on('data', function (line) {
}.bind(this));

socket.on('line', function (line) {
if (socket.state == 'data') {
var message = socket.currentMessage
if(line.match(/^\./)) {
message.emit('end')
socket.state = 'welcome'
var f = function() { acceptOrReject(socket, message, In) }
if(message.smtpCode === undefined) {
In.pause()
var f = function() { acceptOrReject(socket, message) }
if(typeof(message.smtpCode) == 'undefined') {
message.pause()
console.log('waiting for accept or reject')
message.on('accept', f)
message.on('reject', f)
message.on('error', f)
} else {
f()
acceptOrReject(socket, message)
}
} else {
message.emit('data', line)
Expand All @@ -128,35 +148,35 @@ function connectionListener(socket) {
if(helodata.valid) {
socket.helo = helodata
if(helodata.extended) {
Out.out('250-' + self.hostname)
if(socket.maxSize) Out.out("250-SIZE " + socket.maxsize)
if(socket.allowPipelining) Out.out("250-PIPELINING")
if(socket.authMethods) Out.out("250-AUTH "+socket.authMethods.join(' '))
Out.out('250 HELP')
socket.out('250-' + this.hostname)
if(socket.maxSize) socket.out("250-SIZE " + socket.maxsize)
if(socket.allowPipelining) socket.out("250-PIPELINING")
if(socket.authMethods) socket.out("250-AUTH "+socket.authMethods.join(' '))
socket.out('250 HELP')
} else {
Out.out('250 ' + self.hostname)
socket.out('250 ' + this.hostname)
}
} else {
Out.out('550 Bad argument to HELO')
socket.out('550 Bad argument to HELO')
}
} else if(m = line.match(/^MAIL FROM:\s*(.*)\s*/i)) {
if(socket.sender) Out.out("503 We already got one, you see.")
if(socket.sender) socket.out("503 We already got one, you see.")
var sender = {address: m[1], valid: true}
socket.emit('MAIL FROM', sender)
if(sender.valid) {
socket.sender = sender
Out.out("250 MAIL FROM looks good enough for me.")
socket.out("250 MAIL FROM looks good enough for me.")
} else {
Out.out("550 Go Away, you silly English Knnnniiight")
socket.out("550 Go Away, you silly English Knnnniiight")
}
} else if(m = line.match(/^RCPT TO:\s*(.*)\s*/i)) {
var recip = {address: m[1], valid: true}
socket.emit('RCPT TO', recip)
if(recip.valid) {
socket.recipients.push(recip)
Out.out("250 RCPT TO ...I hope that's right. I didn't check.)")
socket.out("250 RCPT TO ...I hope that's right. I didn't check.)")
} else {
Out.out("550 We found a witch! May we burn her?")
socket.out("550 We found a witch! May we burn her?")
}
} else if(line.match(/^DATA\b/i)) {
socket.state = 'data';
Expand All @@ -166,60 +186,54 @@ function connectionListener(socket) {
message.recipients = socket.recipients
message.sender = socket.sender
message.connection = socket
In.pause()
message.on('pause', function() {
In.pause()
socket.pause()
})
message.on('resume', function() {
In.resume()
socket.resume()
})
message.on('error', function(e) {
message.error = e
if(!message.started) {
Out.out((e.smtpCode ? e.smtpCode : '451') + (e.smtpMessage ? ' ' + e.smtpMessage : ' Well, that could have gone better.'));
socket.state =
'welcome'
socket.out((e.smtpCode ? e.smtpCode : '451') + (e.smtpMessage ? ' ' + e.smtpMessage : ' Well, that could have gone better.'));
socket.state = 'welcome'
}
})
socket.emit('DATA', socket.currentMessage)
message.on('start', function() {
Out.out('354 Enter mail, end with "." on a line by itself');
In.resume()
})
socket.out('354 Enter mail, end with "." on a line by itself');
if(message.hasErred) {
acceptOrReject(socket, message, In)
acceptOrReject(socket, message)
socket.state = 'welcome'
}
} catch(e) {
Out.out('451 Internal Error')
socket.out('451 Internal Error')
socket.state = 'welcome'
}
} else if(line.match(/^NOOP\b/i)) {
Out.out('250 OK');
socket.out('250 OK');
} else if(line.match(/^QUIT\b/i)) {
socket.emit('QUIT')
Out.out('221 Go away, you silly English pig-dog types');
In.destroy()
socket.out('221 Go away, you silly English pig-dog types');
socket.destroy()
} else if(line.match(/^RSET\b/i)) {
socket.emit('RSET')
resetSMTPState(socket)
Out.out('250 Reset OK');
socket.out('250 Reset OK');
} else if(line.match(/^HELP\b/i)) {
Out.out('214-Commands supported\r\n214 HELO MAIL RCPT DATA\r\n214 NOOP QUIT RSET HELP');
socket.out('214-Commands supported\r\n214 HELO MAIL RCPT DATA\r\n214 NOOP QUIT RSET HELP');
} else if(line.match(/^EXPN\b/i)) {
socket.emit('EXPN')
Out.out('550 EXPN not available');
socket.out('550 EXPN not available');
} else if(line.match(/^(EHLO|SEND|SAML|SOML|TURN)\b/i)) {
Out.out('502 Unsupported here');
socket.out('502 Unsupported here');
} else if(line.match(/^VRFY\b/i)) {
Out.out('252 VRFY not available');
socket.out('252 VRFY not available');
} else {
Out.out('500 Unrecognized command');
socket.out('500 Unrecognized command');
}
}
});
In.on('end', function () {
}.bind(this));
socket.on('end', function () {
console.info(' Unexpected End, Terminating connection.');
socket.destroy();
});
Expand All @@ -232,7 +246,7 @@ function resetSMTPState(socket) {
socket.heloname = null
}

function acceptOrReject(socket, message, stream) {
function acceptOrReject(socket, message) {
if(message.smtpCode >= 200 && message.smtpCode < 300) {
console.info("Accept!")
socket.out(message.smtpCode + " " + message.smtpMessage)
Expand All @@ -243,5 +257,5 @@ function acceptOrReject(socket, message, stream) {
console.info("Error!")
socket.out("451 Something went wrong")
}
if(stream.paused) stream.resume()
socket.resume()
}
3 changes: 1 addition & 2 deletions package.json
@@ -1,7 +1,6 @@
{ "name" : "smtp"
, "version" : "0.0.5"
, "description" : "SMTP daemon (and eventually client) library"
, "engines" : [ "node" ]
, "dependencies" : ["linebuffer >= 0.0.4"]
, "engines" : {"node": "0.4.x || 0.5.x"}
, "directories" : { "lib" : "./lib", "bin": "./bin" }
}

0 comments on commit 9f12dbd

Please sign in to comment.