w3mail

program to send a web page by email
git clone https://logand.com/git/w3mail.git/
Log | Files | Refs | README | LICENSE

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:
MREADME | 3+++
Mdirpop3d.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); }