ref: 6092354e9384faab64454e7f6b1c9ead84676f90
dir: /mesg.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <thread.h> #include <regexp.h> #include "mail.h" #define Datefmt "?WWW, ?MMM ?DD hh:mm:ss ?Z YYYY" typedef struct Fn Fn; struct Fn { char *name; void (*fn)(Mesg *, char **, int); }; void mesgclear(Mesg *m) { free(m->name); free(m->from); free(m->to); free(m->cc); free(m->replyto); free(m->date); free(m->subject); free(m->type); free(m->disposition); free(m->messageid); free(m->filename); free(m->digest); free(m->mflags); free(m->fromcolon); } void mesgfree(Mesg *m) { if(m == nil) return; mesgclear(m); free(m); } static char* line(char *data, char **pp, int z) { char *p, *q; for(p=data; *p!='\0' && *p!='\n'; p++) ; if(*p == '\n') *pp = p+1; else *pp = p; if(z && p == data) return nil; q = emalloc(p-data + 1); memmove(q, data, p-data); return q; } static char* fc(Mesg *m, char *s) { char *r; if(s != nil && m->from != nil){ r = smprint("%s <%s>", s, m->from); free(s); return r; } if(m->from != nil) return estrdup(m->from); if(s != nil) return s; return estrdup("??"); } Mesg* mesgload(char *name) { char *info, *p; int ninfo; Mesg *m; Tm tm; m = emalloc(sizeof(Mesg)); m->name = estrjoin(name, "/", nil); if((info = rslurp(m, "info", &ninfo)) == nil) return nil; p = info; m->from = line(p, &p, 0); m->to = line(p, &p, 0); m->cc = line(p, &p, 0); m->replyto = line(p, &p, 1); m->date = line(p, &p, 0); m->subject = line(p, &p, 0); m->type = line(p, &p, 1); m->disposition = line(p, &p, 1); m->filename = line(p, &p, 1); m->digest = line(p, &p, 1); /* m->bcc = */ free(line(p, &p, 1)); m->inreplyto = line(p, &p, 1); /* m->date = */ free(line(p, &p, 1)); /* m->sender = */ free(line(p, &p, 1)); m->messageid = line(p, &p, 0); /* m->lines = */ free(line(p, &p, 1)); /* m->size = */ free(line(p, &p, 1)); m->mflags = line(p, &p, 0); /* m->fileid = */ free(line(p, &p, 1)); m->fromcolon = fc(m, line(p, &p, 0)); free(info); m->flags = Funseen; if(strchr(m->mflags, 'd')) m->flags |= Fdel; if(strchr(m->mflags, 's')) m->flags &= ~Funseen; if(strchr(m->mflags, 'a')) m->flags |= Fresp; m->time = time(nil); if(tmparse(&tm, Datefmt, m->date, nil, nil) != nil) m->time = tmnorm(&tm); m->hash = 0; if(m->messageid != nil) m->hash = strhash(m->messageid); return m; } static int mesgshow(Mesg *m) { int rfd, wfd; char *buf, *path; int n; buf = emalloc(Bufsz); path = estrjoin(mbox.path, m->name, "body", nil); if((wfd = winopen(m, "body", OWRITE)) == -1) return -1; if((rfd = open(path, OREAD)) == -1) return -1; fprint(wfd, "From: %s\n", m->from); fprint(wfd, "Date: %s\n", m->to); fprint(wfd, "Subject: %s\n\n", m->subject); while(1){ n = read(rfd, buf, Bufsz); if(n <= 0) break; if(write(wfd, buf, n) != n) break; } close(rfd); close(wfd); free(buf); free(path); return n; } static void reply(Mesg *m, char **f, int nf) { if(nf >= 2 || nf >= 1 && strcmp(f[0], "All") != 0){ fprint(2, "Q: invaid args\n"); return; } /* FIXME: get all recievers of the message */ compose1(m->from, m, 0); } static void qreply(Mesg *m, char **f, int nf) { if(nf >= 3 || nf >= 2 && strcmp(f[1], "All") != 0 || nf >= 1 && strcmp(f[0], "Reply") != 0 || nf == 0){ fprint(2, "Q: invaid args\n"); return; } /* FIXME: get all recievers of the message */ compose1(m->from, m, 1); } static void delmesg(Mesg *m, char **, int nf) { if(nf != 0){ fprint(2, "Delmesg: too many args\n"); return; } m->flags |= Ftodel; m->quitting = 1; mbredraw(m, 0, 0); } static void mesgquit(Mesg *m, char **, int) { m->quitting = 1; } static Fn mesgfn[] = { {"Q", qreply}, {"Reply", reply}, {"Delmesg", delmesg}, {"Save", nil}, {"Del", mesgquit}, {nil} }; static void mesgmain(void *mp) { char *a, *path, *f[32]; Event ev; Mesg *m; Fn *p; int nf; m = mp; m->quitting = 0; path = estrjoin(mbox.path, m->name, nil); wininit(m, path); free(path); wintagwrite(m, "Q Reply all Delmesg Save "); mesgshow(m); fprint(m->ctl, "clean\n"); mbox.nopen++; while(!m->quitting){ if(winevent(m, &ev) != 'M') continue; if(strcmp(ev.text, "Del") == 0) break; switch(ev.type){ case 'l': case 'L': if((a = matchaddr(m, &ev)) != nil) compose1(a, nil, 0); else if(matchmesg(m, ev.text)) mesgopen(ev.text, nil); else winsendevent(m, &ev); free(a); break; case 'x': case 'X': if((nf = tokenize(ev.text, f, nelem(f))) == 0) continue; for(p = mesgfn; p->name != nil; p++){ if(strcmp(p->name, f[0]) == 0 && p->fn != nil){ p->fn(m, &f[1], nf - 1); break; } } if(p->fn == nil) winsendevent(m, &ev); break; } } mbox.nopen--; m->flags &= ~Fopen; winclose(m); threadexits(nil); } void mesgpath2name(char *buf, int nbuf, char *name) { char *e; int n; n = strlen(mbox.path); if(strncmp(name, mbox.path, n) == 0){ e = strecpy(buf, buf + nbuf - 2, name + n); e[0] = '/'; e[1] = 0; }else strecpy(buf, buf+nbuf, name); } int mesgmatch(Mesg *m, char *name, char *digest) { if(m->flags & Fdummy) return 0; if(strcmp(m->name, name) == 0) return digest == nil || strcmp(m->digest, digest) == 0; return 0; } Mesg* mesglookup(char *name, char *digest) { char buf[32]; int i; mesgpath2name(buf, sizeof(buf), name); for(i = 0; i < mbox.nmesg; i++) if(mesgmatch(mbox.mesg[i], buf, digest)) return mbox.mesg[i]; return nil; } void mesgopen(char *name, char *digest) { Mesg *m; char *path; int fd; m = mesglookup(name, digest); if(m == nil || (m->flags & Fopen)) return; assert(!(m->flags & Fdummy)); m->flags |= Fopen; if(m->flags & Funseen){ m->flags &= ~Funseen; path = estrjoin(mbox.path, "/", m->name, "/flags", nil); if((fd = open(path, OWRITE)) != -1){ fprint(fd, "+s"); close(fd); } mbredraw(m, 0, 0); free(path); } threadcreate(mesgmain, m, Stack); }