commit 9d4e8e68234e6726dde6cfe5590fd8fdf30d44f5
parent d04e5d386831a260bb2078a0e05cbf77037a29cc
Author: Tomas Hlavaty <tom@logand.com>
Date: Tue, 13 Sep 2011 23:24:10 +0200
remove tcp code, use stdin/out, invoke via tcpserver
Diffstat:
M | README | | | 3 | +++ |
M | dirpop3d.c | | | 133 | ++++++++++++++++++++++++++++++------------------------------------------------- |
2 files changed, 54 insertions(+), 82 deletions(-)
diff --git a/README b/README
@@ -1,3 +1,6 @@
+$ echo >~/.w3mail/in; tail -f ~/.w3mail/in | xargs -n1 -P20 w3mail 2>>~/.w3mail/log &
+$ tcpserver 127.0.0.1 3333 dirpop3d ~/.w3mail/inbox &
+
w3mail
======
diff --git a/dirpop3d.c b/dirpop3d.c
@@ -24,60 +24,9 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
#include "utils.h"
-#define QLEN 1
-
-typedef void tcp_handler(int fd);
-
-static void tcp_server(int port, tcp_handler handler) {
- int fds;
- if((fds = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- die(1, "socket() failed");
- int optval = 1;
- if(setsockopt(fds, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
- die(1, "setsockopt() failed");
- struct sockaddr_in sa;
- memset(&sa, 0, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = inet_addr("127.0.0.1"); //htonl(INADDR_ANY);
- sa.sin_port = htons(port);
- if(bind(fds, (struct sockaddr *) &sa, sizeof(sa)) < 0)
- die(1, "bind() failed");
- if(listen(fds, QLEN) < 0)
- die(1, "listen() failed");
- for(;;) {
- struct sockaddr_in ca;
- unsigned int n = sizeof(ca);
- int fdc;
- if((fdc = accept(fds, (struct sockaddr *) &ca, &n)) < 0)
- die(1, "accept() failed");
- handler(fdc);
- }
-}
-
-static int crlf(char *buf, int n) {
- if(BLEN < n + 3) die(1, "crlf(): buffer too small %d", n);
- buf[n] = '\r';
- buf[n + 1] = '\n';
- buf[n + 2] = 0;
- return n + 2;
-}
-
-static void pr(int fd, char *fmt, ...) {
- va_list v;
- va_start(v, fmt);
- char buf[BLEN];
- int n = vsnprintf(buf, BLEN, fmt, v);
- n = crlf(buf, n);
- if(send(fd, buf, sizeof(char) * n, 0) < 0)
- die(1, "pr(): send() failed");
- va_end(v);
-}
-
struct msg {
int deleted;
int nbytes;
@@ -141,15 +90,42 @@ static int list_cb(void *udata, char *path, char *fname, struct dirent *e, struc
return 1;
}
-static char *rootdir;
+static int line(int fd, char *buf, char *end) {
+ int n = 0;
+ while(buf < end) {
+ char c;
+ int m = read(fd, &c, sizeof(char));
+ if(m <= 0) break;
+ if(m != sizeof(char)) exit(-1);
+ *buf++ = c;
+ n++;
+ if('\n' == c) break;
+ }
+ return n;
+}
+
+static inline void crlf() {
+ printf("\r\n");
+ fflush(stdout);
+}
+
+static void pr(char *fmt, ...) {
+ va_list v;
+ va_start(v, fmt);
+ vprintf(fmt, v);
+ crlf();
+ va_end(v);
+}
-static void pop3_handler(int fd) {
- pr(fd, "+OK dirpop3d ready");
+int main(int argc, char *argv[]) {
+ if(argc != 2) quit(1, "Usage: %s rootdir", argv[0]);
+ char *rootdir = argv[1];
+ pr("+OK dirpop3d ready");
enum {START, USER, PASS, STAT, LIST} state = START;
char cmd[BLEN], usr[BLEN], pwd[BLEN];
struct flist *flist = NULL;
char buf[BLEN];
- for(int n; 0 < (n = recv(fd, buf, sizeof(char) * BLEN, 0));) {
+ for(int n; 0 < (n = line(0, buf, buf + BLEN));) {
rtrim(buf);
sscanf(buf, "%s", cmd);
if(0 == strcmp("QUIT", cmd)) {
@@ -161,27 +137,27 @@ static void pop3_handler(int fd) {
flist_free(flist);
flist = NULL;
}
- pr(fd, "+OK dirpop3d bye");
+ pr("+OK dirpop3d bye");
break;
}
else if(0 == strcmp("USER", cmd)) {
- if(state != START) pr(fd, "-ERR");
+ if(state != START) pr("-ERR");
else {
sscanf(buf, "%s %s", cmd, usr);
- pr(fd, "+OK hi %s", usr);
+ pr("+OK hi %s", usr);
state = USER;
}
}
else if(0 == strcmp("PASS", cmd)) {
- if(state != USER) pr(fd, "-ERR");
+ if(state != USER) pr("-ERR");
else {
sscanf(buf, "%s %s", cmd, pwd);
- pr(fd, "+OK welcome %s", usr);
+ pr("+OK welcome %s", usr);
state = PASS;
}
}
else if(0 == strcmp("STAT", cmd)) {
- if(state != PASS) pr(fd, "-ERR");
+ if(state != PASS) pr("-ERR");
else {
if(!flist) {
flist = flist_new(100);
@@ -189,28 +165,28 @@ static void pop3_handler(int fd) {
dir(&x, list_cb, "%s/%s", rootdir, usr);
flist = x.flist;
}
- pr(fd, "+OK %d %d", flist->n, flist->nbytes);
+ pr("+OK %d %d", flist->n, flist->nbytes);
state = STAT;
}
}
else if(0 == strcmp("LIST", cmd)) {
- if(state != STAT) pr(fd, "-ERR");
+ if(state != STAT) pr("-ERR");
else {
- pr(fd, "+OK %d messages (%d octets)", flist->n, flist->nbytes);
+ pr("+OK %d messages (%d octets)", flist->n, flist->nbytes);
for(int i = 0; i < flist->n; i++)
- pr(fd, "%d %d", i + 1, flist->msg[i].nbytes);
- pr(fd, ".");
+ pr("%d %d", i + 1, flist->msg[i].nbytes);
+ pr(".");
state = LIST;
}
}
else if(0 == strcmp("RETR", cmd)) {
- if(state != STAT) pr(fd, "-ERR");
+ if(state != STAT) pr("-ERR");
else {
int n = 0;
sscanf(buf, "%s %d", cmd, &n);
if(0 < n && n <= flist->n) {
struct msg *x = &flist->msg[n - 1];
- pr(fd, "+OK %d octets", x->nbytes);
+ pr("+OK %d octets", x->nbytes);
FILE *in = fopen(x->fname, "r");
if(!in) die(1, "echo(): cannot open input file '%s'", x->fname);
/* Note that the served files must have lines shorter than
@@ -219,34 +195,27 @@ static void pop3_handler(int fd) {
char buf[BLEN];
while(fgets(buf, BLEN, in)) {
rtrim(buf);
- pr(fd, "%s", buf);
+ pr("%s", buf);
}
fclose(in);
- pr(fd, ".");
+ pr(".");
}
- else pr(fd, "-ERR");
+ else pr("-ERR");
}
}
else if(0 == strcmp("DELE", cmd)) {
- if(state != STAT) pr(fd, "-ERR");
+ if(state != STAT) pr("-ERR");
else {
int n = 0;
sscanf(buf, "%s %d", cmd, &n);
if(0 < n && n <= flist->n) {
struct msg *x = &flist->msg[n - 1];
x->deleted = 1;
- pr(fd, "+OK message %d deleted", n);
+ pr("+OK message %d deleted", n);
}
- else pr(fd, "-ERR");
+ else pr("-ERR");
}
}
- else pr(fd, "-ERR wrong command");
+ else pr("-ERR wrong command");
}
- close(fd);
-}
-
-int main(int argc, char *argv[]) {
- if(argc != 3) quit(1, "Usage: %s port rootdir", argv[0]);
- rootdir = argv[2];
- tcp_server(atoi(argv[1]), pop3_handler);
}