w3mail

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

commit 83ce27955293d301293d7522a49e331928ff212a
parent 413c92ef704db1b00cc40427e41455c045690f2c
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sun, 16 Jan 2011 15:38:32 +0100

w3mail and dirpop3d fixes

Diffstat:
Mdirpop3d.c | 237+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mw3mail.c | 37+++++++++++++++++++++----------------
2 files changed, 139 insertions(+), 135 deletions(-)

diff --git a/dirpop3d.c b/dirpop3d.c @@ -1,18 +1,24 @@ -// ??? -// Copyright (C) 2010 Tomas Hlavaty -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +/* + + dirpop3d -- pop3 server for w3mail + + Copyright (C) 2011 Tomas Hlavaty + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. + +*/ #include <stdio.h> #include <stdlib.h> @@ -73,99 +79,76 @@ static void pr(int fd, char *fmt, ...) { va_end(v); } -struct xstat { - int nfiles; +struct msg { + int deleted; int nbytes; + char *fname; }; -static void stat_cb(void *udata, char *path, struct dirent *e, struct stat *s) { - struct xstat *x = udata; - if(!S_ISREG(s->st_mode)) return; - x->nfiles += 1; - x->nbytes += s->st_size; -} - -struct xlist { - int nfiles; - int fd; +struct flist { + int len; + int n; + int nbytes; + struct msg msg[]; }; -static void list_cb(void *udata, char *path, struct dirent *e, struct stat *s) { - struct xlist *x = udata; - if(!S_ISREG(s->st_mode)) return; - pr(x->fd, "%d %d", ++x->nfiles, s->st_size); +static int sizeof_flist(int len) { + return 3 * sizeof(int) + sizeof(struct msg) * len; } -struct xretr { - int n; - int nfiles; - int fd; -}; +static struct flist *flist_new(int len) { + struct flist *x = malloc(sizeof_flist(len)); + x->len = len; + x->n = 0; + x->nbytes = 0; + return x; +} -static void retr_cb(void *udata, char *path, struct dirent *e, struct stat *s) { - struct xretr *x = udata; - if(!S_ISREG(s->st_mode) || (x->n != ++x->nfiles)) return; - pr(x->fd, "+OK %d octets", s->st_size); - char fname[BLEN]; - snprintf(fname, BLEN, "%s/%s", path, e->d_name); - FILE *in = fopen(fname, "r"); - if(!in) die(1, "echo(): cannot open input file '%s'", fname); - // Note that the served files must have lines shorter than BLEN and - // no single dot char on its own line. Therefore use base64 for the - // message body. - char buf[BLEN]; - while(fgets(buf, BLEN, in)) { - rtrim(buf); - pr(x->fd, "%s", buf); +/* static void flist_free(struct flist *x) { */ +/* for(int i = 0; i < x->n; i++) */ +/* free(x->msg[i].fname); */ +/* free(x); */ +/* } */ + +static struct flist *flist_realloc(struct flist *x, int len) { + if(x->len < len) { + struct flist *y = realloc(x, sizeof_flist(len)); + y->len = len; + return y; } - fclose(in); - pr(x->fd, "."); + return x; } -static void dele_cb(void *udata, char *path, struct dirent *e, struct stat *s) { - struct xretr *x = udata; - if(!S_ISREG(s->st_mode) || (x->n != ++x->nfiles)) return; - - char fname[BLEN]; - snprintf(fname, BLEN, "%s/%s", path, e->d_name); - unlink(fname); - - pr(x->fd, "+OK message %d deleted", x->n); +static struct flist *flist_add(struct flist *x, char *fname, int nbytes) { + if(x->len <= x->n) + x = flist_realloc(x, x->len + 100); + x->nbytes += nbytes; + struct msg *y = &x->msg[x->n++]; + y->deleted = 0; + y->nbytes = nbytes; + y->fname = fname; + return x; } -struct fmsg { - int deleted; - int nbytes; - char *fname; -}; - -struct flist { - int n; - fmsg msg[]; +struct xlist { + struct flist *flist; }; -static struct flist *flist_new(int n) { - struct flist *x = malloc(sizeof(int) + (sizeof(int) + sizeof(char *)) * n); - x->n = n; - for(int i = 0; i < x->n; i++) { - x->msg[i].deleted = 0; - x->msg[i].fname = NULL; - } - return x; -} - -static void flist_free(struct flist *x) { - for(int i = 0; i < x->n; i++) { - free(x->msg[i].fname); - } - free(x); +static void list_cb(void *udata, char *path, struct dirent *e, struct stat *s) { + struct xlist *x = udata; + if(!S_ISREG(s->st_mode)) return; + char buf[BLEN]; + snprintf(buf, BLEN, "%s/%s", path, e->d_name); + char *fname = malloc(strlen(buf) + 1); + strcpy(fname, buf); + x->flist = flist_add(x->flist, fname, s->st_size); } static char *rootdir; static void pop3_handler(int fd) { pr(fd, "+OK dirpop3d ready"); - enum {START, USER, PASS, LIST} state = START; + enum {START, USER, PASS, STAT, LIST} state = START; char cmd[BLEN], usr[BLEN], pwd[BLEN]; struct flist *flist = NULL; char buf[BLEN]; @@ -173,6 +156,12 @@ static void pop3_handler(int fd) { rtrim(buf); sscanf(buf, "%s", cmd); if(0 == strcmp("QUIT", cmd)) { + if(flist) { + for(int i = 0; i < flist->n; i++) { + struct msg *x = &flist->msg[i]; + if(x->deleted) unlink(x->fname); + } + } pr(fd, "+OK dirpop3d bye"); break; } @@ -192,54 +181,64 @@ static void pop3_handler(int fd) { state = PASS; } } - /* else if(0 == strcmp("STAT", cmd)) { */ - /* if(state != PASS && state != LIST) pr(fd, "-ERR"); */ - /* else { */ - /* struct xstat x = {0, 0}; */ - /* char buf[BLEN]; */ - /* snprintf(buf, BLEN, "%s/%s", rootdir, usr); */ - /* dir(&x, stat_cb, buf); */ - /* pr(fd, "+OK %d %d", x.nfiles, x.nbytes); */ - /* state = LIST; */ - /* } */ - /* } */ - else if(0 == strcmp("LIST", cmd)) { - if(state != PASS && state != LIST) pr(fd, "-ERR"); + else if(0 == strcmp("STAT", cmd)) { + if(state != PASS) pr(fd, "-ERR"); else { char buf[BLEN]; snprintf(buf, BLEN, "%s/%s", rootdir, usr); - struct xstat x = {0, 0}; - dir(&x, stat_cb, buf); - pr(fd, "+OK %d messages (%d octets)", x.nfiles, x.nbytes); - flist = flist_new(x.nfiles); - struct xlist y = {0, fd}; - dir(&y, list_cb, buf); + if(!flist) { + flist = flist_new(100); + struct xlist x = {flist}; + dir(&x, list_cb, buf); + flist = x.flist; + } + pr(fd, "+OK %d %d", flist->n, flist->nbytes); + state = STAT; + } + } + else if(0 == strcmp("LIST", cmd)) { + if(state != STAT) pr(fd, "-ERR"); + else { + pr(fd, "+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, "."); state = LIST; } } else if(0 == strcmp("RETR", cmd)) { - if(state != LIST) pr(fd, "-ERR"); + if(state != STAT) pr(fd, "-ERR"); else { - struct xretr x = {0, 0, fd}; - sscanf(buf, "%s %d", cmd, &x.n); - if(0 < x.n) { + 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); + 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 + BLEN and no single dot char on its own line. Therefore + use base64 for the message body. */ char buf[BLEN]; - snprintf(buf, BLEN, "%s/%s", rootdir, usr); - dir(&x, retr_cb, buf); + while(fgets(buf, BLEN, in)) { + rtrim(buf); + pr(fd, "%s", buf); + } + fclose(in); + pr(fd, "."); } else pr(fd, "-ERR"); } } else if(0 == strcmp("DELE", cmd)) { - if(state != LIST) pr(fd, "-ERR"); + if(state != STAT) pr(fd, "-ERR"); else { - struct xretr x = {0, 0, fd}; - sscanf(buf, "%s %d", cmd, &x.n); - if(0 < x.n) { - char buf[BLEN]; - snprintf(buf, BLEN, "%s/%s", rootdir, usr); - dir(&x, dele_cb, buf); + 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); } else pr(fd, "-ERR"); } diff --git a/w3mail.c b/w3mail.c @@ -1,18 +1,24 @@ -// w3mail -- a program that sends a web page by email. -// Copyright (C) 2010 Tomas Hlavaty -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +/* + + w3mail -- program for sending web page by email + + Copyright (C) 2010 Tomas Hlavaty + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. + +*/ #include <string.h> #include <ctype.h> @@ -97,7 +103,6 @@ static void cb_sendmail(void *udata, FILE* out) { pr("User-Agent: w3mail"); pr("MIME-Version: 1.0"); pr("Content-Type: text/html"); // TODO detect and ; charset=utf-8 - pr("Content-Disposition: inline; filename=", x->fname); // TODO use better fname pr("Content-Transfer-Encoding: base64"); pr(""); char cmd[BLEN];