commit 83ce27955293d301293d7522a49e331928ff212a
parent 413c92ef704db1b00cc40427e41455c045690f2c
Author: Tomas Hlavaty <tom@logand.com>
Date: Sun, 16 Jan 2011 15:38:32 +0100
w3mail and dirpop3d fixes
Diffstat:
M | dirpop3d.c | | | 237 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | w3mail.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];