Skip to content

Commit

Permalink
Added RETR support
Browse files Browse the repository at this point in the history
  • Loading branch information
ditesh committed Jul 7, 2011
1 parent f360fa0 commit 0ab97bd
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 63 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
POP3 server written in Node.js.
node-pop3d is a POP3 server written in Node.js. It is aiming to be RFC 1939 compliant and has the following set of features:

* PAM authentication
* mbox and spool directory support
* simple configuration (via a JSON file)
* extensive logging (file, syslog, stdout)

Doesn't conform to any RFC. Very much a work in progress, at the moment.
45 changes: 25 additions & 20 deletions mailbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ this.unlock= function(cb) {
this.mailbox = function(fd, cb) {

// Not the best data structure, but its good enough
var msgoffset = [];
var msgsizes = [];
var totalmsgsize = 0;
var messages = {
offsets: [],
sizes: [],
count: 0,
size: 0
}

function readmbox(position, previousbuf, cb) {

Expand Down Expand Up @@ -99,7 +102,7 @@ this.mailbox = function(fd, cb) {

// \nFrom is split between the buffers
} else if (buffer.slice(i+1, i+6).toString() === "From ")
msgoffset.push(position+i+1)
messages.offsets.push(position+i+1)

}

Expand All @@ -116,18 +119,19 @@ this.mailbox = function(fd, cb) {

i = 0;

while (i < msgoffset.length - 1) {
while (i < messages.offsets.length - 1) {

msgsize = msgoffset[i+1] - msgoffset[i];
totalmsgsize += msgsize;
msgsizes.push(msgsize);
msgsize = messages.offsets[i+1] - messages.offsets[i];
messages.size += msgsize;
messages.sizes.push(msgsize);
i++;

}

msgsize = position + bytesRead - msgoffset[i];
totalmsgsize += msgsize;
msgsizes[msgoffset[i]] = msgsize;
msgsize = position + bytesRead - messages.offsets[i];
messages.size += msgsize;
messages.sizes[messages.offsets[i]] = msgsize;
messages.count = messages.offsets.length;
cb(null);

}
Expand All @@ -136,16 +140,16 @@ this.mailbox = function(fd, cb) {
}

this.list = function(cb) {
cb(msgsizes);
cb(messages.sizes);
}

this.stat = function(cb) {
cb(msgoffset.length, totalmsgsize);
cb(messages.count, messages.size);
}

this.dele = function(msgnumber, cb) {

if (msgnumber > msgoffset.length) {
if (msgnumber > messages.count) {

cb(true);

Expand All @@ -158,26 +162,27 @@ this.mailbox = function(fd, cb) {
}
}

this.retr = function(msgnumber) {
this.retr = function(msgnumber, cb) {

if (msgnumber > msgoffset.length) {
if (msgnumber > messages.count) {

cb({errno: 5});

} else {

var buffer = new Buffer(msgsizes[msgoffset[msgnumber]]);
var bufsize = messages.sizes[messages.offsets[msgnumber-1]];
var buffer = new Buffer(bufsize);

fs.read(fd, buffer, 0, msgsizes[msgoffset[msgnumber]], msgoffset[msgnumber], function(err, bytesRead, buffer) {
fs.read(fd, buffer, 0, bufsize, messages.offsets[msgnumber-1], function(err, bytesRead, buffer) {
cb(err, buffer.toString());
});
}
}

this.close=function() {
this.close=function(cb) {

// This should automagically release the lock
fs.close(fd);
fs.close(fd, cb);

}

Expand Down
24 changes: 15 additions & 9 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ path.exists(argv.config, function(result) {
// Session is active
if (activesessions[username] !== undefined) {

// Should we close the socket here?
logger.error("Login rejected as session still active for user " + username);
support.sorry(socket);

Expand Down Expand Up @@ -115,7 +116,7 @@ path.exists(argv.config, function(result) {
username = "";
password = "";
support.sorry(socket);
delete activesession[username];
delete activesessions[username];

if (err.errno === 1) {

Expand Down Expand Up @@ -167,12 +168,15 @@ path.exists(argv.config, function(result) {

if (err) {

logger.error("Invalid message number " + msgnumber + " in RETR for user " + username);
support.sorry(socket);

} else {

support.ok(socket);
console.log(data);
logger.log("Successfully retrieved message number " + msgnumber + " for user " + username);
support.write(socket, data);
support.write(socket, ".");

}
});
Expand All @@ -189,12 +193,12 @@ path.exists(argv.config, function(result) {

for (var i in msgsizes) {

support.write(count + " " + msgsizes[i]);
support.write(socket, count + " " + msgsizes[i]);
count++;

}

support.write(".");
support.write(socket, ".");

});

Expand Down Expand Up @@ -242,14 +246,16 @@ path.exists(argv.config, function(result) {

socket.addListener("end", function () {

if (typeof mbox === "object")
mbox.close();
if (typeof mbox === "object") {

if (activesessions[username] !== undefined)
delete activesessions[username];
mbox.close(function() {
logger.log("Closed file descriptor for user " + username);
});
}

socket.end();
delete activesessions[username];
logger.log("Closing connection from " + socket.remoteAddress);
socket.end();

});

Expand Down
72 changes: 40 additions & 32 deletions tests/basic.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,72 @@
var net = require("net");

var argv = require('optimist')
.usage("Usage: $0 --port [port] --username username --password password --commands command1 command2")
.usage("Usage: $0 --port [port] --username username --password password")
.demand(['port', 'username', 'password'])
.argv;

state = "username";
var state = "username";
var multiline = false;

socket = net.Socket()
socket.addListener('error', function(data) {
console.log(data);
});

socket.addListener('data', function(data) {

console.log("GOT data: " + data);
console.log("GOT data: '" + data + "'");

if (data.substring(data.length-3, 3) === "\n\r\n")
console.log("wooo");
if (multiline && data.slice(data.length-5).toString() === "\r\n.\r\n") {
multiline = false;
}

if (state === "username") {
if (!multiline) {

console.log("USER " + argv.username);
socket.write('USER ' + argv.username + '\r\n');
state = "password";
if (state === "username") {

} else if (state === "password") {
console.log("USER " + argv.username);
socket.write('USER ' + argv.username + '\r\n');
state = "password";

console.log("PASS " + argv.password);
socket.write('PASS ' + argv.password + '\r\n');
state = "stat";
} else if (state === "password") {

} else if (state === "stat") {
console.log("PASS " + argv.password);
socket.write('PASS ' + argv.password + '\r\n');
state = "noop";

console.log("STAT");
socket.write("STAT\r\n");
state = "list";
} else if (state === "noop") {

} else if (state === "list") {
console.log("NOOP");
socket.write("NOOP\r\n");
state = "stat";

console.log("LIST");
socket.write("LIST\r\n");
state = "noop";
} else if (state === "stat") {

} else if (state === "noop") {
console.log("STAT");
socket.write("STAT\r\n");
state = "list";

console.log("NOOP");
socket.write("NOOP\r\n");
state = "retr";
} else if (state === "list") {

} else if (state === "retr") {
console.log("LIST");
socket.write("LIST\r\n");
state="retr";
multiline = true;

console.log("RETR 1");
socket.write("RETR 1\r\n");
state = "dele";
} else if (state === "retr") {

console.log("RETR 1");
socket.write("RETR 1\r\n");
state = "dele";
multiline = true;
}
}


console.log(err);

});

socket.connect(argv.port);

function send(msg) {
socket.write(msg);
}

0 comments on commit 0ab97bd

Please sign in to comment.