Created
April 8, 2013 19:17
-
-
Save jonathansadowski/5339631 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var net = require('net'); | |
var extend = require('node.extend'); | |
function Session(lime){ | |
this.lime = lime; | |
this.store = {}; | |
this.mode = 0; | |
// 0 - expecting helo/ehlo | |
// 1 - expecting mail | |
// 2 - expecting rcpt | |
// 3 - expecting data (or more rcpt) | |
// 4 - data (expecting .) | |
this.from = ''; | |
this.to = []; | |
this.body = ''; | |
this.c = null; | |
var t = this; | |
this.listen = function(){ | |
t.c.on('data', function(data){ | |
var line = data.toString().trim(); | |
var parts = line.split(' '); | |
var remainder = parts.slice(1).join(' '); | |
if(4 > t.mode) { | |
var command = parts[0].toLowerCase(); | |
if(t.commands[command]) | |
t.commands[command](remainder); | |
else | |
t.unknown(line); | |
} else { | |
t.body += data; | |
if(data.toString().match(/(^|\n)\.(\r?\n)?$/)){ | |
t.body = t.body.replace(/\r?\n\.\r?\n$/,''); | |
t.lime.trigger('data_post',function(response){ | |
if(2 === response){ | |
t.c.write('554 I didn\'t like your message, so it wasn\'t saved\r\n'); | |
} else { | |
t.mode = 1; | |
t.c.write('250 OK I haz all your data, now whatcha gonna do?\r\n'); | |
} | |
},t,[t.from,t.to,t.body]); | |
} | |
} | |
}); | |
} | |
this.commands = { | |
helo: function(remainder){ | |
t.lime.trigger('helo',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else { | |
t.mode = 1; | |
t.c.write('250 limebin.com Hello, you look nice today!\r\n'); | |
} | |
},t); | |
}, | |
ehlo: function(remainder){ | |
t.lime.trigger('helo',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else { | |
t.mode = 1; | |
t.c.write('250-limebin.com Hello, you look nice today!\r\n'); | |
t.c.write('250 size 10485760\r\n'); | |
} | |
},t); | |
}, | |
mail: function(remainder){ | |
var matches; | |
var from = ''; | |
if(!(matches=remainder.match(/^from:\s?<?(.*?)>?\s?$/i))){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('501 Check your syntax, bro!\r\n'); | |
},t); | |
return; | |
} | |
from = matches[1].trim(); | |
if(0==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 That\'s a little rude, you should say HELO first!\r\n'); | |
},t); | |
return; | |
} | |
t.lime.trigger('mail',function(response){ | |
if(2 === response){ | |
t.c.write('451 We do not accept mail from that address.\r\n'); | |
} else { | |
t.mode = 2; | |
t.to = []; | |
t.from = from; | |
t.c.write('250 OK Now why don\'t you tell me where to send it?\r\n'); | |
} | |
},t,from); | |
}, | |
rcpt: function(remainder){ | |
var matches; | |
var to = ''; | |
if(!(matches=remainder.match(/^to:\s?<?(.*?)>?\s?$/i))){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('501 Check your syntax, bro!\r\n'); | |
},t); | |
return; | |
} | |
to = matches[1].trim(); | |
if(0==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 That\'s a little rude, you should say HELO first!\r\n'); | |
},t); | |
return; | |
} else if(1==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 WHOA BUDDY, YOU ARE GETTING AHEAD OF YOURSELF, MAIL FIRST!\r\n'); | |
},t); | |
return; | |
} | |
t.lime.trigger('rcpt',function(response){ | |
if(2 === response){ | |
t.c.write('550 WHO DAT?\r\n'); | |
} else if(1 === response) { | |
t.mode = 3; | |
t.to.push(to); | |
t.c.write('250 OK Got it, now what?\r\n'); | |
} else { | |
t.c.write('550 WHO DAT?\r\n'); | |
} | |
},t,to); | |
}, | |
data: function(remainder){ | |
if(0==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 That\'s a little rude, you should say HELO first!\r\n'); | |
},t); | |
return; | |
} else if(1==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 WHOA BUDDY, YOU ARE GETTING AHEAD OF YOURSELF, MAIL FIRST!\r\n'); | |
},t); | |
return; | |
} else if(2==t.mode){ | |
t.lime.trigger('invalid',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else | |
t.c.write('503 Now who do you expect me to deliver this to? RCPT FIRST!\r\n'); | |
},t); | |
return; | |
} | |
t.lime.trigger('data',function(response){ | |
if(2 === response){ | |
t.c.end(); | |
} else { | |
t.mode = 4; | |
t.c.write('354 Go ahead, give me your tired, your poor, your huddled data yearning to breathe free.\r\n'); | |
} | |
},t); | |
}, | |
quit: function(remainder){ | |
t.lime.trigger('helo',function(response){ | |
if(2 === response) | |
t.c.end(); | |
else { | |
t.c.write('221 Leaving me already? I\'ll miss you, visit again soon!\r\n'); | |
t.c.end(); | |
} | |
},t); | |
} | |
} | |
this.unknown = function(line){ | |
t.lime.trigger('unknown',function(response){ | |
if(2 === response) | |
t.c.end() | |
else | |
t.c.write('502 SAY WHAT?\r\n'); | |
},t); | |
} | |
} | |
Session.prototype.start = function(c){ | |
var t = this; | |
this.c=c; | |
this.lime.trigger('connect',function(response){ | |
if(2 === response) | |
c.end(); | |
else { | |
c.write('220 limebin.com ESMTP Welcome to the best mail server EVAR!!!1!!one!!eleven!!!11!\r\n'); | |
t.listen(); | |
} | |
},t); | |
} | |
function Lime(){ | |
this.callbacks = { | |
'connect':[], | |
'helo':[], | |
'mail':[], | |
'rcpt':[], | |
'data':[], | |
'data_post':[], | |
'quit':[], | |
'unknown':[], | |
'invalid':[] | |
}; | |
} | |
Lime.prototype.start = function(){ | |
var lime = this; | |
var server = net.createServer(function(c) { | |
var s = new Session(lime); | |
s.start(c); | |
}); | |
server.listen(25); | |
} | |
Lime.prototype.on = function(event, callback){ | |
if(this.callbacks[event]) | |
this.callbacks[event].push(callback); | |
} | |
Lime.prototype.trigger = function(event, callback, con, data, callbacks){ | |
if(!this.callbacks[event] || !this.callbacks[event].length){ | |
return callback(0); | |
} | |
if(!callbacks){ | |
callbacks = extend([],this.callbacks[event]); | |
} else if(!callbacks.length) { | |
return callback(0); | |
} | |
var cb = callbacks.shift(); | |
var t = this; | |
var timeoutTimer = setTimeout(function(){ | |
callbacks = []; | |
callback(2); | |
},5000); | |
var next = function(resp, message){ | |
timeoutFunction = function(){} | |
clearTimeout(timeoutTimer); | |
if(resp && (1===resp || 2===resp)) | |
return callback(resp, message); | |
t.trigger(event,callback,con,data,callbacks); | |
} | |
if(cb) | |
cb(next,con,data); | |
} | |
exports.CONT = 0; | |
exports.OK = 1; | |
exports.DENY = 2; | |
exports.server = Lime; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment