17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <ctype.h>
67dd7cddfSDavid du Colombier #include <plumb.h>
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier enum
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier DIRCHUNK = 32*sizeof(Dir)
127dd7cddfSDavid du Colombier };
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier char regexchars[] = "\\/[].+?()*^$";
157dd7cddfSDavid du Colombier char deleted[] = "(deleted)-";
167dd7cddfSDavid du Colombier char deletedrx[] = "\\(deleted\\)-";
177dd7cddfSDavid du Colombier char deletedrx01[] = "(\\(deleted\\)-)?";
187dd7cddfSDavid du Colombier char deletedaddr[] = "-#0;/^\\(deleted\\)-/";
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier struct{
217dd7cddfSDavid du Colombier char *type;
227dd7cddfSDavid du Colombier char *port;
237dd7cddfSDavid du Colombier char *suffix;
247dd7cddfSDavid du Colombier } ports[] = {
2514cc0f53SDavid du Colombier "text/", "edit", ".txt",
2614cc0f53SDavid du Colombier /* text must be first for plumbport() */
279a747e4fSDavid du Colombier "image/gif", "image", ".gif",
289a747e4fSDavid du Colombier "image/jpeg", "image", ".jpg",
299a747e4fSDavid du Colombier "image/jpeg", "image", ".jpeg",
30dc72095aSDavid du Colombier "image/png", "image", ".png",
3114cc0f53SDavid du Colombier "image/tiff", "image", ".tif",
329a747e4fSDavid du Colombier "application/postscript", "postscript", ".ps",
339a747e4fSDavid du Colombier "application/pdf", "postscript", ".pdf",
349a747e4fSDavid du Colombier "application/msword", "msword", ".doc",
359a747e4fSDavid du Colombier "application/rtf", "msword", ".rtf",
3614cc0f53SDavid du Colombier "audio/x-wav", "wav", ".wav",
377dd7cddfSDavid du Colombier nil, nil
387dd7cddfSDavid du Colombier };
397dd7cddfSDavid du Colombier
407dd7cddfSDavid du Colombier char *goodtypes[] = {
417dd7cddfSDavid du Colombier "text",
427dd7cddfSDavid du Colombier "text/plain",
437dd7cddfSDavid du Colombier "message/rfc822",
447dd7cddfSDavid du Colombier "text/richtext",
457dd7cddfSDavid du Colombier "text/tab-separated-values",
46*8ccc32efSDavid du Colombier "text/calendar",
477dd7cddfSDavid du Colombier "application/octet-stream",
487dd7cddfSDavid du Colombier nil,
497dd7cddfSDavid du Colombier };
507dd7cddfSDavid du Colombier
517dd7cddfSDavid du Colombier struct{
527dd7cddfSDavid du Colombier char *type;
537dd7cddfSDavid du Colombier char *ext;
547dd7cddfSDavid du Colombier } exts[] = {
557dd7cddfSDavid du Colombier "image/gif", ".gif",
567dd7cddfSDavid du Colombier "image/jpeg", ".jpg",
577dd7cddfSDavid du Colombier nil, nil
587dd7cddfSDavid du Colombier };
597dd7cddfSDavid du Colombier
609a747e4fSDavid du Colombier char *okheaders[] =
619a747e4fSDavid du Colombier {
629a747e4fSDavid du Colombier "From:",
639a747e4fSDavid du Colombier "Date:",
649a747e4fSDavid du Colombier "To:",
659a747e4fSDavid du Colombier "CC:",
669a747e4fSDavid du Colombier "Subject:",
679a747e4fSDavid du Colombier nil
689a747e4fSDavid du Colombier };
699a747e4fSDavid du Colombier
70c27b0bc9SDavid du Colombier char *extraheaders[] =
71c27b0bc9SDavid du Colombier {
72c4845253SDavid du Colombier "Resent-From:",
73c4845253SDavid du Colombier "Resent-To:",
74c4845253SDavid du Colombier "Sort:",
75c27b0bc9SDavid du Colombier nil,
76c27b0bc9SDavid du Colombier };
77c27b0bc9SDavid du Colombier
787dd7cddfSDavid du Colombier char*
line(char * data,char ** pp)797dd7cddfSDavid du Colombier line(char *data, char **pp)
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier char *p, *q;
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier for(p=data; *p!='\0' && *p!='\n'; p++)
847dd7cddfSDavid du Colombier ;
857dd7cddfSDavid du Colombier if(*p == '\n')
867dd7cddfSDavid du Colombier *pp = p+1;
877dd7cddfSDavid du Colombier else
887dd7cddfSDavid du Colombier *pp = p;
897dd7cddfSDavid du Colombier q = emalloc(p-data + 1);
907dd7cddfSDavid du Colombier memmove(q, data, p-data);
917dd7cddfSDavid du Colombier return q;
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier void
scanheaders(Message * m,char * dir)957dd7cddfSDavid du Colombier scanheaders(Message *m, char *dir)
967dd7cddfSDavid du Colombier {
979a747e4fSDavid du Colombier char *s, *t, *u, *f;
987dd7cddfSDavid du Colombier
999a747e4fSDavid du Colombier s = f = readfile(dir, "header", nil);
1007dd7cddfSDavid du Colombier if(s != nil)
1017dd7cddfSDavid du Colombier while(*s){
1027dd7cddfSDavid du Colombier t = line(s, &s);
1037dd7cddfSDavid du Colombier if(strncmp(t, "From: ", 6) == 0){
1047dd7cddfSDavid du Colombier m->fromcolon = estrdup(t+6);
1057dd7cddfSDavid du Colombier /* remove all quotes; they're ugly and irregular */
1067dd7cddfSDavid du Colombier for(u=m->fromcolon; *u; u++)
1077dd7cddfSDavid du Colombier if(*u == '"')
1087dd7cddfSDavid du Colombier memmove(u, u+1, strlen(u));
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier if(strncmp(t, "Subject: ", 9) == 0)
1117dd7cddfSDavid du Colombier m->subject = estrdup(t+9);
1127dd7cddfSDavid du Colombier free(t);
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier if(m->fromcolon == nil)
1157dd7cddfSDavid du Colombier m->fromcolon = estrdup(m->from);
1169a747e4fSDavid du Colombier free(f);
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier int
loadinfo(Message * m,char * dir)1207dd7cddfSDavid du Colombier loadinfo(Message *m, char *dir)
1217dd7cddfSDavid du Colombier {
1227dd7cddfSDavid du Colombier int n;
1237dd7cddfSDavid du Colombier char *data, *p, *s;
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier data = readfile(dir, "info", &n);
1267dd7cddfSDavid du Colombier if(data == nil)
1277dd7cddfSDavid du Colombier return 0;
1287dd7cddfSDavid du Colombier m->from = line(data, &p);
1297dd7cddfSDavid du Colombier scanheaders(m, dir); /* depends on m->from being set */
1307dd7cddfSDavid du Colombier m->to = line(p, &p);
1317dd7cddfSDavid du Colombier m->cc = line(p, &p);
1327dd7cddfSDavid du Colombier m->replyto = line(p, &p);
1337dd7cddfSDavid du Colombier m->date = line(p, &p);
1347dd7cddfSDavid du Colombier s = line(p, &p);
1357dd7cddfSDavid du Colombier if(m->subject == nil)
1367dd7cddfSDavid du Colombier m->subject = s;
1377dd7cddfSDavid du Colombier else
1387dd7cddfSDavid du Colombier free(s);
1397dd7cddfSDavid du Colombier m->type = line(p, &p);
1407dd7cddfSDavid du Colombier m->disposition = line(p, &p);
1417dd7cddfSDavid du Colombier m->filename = line(p, &p);
1427dd7cddfSDavid du Colombier m->digest = line(p, &p);
1437dd7cddfSDavid du Colombier free(data);
1447dd7cddfSDavid du Colombier return 1;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier int
isnumeric(char * s)1487dd7cddfSDavid du Colombier isnumeric(char *s)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier while(*s){
1517dd7cddfSDavid du Colombier if(!isdigit(*s))
1527dd7cddfSDavid du Colombier return 0;
1537dd7cddfSDavid du Colombier s++;
1547dd7cddfSDavid du Colombier }
1557dd7cddfSDavid du Colombier return 1;
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier Dir*
loaddir(char * name,int * np)1599a747e4fSDavid du Colombier loaddir(char *name, int *np)
1607dd7cddfSDavid du Colombier {
1619a747e4fSDavid du Colombier int fd;
1627dd7cddfSDavid du Colombier Dir *dp;
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier fd = open(name, OREAD);
1657dd7cddfSDavid du Colombier if(fd < 0)
1669a747e4fSDavid du Colombier return nil;
1679a747e4fSDavid du Colombier *np = dirreadall(fd, &dp);
1687dd7cddfSDavid du Colombier close(fd);
1697dd7cddfSDavid du Colombier return dp;
1707dd7cddfSDavid du Colombier }
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier void
readmbox(Message * mbox,char * dir,char * subdir)1737dd7cddfSDavid du Colombier readmbox(Message *mbox, char *dir, char *subdir)
1747dd7cddfSDavid du Colombier {
1757dd7cddfSDavid du Colombier char *name;
1767dd7cddfSDavid du Colombier Dir *d, *dirp;
1779a747e4fSDavid du Colombier int i, n;
1787dd7cddfSDavid du Colombier
1797dd7cddfSDavid du Colombier name = estrstrdup(dir, subdir);
1809a747e4fSDavid du Colombier dirp = loaddir(name, &n);
1819a747e4fSDavid du Colombier mbox->recursed = 1;
1829a747e4fSDavid du Colombier if(dirp)
1839a747e4fSDavid du Colombier for(i=0; i<n; i++){
1849a747e4fSDavid du Colombier d = &dirp[i];
1857dd7cddfSDavid du Colombier if(isnumeric(d->name))
1867dd7cddfSDavid du Colombier mesgadd(mbox, name, d, nil);
1879a747e4fSDavid du Colombier }
1887dd7cddfSDavid du Colombier free(dirp);
1897dd7cddfSDavid du Colombier free(name);
1907dd7cddfSDavid du Colombier }
1917dd7cddfSDavid du Colombier
1927dd7cddfSDavid du Colombier /* add message to box, in increasing numerical order */
1937dd7cddfSDavid du Colombier int
mesgadd(Message * mbox,char * dir,Dir * d,char * digest)1947dd7cddfSDavid du Colombier mesgadd(Message *mbox, char *dir, Dir *d, char *digest)
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier Message *m;
1977dd7cddfSDavid du Colombier char *name;
1987dd7cddfSDavid du Colombier int loaded;
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier m = emalloc(sizeof(Message));
2017dd7cddfSDavid du Colombier m->name = estrstrdup(d->name, "/");
2027dd7cddfSDavid du Colombier m->next = nil;
2037dd7cddfSDavid du Colombier m->prev = mbox->tail;
2049a747e4fSDavid du Colombier m->level= mbox->level+1;
2059a747e4fSDavid du Colombier m->recursed = 0;
2067dd7cddfSDavid du Colombier name = estrstrdup(dir, m->name);
2077dd7cddfSDavid du Colombier loaded = loadinfo(m, name);
2087dd7cddfSDavid du Colombier free(name);
2097dd7cddfSDavid du Colombier /* if two upas/fs are running, we can get misled, so check digest before accepting message */
2107dd7cddfSDavid du Colombier if(loaded==0 || (digest!=nil && m->digest!=nil && strcmp(digest, m->digest)!=0)){
2117dd7cddfSDavid du Colombier mesgfreeparts(m);
2127dd7cddfSDavid du Colombier free(m);
2137dd7cddfSDavid du Colombier return 0;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier if(mbox->tail != nil)
2167dd7cddfSDavid du Colombier mbox->tail->next = m;
2177dd7cddfSDavid du Colombier mbox->tail = m;
2187dd7cddfSDavid du Colombier if(mbox->head == nil)
2197dd7cddfSDavid du Colombier mbox->head = m;
2209a747e4fSDavid du Colombier
2219a747e4fSDavid du Colombier if (m->level != 1){
2229a747e4fSDavid du Colombier m->recursed = 1;
2237dd7cddfSDavid du Colombier readmbox(m, dir, m->name);
2249a747e4fSDavid du Colombier }
2257dd7cddfSDavid du Colombier return 1;
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier int
thisyear(char * year)2297dd7cddfSDavid du Colombier thisyear(char *year)
2307dd7cddfSDavid du Colombier {
2317dd7cddfSDavid du Colombier static char now[10];
2327dd7cddfSDavid du Colombier char *s;
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier if(now[0] == '\0'){
2357dd7cddfSDavid du Colombier s = ctime(time(nil));
2367dd7cddfSDavid du Colombier strcpy(now, s+24);
2377dd7cddfSDavid du Colombier }
2387dd7cddfSDavid du Colombier return strncmp(year, now, 4) == 0;
2397dd7cddfSDavid du Colombier }
2407dd7cddfSDavid du Colombier
2417dd7cddfSDavid du Colombier char*
stripdate(char * as)2427dd7cddfSDavid du Colombier stripdate(char *as)
2437dd7cddfSDavid du Colombier {
2447dd7cddfSDavid du Colombier int n;
2457dd7cddfSDavid du Colombier char *s, *fld[10];
2467dd7cddfSDavid du Colombier
2477dd7cddfSDavid du Colombier as = estrdup(as);
2487dd7cddfSDavid du Colombier s = estrdup(as);
2497dd7cddfSDavid du Colombier n = tokenize(s, fld, 10);
2507dd7cddfSDavid du Colombier if(n > 5){
2517dd7cddfSDavid du Colombier sprint(as, "%.3s ", fld[0]); /* day */
2527dd7cddfSDavid du Colombier /* some dates have 19 Apr, some Apr 19 */
2537dd7cddfSDavid du Colombier if(strlen(fld[1])<4 && isnumeric(fld[1]))
2547dd7cddfSDavid du Colombier sprint(as+strlen(as), "%.3s %.3s ", fld[1], fld[2]); /* date, month */
2557dd7cddfSDavid du Colombier else
2567dd7cddfSDavid du Colombier sprint(as+strlen(as), "%.3s %.3s ", fld[2], fld[1]); /* date, month */
2577dd7cddfSDavid du Colombier /* do we use time or year? depends on whether year matches this one */
2587dd7cddfSDavid du Colombier if(thisyear(fld[5])){
2597dd7cddfSDavid du Colombier if(strchr(fld[3], ':') != nil)
2607dd7cddfSDavid du Colombier sprint(as+strlen(as), "%.5s ", fld[3]); /* time */
2617dd7cddfSDavid du Colombier else if(strchr(fld[4], ':') != nil)
2627dd7cddfSDavid du Colombier sprint(as+strlen(as), "%.5s ", fld[4]); /* time */
2637dd7cddfSDavid du Colombier }else
2647dd7cddfSDavid du Colombier sprint(as+strlen(as), "%.4s ", fld[5]); /* year */
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier free(s);
2677dd7cddfSDavid du Colombier return as;
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier char*
readfile(char * dir,char * name,int * np)2717dd7cddfSDavid du Colombier readfile(char *dir, char *name, int *np)
2727dd7cddfSDavid du Colombier {
2737dd7cddfSDavid du Colombier char *file, *data;
2749a747e4fSDavid du Colombier int fd, len;
2759a747e4fSDavid du Colombier Dir *d;
2767dd7cddfSDavid du Colombier
2777dd7cddfSDavid du Colombier if(np != nil)
2787dd7cddfSDavid du Colombier *np = 0;
2797dd7cddfSDavid du Colombier file = estrstrdup(dir, name);
2807dd7cddfSDavid du Colombier fd = open(file, OREAD);
2817dd7cddfSDavid du Colombier if(fd < 0)
2827dd7cddfSDavid du Colombier return nil;
2839a747e4fSDavid du Colombier d = dirfstat(fd);
2847dd7cddfSDavid du Colombier free(file);
2859a747e4fSDavid du Colombier len = 0;
2869a747e4fSDavid du Colombier if(d != nil)
2879a747e4fSDavid du Colombier len = d->length;
2889a747e4fSDavid du Colombier free(d);
2899a747e4fSDavid du Colombier data = emalloc(len+1);
2909a747e4fSDavid du Colombier read(fd, data, len);
2917dd7cddfSDavid du Colombier close(fd);
2927dd7cddfSDavid du Colombier if(np != nil)
2939a747e4fSDavid du Colombier *np = len;
2947dd7cddfSDavid du Colombier return data;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier char*
info(Message * m,int ind,int ogf)2983ff48bf5SDavid du Colombier info(Message *m, int ind, int ogf)
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier char *i;
3013ff48bf5SDavid du Colombier int j, len, lens;
3023ff48bf5SDavid du Colombier char *p;
3033ff48bf5SDavid du Colombier char fmt[80], s[80];
3043ff48bf5SDavid du Colombier
3053ff48bf5SDavid du Colombier if (ogf)
3063ff48bf5SDavid du Colombier p=m->to;
3073ff48bf5SDavid du Colombier else
3083ff48bf5SDavid du Colombier p=m->fromcolon;
3097dd7cddfSDavid du Colombier
3109a747e4fSDavid du Colombier if(ind==0 && shortmenu){
3113ff48bf5SDavid du Colombier len = 30;
3123ff48bf5SDavid du Colombier lens = 30;
3133ff48bf5SDavid du Colombier if(shortmenu > 1){
3143ff48bf5SDavid du Colombier len = 10;
3153ff48bf5SDavid du Colombier lens = 25;
3163ff48bf5SDavid du Colombier }
3179a747e4fSDavid du Colombier if(ind==0 && m->subject[0]=='\0'){
3183ff48bf5SDavid du Colombier snprint(fmt, sizeof fmt, " %%-%d.%ds", len, len);
3193ff48bf5SDavid du Colombier snprint(s, sizeof s, fmt, p);
3209a747e4fSDavid du Colombier }else{
3213ff48bf5SDavid du Colombier snprint(fmt, sizeof fmt, " %%-%d.%ds %%-%d.%ds", len, len, lens, lens);
3223ff48bf5SDavid du Colombier snprint(s, sizeof s, fmt, p, m->subject);
3239a747e4fSDavid du Colombier }
3249a747e4fSDavid du Colombier i = estrdup(s);
3259a747e4fSDavid du Colombier
3269a747e4fSDavid du Colombier return i;
3279a747e4fSDavid du Colombier }
3289a747e4fSDavid du Colombier
3297dd7cddfSDavid du Colombier i = estrdup("");
3303ff48bf5SDavid du Colombier i = eappend(i, "\t", p);
3317dd7cddfSDavid du Colombier i = egrow(i, "\t", stripdate(m->date));
3327dd7cddfSDavid du Colombier if(ind == 0){
3337dd7cddfSDavid du Colombier if(strcmp(m->type, "text")!=0 && strncmp(m->type, "text/", 5)!=0 &&
3347dd7cddfSDavid du Colombier strncmp(m->type, "multipart/", 10)!=0)
3357dd7cddfSDavid du Colombier i = egrow(i, "\t(", estrstrdup(m->type, ")"));
3367dd7cddfSDavid du Colombier }else if(strncmp(m->type, "multipart/", 10) != 0)
3377dd7cddfSDavid du Colombier i = egrow(i, "\t(", estrstrdup(m->type, ")"));
3387dd7cddfSDavid du Colombier if(m->subject[0] != '\0'){
3397dd7cddfSDavid du Colombier i = eappend(i, "\n", nil);
3407dd7cddfSDavid du Colombier for(j=0; j<ind; j++)
3417dd7cddfSDavid du Colombier i = eappend(i, "\t", nil);
3427dd7cddfSDavid du Colombier i = eappend(i, "\t", m->subject);
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier return i;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier void
mesgmenu0(Window * w,Message * mbox,char * realdir,char * dir,int ind,Biobuf * fd,int onlyone,int dotail)3489a747e4fSDavid du Colombier mesgmenu0(Window *w, Message *mbox, char *realdir, char *dir, int ind, Biobuf *fd, int onlyone, int dotail)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier int i;
3517dd7cddfSDavid du Colombier Message *m;
3527dd7cddfSDavid du Colombier char *name, *tmp;
3533ff48bf5SDavid du Colombier int ogf=0;
3543ff48bf5SDavid du Colombier
355c27b0bc9SDavid du Colombier if(strstr(realdir, "outgoing") != nil)
3563ff48bf5SDavid du Colombier ogf=1;
3577dd7cddfSDavid du Colombier
3587dd7cddfSDavid du Colombier /* show mail box in reverse order, pieces in forward order */
3597dd7cddfSDavid du Colombier if(ind > 0)
3607dd7cddfSDavid du Colombier m = mbox->head;
3617dd7cddfSDavid du Colombier else
3627dd7cddfSDavid du Colombier m = mbox->tail;
3637dd7cddfSDavid du Colombier while(m != nil){
3647dd7cddfSDavid du Colombier for(i=0; i<ind; i++)
3657dd7cddfSDavid du Colombier Bprint(fd, "\t");
3667dd7cddfSDavid du Colombier if(ind != 0)
3677dd7cddfSDavid du Colombier Bprint(fd, " ");
3687dd7cddfSDavid du Colombier name = estrstrdup(dir, m->name);
3693ff48bf5SDavid du Colombier tmp = info(m, ind, ogf);
3707dd7cddfSDavid du Colombier Bprint(fd, "%s%s\n", name, tmp);
3717dd7cddfSDavid du Colombier free(tmp);
3729a747e4fSDavid du Colombier if(dotail && m->tail)
3739a747e4fSDavid du Colombier mesgmenu0(w, m, realdir, name, ind+1, fd, 0, dotail);
3747dd7cddfSDavid du Colombier free(name);
3757dd7cddfSDavid du Colombier if(ind)
3767dd7cddfSDavid du Colombier m = m->next;
3777dd7cddfSDavid du Colombier else
3787dd7cddfSDavid du Colombier m = m->prev;
3797dd7cddfSDavid du Colombier if(onlyone)
3807dd7cddfSDavid du Colombier m = nil;
3817dd7cddfSDavid du Colombier }
3827dd7cddfSDavid du Colombier }
3837dd7cddfSDavid du Colombier
3847dd7cddfSDavid du Colombier void
mesgmenu(Window * w,Message * mbox)3857dd7cddfSDavid du Colombier mesgmenu(Window *w, Message *mbox)
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier winopenbody(w, OWRITE);
3889a747e4fSDavid du Colombier mesgmenu0(w, mbox, mbox->name, "", 0, w->body, 0, !shortmenu);
3897dd7cddfSDavid du Colombier winclosebody(w);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier
3927dd7cddfSDavid du Colombier /* one new message has arrived, as mbox->tail */
3937dd7cddfSDavid du Colombier void
mesgmenunew(Window * w,Message * mbox)3947dd7cddfSDavid du Colombier mesgmenunew(Window *w, Message *mbox)
3957dd7cddfSDavid du Colombier {
3967dd7cddfSDavid du Colombier Biobuf *b;
3977dd7cddfSDavid du Colombier
3987dd7cddfSDavid du Colombier winselect(w, "0", 0);
3997dd7cddfSDavid du Colombier w->data = winopenfile(w, "data");
4007dd7cddfSDavid du Colombier b = emalloc(sizeof(Biobuf));
4017dd7cddfSDavid du Colombier Binit(b, w->data, OWRITE);
4029a747e4fSDavid du Colombier mesgmenu0(w, mbox, mbox->name, "", 0, b, 1, !shortmenu);
4037dd7cddfSDavid du Colombier Bterm(b);
4049a747e4fSDavid du Colombier free(b);
4057dd7cddfSDavid du Colombier if(!mbox->dirty)
4067dd7cddfSDavid du Colombier winclean(w);
4077dd7cddfSDavid du Colombier /* select tag line plus following indented lines, but not final newline (it's distinctive) */
4087dd7cddfSDavid du Colombier winselect(w, "0/.*\\n((\t.*\\n)*\t.*)?/", 1);
4097dd7cddfSDavid du Colombier close(w->addr);
4107dd7cddfSDavid du Colombier close(w->data);
4117dd7cddfSDavid du Colombier w->addr = -1;
4127dd7cddfSDavid du Colombier w->data = -1;
4137dd7cddfSDavid du Colombier }
4147dd7cddfSDavid du Colombier
4157dd7cddfSDavid du Colombier char*
name2regexp(char * prefix,char * s)4167dd7cddfSDavid du Colombier name2regexp(char *prefix, char *s)
4177dd7cddfSDavid du Colombier {
4187dd7cddfSDavid du Colombier char *buf, *p, *q;
4197dd7cddfSDavid du Colombier
4207dd7cddfSDavid du Colombier buf = emalloc(strlen(prefix)+2*strlen(s)+50); /* leave room to append more */
4217dd7cddfSDavid du Colombier p = buf;
4227dd7cddfSDavid du Colombier *p++ = '0';
4237dd7cddfSDavid du Colombier *p++ = '/';
4247dd7cddfSDavid du Colombier *p++ = '^';
4257dd7cddfSDavid du Colombier strcpy(p, prefix);
4267dd7cddfSDavid du Colombier p += strlen(prefix);
4277dd7cddfSDavid du Colombier for(q=s; *q!='\0'; q++){
4287dd7cddfSDavid du Colombier if(strchr(regexchars, *q) != nil)
4297dd7cddfSDavid du Colombier *p++ = '\\';
4307dd7cddfSDavid du Colombier *p++ = *q;
4317dd7cddfSDavid du Colombier }
4327dd7cddfSDavid du Colombier *p++ = '/';
4337dd7cddfSDavid du Colombier *p = '\0';
4347dd7cddfSDavid du Colombier return buf;
4357dd7cddfSDavid du Colombier }
4367dd7cddfSDavid du Colombier
4377dd7cddfSDavid du Colombier void
mesgmenumarkdel(Window * w,Message * mbox,Message * m,int writeback)4387dd7cddfSDavid du Colombier mesgmenumarkdel(Window *w, Message *mbox, Message *m, int writeback)
4397dd7cddfSDavid du Colombier {
4407dd7cddfSDavid du Colombier char *buf;
4417dd7cddfSDavid du Colombier
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier if(m->deleted)
4447dd7cddfSDavid du Colombier return;
4457dd7cddfSDavid du Colombier m->writebackdel = writeback;
4467dd7cddfSDavid du Colombier if(w->data < 0)
4477dd7cddfSDavid du Colombier w->data = winopenfile(w, "data");
4487dd7cddfSDavid du Colombier buf = name2regexp("", m->name);
4497dd7cddfSDavid du Colombier strcat(buf, "-#0");
4507dd7cddfSDavid du Colombier if(winselect(w, buf, 1))
4517dd7cddfSDavid du Colombier write(w->data, deleted, 10);
4527dd7cddfSDavid du Colombier free(buf);
4537dd7cddfSDavid du Colombier close(w->data);
4547dd7cddfSDavid du Colombier close(w->addr);
4557dd7cddfSDavid du Colombier w->addr = w->data = -1;
4567dd7cddfSDavid du Colombier mbox->dirty = 1;
4577dd7cddfSDavid du Colombier m->deleted = 1;
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier
4607dd7cddfSDavid du Colombier void
mesgmenumarkundel(Window * w,Message *,Message * m)4617dd7cddfSDavid du Colombier mesgmenumarkundel(Window *w, Message*, Message *m)
4627dd7cddfSDavid du Colombier {
4637dd7cddfSDavid du Colombier char *buf;
4647dd7cddfSDavid du Colombier
4657dd7cddfSDavid du Colombier if(m->deleted == 0)
4667dd7cddfSDavid du Colombier return;
4677dd7cddfSDavid du Colombier if(w->data < 0)
4687dd7cddfSDavid du Colombier w->data = winopenfile(w, "data");
4697dd7cddfSDavid du Colombier buf = name2regexp(deletedrx, m->name);
4707dd7cddfSDavid du Colombier if(winselect(w, buf, 1))
4717dd7cddfSDavid du Colombier if(winsetaddr(w, deletedaddr, 1))
4727dd7cddfSDavid du Colombier write(w->data, "", 0);
4737dd7cddfSDavid du Colombier free(buf);
4747dd7cddfSDavid du Colombier close(w->data);
4757dd7cddfSDavid du Colombier close(w->addr);
4767dd7cddfSDavid du Colombier w->addr = w->data = -1;
4777dd7cddfSDavid du Colombier m->deleted = 0;
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier void
mesgmenudel(Window * w,Message * mbox,Message * m)4817dd7cddfSDavid du Colombier mesgmenudel(Window *w, Message *mbox, Message *m)
4827dd7cddfSDavid du Colombier {
4837dd7cddfSDavid du Colombier char *buf;
4847dd7cddfSDavid du Colombier
4857dd7cddfSDavid du Colombier if(w->data < 0)
4867dd7cddfSDavid du Colombier w->data = winopenfile(w, "data");
4877dd7cddfSDavid du Colombier buf = name2regexp(deletedrx, m->name);
4887dd7cddfSDavid du Colombier if(winsetaddr(w, buf, 1) && winsetaddr(w, ".,./.*\\n(\t.*\\n)*/", 1))
4897dd7cddfSDavid du Colombier write(w->data, "", 0);
4907dd7cddfSDavid du Colombier free(buf);
4917dd7cddfSDavid du Colombier close(w->data);
4927dd7cddfSDavid du Colombier close(w->addr);
4937dd7cddfSDavid du Colombier w->addr = w->data = -1;
4947dd7cddfSDavid du Colombier mbox->dirty = 1;
4957dd7cddfSDavid du Colombier m->deleted = 1;
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier void
mesgmenumark(Window * w,char * which,char * mark)4997dd7cddfSDavid du Colombier mesgmenumark(Window *w, char *which, char *mark)
5007dd7cddfSDavid du Colombier {
5017dd7cddfSDavid du Colombier char *buf;
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier if(w->data < 0)
5047dd7cddfSDavid du Colombier w->data = winopenfile(w, "data");
5057dd7cddfSDavid du Colombier buf = name2regexp(deletedrx01, which);
5067dd7cddfSDavid du Colombier if(winsetaddr(w, buf, 1) && winsetaddr(w, "+0-#1", 1)) /* go to end of line */
5077dd7cddfSDavid du Colombier write(w->data, mark, strlen(mark));
5087dd7cddfSDavid du Colombier free(buf);
5097dd7cddfSDavid du Colombier close(w->data);
5107dd7cddfSDavid du Colombier close(w->addr);
5117dd7cddfSDavid du Colombier w->addr = w->data = -1;
5127dd7cddfSDavid du Colombier if(!mbox.dirty)
5137dd7cddfSDavid du Colombier winclean(w);
5147dd7cddfSDavid du Colombier }
5157dd7cddfSDavid du Colombier
5167dd7cddfSDavid du Colombier void
mesgfreeparts(Message * m)5177dd7cddfSDavid du Colombier mesgfreeparts(Message *m)
5187dd7cddfSDavid du Colombier {
5197dd7cddfSDavid du Colombier free(m->name);
5207dd7cddfSDavid du Colombier free(m->replyname);
5217dd7cddfSDavid du Colombier free(m->fromcolon);
5227dd7cddfSDavid du Colombier free(m->from);
5237dd7cddfSDavid du Colombier free(m->to);
5247dd7cddfSDavid du Colombier free(m->cc);
5257dd7cddfSDavid du Colombier free(m->replyto);
5267dd7cddfSDavid du Colombier free(m->date);
5277dd7cddfSDavid du Colombier free(m->subject);
5287dd7cddfSDavid du Colombier free(m->type);
5297dd7cddfSDavid du Colombier free(m->disposition);
5307dd7cddfSDavid du Colombier free(m->filename);
5317dd7cddfSDavid du Colombier free(m->digest);
5327dd7cddfSDavid du Colombier }
5337dd7cddfSDavid du Colombier
5347dd7cddfSDavid du Colombier void
mesgdel(Message * mbox,Message * m)5357dd7cddfSDavid du Colombier mesgdel(Message *mbox, Message *m)
5367dd7cddfSDavid du Colombier {
5377dd7cddfSDavid du Colombier Message *n, *next;
5387dd7cddfSDavid du Colombier
5397dd7cddfSDavid du Colombier if(m->opened)
54092fd5f07SDavid du Colombier error("internal error: deleted message still open in mesgdel");
5417dd7cddfSDavid du Colombier /* delete subparts */
5427dd7cddfSDavid du Colombier for(n=m->head; n!=nil; n=next){
5437dd7cddfSDavid du Colombier next = n->next;
5447dd7cddfSDavid du Colombier mesgdel(m, n);
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier /* remove this message from list */
5477dd7cddfSDavid du Colombier if(m->next)
5487dd7cddfSDavid du Colombier m->next->prev = m->prev;
5497dd7cddfSDavid du Colombier else
5507dd7cddfSDavid du Colombier mbox->tail = m->prev;
5517dd7cddfSDavid du Colombier if(m->prev)
5527dd7cddfSDavid du Colombier m->prev->next = m->next;
5537dd7cddfSDavid du Colombier else
5547dd7cddfSDavid du Colombier mbox->head = m->next;
5557dd7cddfSDavid du Colombier
5567dd7cddfSDavid du Colombier mesgfreeparts(m);
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier
5597dd7cddfSDavid du Colombier int
mesgsave(Message * m,char * s)5607dd7cddfSDavid du Colombier mesgsave(Message *m, char *s)
5617dd7cddfSDavid du Colombier {
5627dd7cddfSDavid du Colombier int ofd, n, k, ret;
5637dd7cddfSDavid du Colombier char *t, *raw, *unixheader, *all;
5647dd7cddfSDavid du Colombier
5657dd7cddfSDavid du Colombier t = estrstrdup(mbox.name, m->name);
5667dd7cddfSDavid du Colombier raw = readfile(t, "raw", &n);
5677dd7cddfSDavid du Colombier unixheader = readfile(t, "unixheader", &k);
5687dd7cddfSDavid du Colombier if(raw==nil || unixheader==nil){
5699a747e4fSDavid du Colombier fprint(2, "Mail: can't read %s: %r\n", t);
5707dd7cddfSDavid du Colombier free(t);
5717dd7cddfSDavid du Colombier return 0;
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier free(t);
5747dd7cddfSDavid du Colombier
575853458f3SDavid du Colombier all = emalloc(k+n+1);
576853458f3SDavid du Colombier memmove(all, unixheader, k);
577853458f3SDavid du Colombier memmove(all+k, raw, n);
578853458f3SDavid du Colombier memmove(all+k+n, "\n", 1);
579853458f3SDavid du Colombier n += k+1;
580853458f3SDavid du Colombier free(unixheader);
5817dd7cddfSDavid du Colombier free(raw);
5827dd7cddfSDavid du Colombier ret = 1;
5837dd7cddfSDavid du Colombier s = estrdup(s);
5847dd7cddfSDavid du Colombier if(s[0] != '/')
5857dd7cddfSDavid du Colombier s = egrow(estrdup(mailboxdir), "/", s);
5867dd7cddfSDavid du Colombier ofd = open(s, OWRITE);
5877dd7cddfSDavid du Colombier if(ofd < 0){
5889a747e4fSDavid du Colombier fprint(2, "Mail: can't open %s: %r\n", s);
5897dd7cddfSDavid du Colombier ret = 0;
590853458f3SDavid du Colombier }else if(seek(ofd, 0LL, 2)<0 || write(ofd, all, n)!=n){
5919a747e4fSDavid du Colombier fprint(2, "Mail: save failed: can't write %s: %r\n", s);
5927dd7cddfSDavid du Colombier ret = 0;
5937dd7cddfSDavid du Colombier }
5947dd7cddfSDavid du Colombier free(all);
5957dd7cddfSDavid du Colombier close(ofd);
5967dd7cddfSDavid du Colombier free(s);
5977dd7cddfSDavid du Colombier return ret;
5987dd7cddfSDavid du Colombier }
5997dd7cddfSDavid du Colombier
6007dd7cddfSDavid du Colombier int
mesgcommand(Message * m,char * cmd)6017dd7cddfSDavid du Colombier mesgcommand(Message *m, char *cmd)
6027dd7cddfSDavid du Colombier {
6039a747e4fSDavid du Colombier char *s;
6049a747e4fSDavid du Colombier char *args[10];
6059a747e4fSDavid du Colombier int ok, ret, nargs;
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier s = cmd;
6087dd7cddfSDavid du Colombier ret = 1;
6099a747e4fSDavid du Colombier nargs = tokenize(s, args, nelem(args));
6109a747e4fSDavid du Colombier if(nargs == 0)
6119a747e4fSDavid du Colombier return 0;
6129a747e4fSDavid du Colombier if(strcmp(args[0], "Post") == 0){
6137dd7cddfSDavid du Colombier mesgsend(m);
6147dd7cddfSDavid du Colombier goto Return;
6157dd7cddfSDavid du Colombier }
6169a747e4fSDavid du Colombier if(strncmp(args[0], "Save", 4) == 0){
6177dd7cddfSDavid du Colombier if(m->isreply)
6187dd7cddfSDavid du Colombier goto Return;
6199a747e4fSDavid du Colombier s = estrdup("\t[saved");
6209a747e4fSDavid du Colombier if(nargs==1 || strcmp(args[1], "")==0){
6217dd7cddfSDavid du Colombier ok = mesgsave(m, "stored");
6227dd7cddfSDavid du Colombier }else{
6239a747e4fSDavid du Colombier ok = mesgsave(m, args[1]);
6249a747e4fSDavid du Colombier s = eappend(s, " ", args[1]);
6257dd7cddfSDavid du Colombier }
6267dd7cddfSDavid du Colombier if(ok){
6279a747e4fSDavid du Colombier s = egrow(s, "]", nil);
6289a747e4fSDavid du Colombier mesgmenumark(mbox.w, m->name, s);
6297dd7cddfSDavid du Colombier }
6309a747e4fSDavid du Colombier free(s);
6317dd7cddfSDavid du Colombier goto Return;
6327dd7cddfSDavid du Colombier }
6339a747e4fSDavid du Colombier if(strcmp(args[0], "Reply")==0){
6349a747e4fSDavid du Colombier if(nargs>=2 && strcmp(args[1], "all")==0)
635d9306527SDavid du Colombier mkreply(m, "Replyall", nil, nil, nil);
6369a747e4fSDavid du Colombier else
637d9306527SDavid du Colombier mkreply(m, "Reply", nil, nil, nil);
6387dd7cddfSDavid du Colombier goto Return;
6397dd7cddfSDavid du Colombier }
6409a747e4fSDavid du Colombier if(strcmp(args[0], "Q") == 0){
641d9306527SDavid du Colombier s = winselection(m->w); /* will be freed by mkreply */
6429a747e4fSDavid du Colombier if(nargs>=3 && strcmp(args[1], "Reply")==0 && strcmp(args[2], "all")==0)
643d9306527SDavid du Colombier mkreply(m, "QReplyall", nil, nil, s);
6449a747e4fSDavid du Colombier else
645d9306527SDavid du Colombier mkreply(m, "QReply", nil, nil, s);
6469a747e4fSDavid du Colombier goto Return;
6479a747e4fSDavid du Colombier }
6489a747e4fSDavid du Colombier if(strcmp(args[0], "Del") == 0){
6497dd7cddfSDavid du Colombier if(windel(m->w, 0)){
6507dd7cddfSDavid du Colombier chanfree(m->w->cevent);
6517dd7cddfSDavid du Colombier free(m->w);
6527dd7cddfSDavid du Colombier m->w = nil;
6537dd7cddfSDavid du Colombier if(m->isreply)
6547dd7cddfSDavid du Colombier delreply(m);
6557dd7cddfSDavid du Colombier else{
6567dd7cddfSDavid du Colombier m->opened = 0;
6577dd7cddfSDavid du Colombier m->tagposted = 0;
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier free(cmd);
6607dd7cddfSDavid du Colombier threadexits(nil);
6617dd7cddfSDavid du Colombier }
6627dd7cddfSDavid du Colombier goto Return;
6637dd7cddfSDavid du Colombier }
6649a747e4fSDavid du Colombier if(strcmp(args[0], "Delmesg") == 0){
6657dd7cddfSDavid du Colombier if(!m->isreply){
6667dd7cddfSDavid du Colombier mesgmenumarkdel(wbox, &mbox, m, 1);
6677dd7cddfSDavid du Colombier free(cmd); /* mesgcommand might not return */
6687dd7cddfSDavid du Colombier mesgcommand(m, estrdup("Del"));
6697dd7cddfSDavid du Colombier return 1;
6707dd7cddfSDavid du Colombier }
6717dd7cddfSDavid du Colombier goto Return;
6727dd7cddfSDavid du Colombier }
6739a747e4fSDavid du Colombier if(strcmp(args[0], "UnDelmesg") == 0){
6747dd7cddfSDavid du Colombier if(!m->isreply && m->deleted)
6757dd7cddfSDavid du Colombier mesgmenumarkundel(wbox, &mbox, m);
6767dd7cddfSDavid du Colombier goto Return;
6777dd7cddfSDavid du Colombier }
6789a747e4fSDavid du Colombier // if(strcmp(args[0], "Headers") == 0){
6797dd7cddfSDavid du Colombier // m->showheaders();
6807dd7cddfSDavid du Colombier // return True;
6817dd7cddfSDavid du Colombier // }
6827dd7cddfSDavid du Colombier
6837dd7cddfSDavid du Colombier ret = 0;
6847dd7cddfSDavid du Colombier
6857dd7cddfSDavid du Colombier Return:
6867dd7cddfSDavid du Colombier free(cmd);
6877dd7cddfSDavid du Colombier return ret;
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier
6907dd7cddfSDavid du Colombier void
mesgtagpost(Message * m)6917dd7cddfSDavid du Colombier mesgtagpost(Message *m)
6927dd7cddfSDavid du Colombier {
6937dd7cddfSDavid du Colombier if(m->tagposted)
6947dd7cddfSDavid du Colombier return;
6957dd7cddfSDavid du Colombier wintagwrite(m->w, " Post", 5);
6967dd7cddfSDavid du Colombier m->tagposted = 1;
6977dd7cddfSDavid du Colombier }
6987dd7cddfSDavid du Colombier
6995d459b5aSDavid du Colombier /* need to expand selection more than default word */
7005d459b5aSDavid du Colombier #pragma varargck argpos eval 2
7015d459b5aSDavid du Colombier
7025d459b5aSDavid du Colombier long
eval(Window * w,char * s,...)7035d459b5aSDavid du Colombier eval(Window *w, char *s, ...)
7045d459b5aSDavid du Colombier {
7055d459b5aSDavid du Colombier char buf[64];
7065d459b5aSDavid du Colombier va_list arg;
7075d459b5aSDavid du Colombier
7085d459b5aSDavid du Colombier va_start(arg, s);
7095d459b5aSDavid du Colombier vsnprint(buf, sizeof buf, s, arg);
7105d459b5aSDavid du Colombier va_end(arg);
7115d459b5aSDavid du Colombier
7125d459b5aSDavid du Colombier if(winsetaddr(w, buf, 1)==0)
7135d459b5aSDavid du Colombier return -1;
7145d459b5aSDavid du Colombier
7155d459b5aSDavid du Colombier if(pread(w->addr, buf, 24, 0) != 24)
7165d459b5aSDavid du Colombier return -1;
7175d459b5aSDavid du Colombier return strtol(buf, 0, 10);
7185d459b5aSDavid du Colombier }
7195d459b5aSDavid du Colombier
7205d459b5aSDavid du Colombier int
isemail(char * s)7215d459b5aSDavid du Colombier isemail(char *s)
7225d459b5aSDavid du Colombier {
7235d459b5aSDavid du Colombier int nat;
7245d459b5aSDavid du Colombier
7255d459b5aSDavid du Colombier nat = 0;
7265d459b5aSDavid du Colombier for(; *s; s++)
7275d459b5aSDavid du Colombier if(*s == '@')
7285d459b5aSDavid du Colombier nat++;
7295d459b5aSDavid du Colombier else if(!isalpha(*s) && !isdigit(*s) && !strchr("_.-+/", *s))
7305d459b5aSDavid du Colombier return 0;
7315d459b5aSDavid du Colombier return nat==1;
7325d459b5aSDavid du Colombier }
7335d459b5aSDavid du Colombier
7345d459b5aSDavid du Colombier char addrdelim[] = "/[ \t\\n<>()\\[\\]]/";
7355d459b5aSDavid du Colombier char*
expandaddr(Window * w,Event * e)7365d459b5aSDavid du Colombier expandaddr(Window *w, Event *e)
7375d459b5aSDavid du Colombier {
7385d459b5aSDavid du Colombier char *s;
7395d459b5aSDavid du Colombier long q0, q1;
7405d459b5aSDavid du Colombier
7415d459b5aSDavid du Colombier if(e->q0 != e->q1) /* cannot happen */
7425d459b5aSDavid du Colombier return nil;
7435d459b5aSDavid du Colombier
7445d459b5aSDavid du Colombier q0 = eval(w, "#%d-%s", e->q0, addrdelim);
7455d459b5aSDavid du Colombier if(q0 == -1) /* bad char not found */
7465d459b5aSDavid du Colombier q0 = 0;
7475d459b5aSDavid du Colombier else /* increment past bad char */
7485d459b5aSDavid du Colombier q0++;
7495d459b5aSDavid du Colombier
7505d459b5aSDavid du Colombier q1 = eval(w, "#%d+%s", e->q0, addrdelim);
7515d459b5aSDavid du Colombier if(q1 < 0){
7525d459b5aSDavid du Colombier q1 = eval(w, "$");
7535d459b5aSDavid du Colombier if(q1 < 0)
7545d459b5aSDavid du Colombier return nil;
7555d459b5aSDavid du Colombier }
7565d459b5aSDavid du Colombier if(q0 >= q1)
7575d459b5aSDavid du Colombier return nil;
7585d459b5aSDavid du Colombier s = emalloc((q1-q0)*UTFmax+1);
7595d459b5aSDavid du Colombier winread(w, q0, q1, s);
7605d459b5aSDavid du Colombier return s;
7615d459b5aSDavid du Colombier }
7625d459b5aSDavid du Colombier
7635d459b5aSDavid du Colombier int
replytoaddr(Window * w,Message * m,Event * e,char * s)7645d459b5aSDavid du Colombier replytoaddr(Window *w, Message *m, Event *e, char *s)
7655d459b5aSDavid du Colombier {
7665d459b5aSDavid du Colombier int did;
7675d459b5aSDavid du Colombier char *buf;
7685d459b5aSDavid du Colombier Plumbmsg *pm;
7695d459b5aSDavid du Colombier
7705d459b5aSDavid du Colombier buf = nil;
7715d459b5aSDavid du Colombier did = 0;
7725d459b5aSDavid du Colombier if(e->flag & 2){
7735d459b5aSDavid du Colombier /* autoexpanded; use our own bigger expansion */
7745d459b5aSDavid du Colombier buf = expandaddr(w, e);
7755d459b5aSDavid du Colombier if(buf == nil)
7765d459b5aSDavid du Colombier return 0;
7775d459b5aSDavid du Colombier s = buf;
7785d459b5aSDavid du Colombier }
7795d459b5aSDavid du Colombier if(isemail(s)){
7805d459b5aSDavid du Colombier did = 1;
7815d459b5aSDavid du Colombier pm = emalloc(sizeof(Plumbmsg));
7825d459b5aSDavid du Colombier pm->src = estrdup("Mail");
7835d459b5aSDavid du Colombier pm->dst = estrdup("sendmail");
7845d459b5aSDavid du Colombier pm->data = estrdup(s);
7855d459b5aSDavid du Colombier pm->ndata = -1;
7865d459b5aSDavid du Colombier if(m->subject && m->subject[0]){
7875d459b5aSDavid du Colombier pm->attr = emalloc(sizeof(Plumbattr));
7885d459b5aSDavid du Colombier pm->attr->name = estrdup("Subject");
7895d459b5aSDavid du Colombier if(tolower(m->subject[0]) != 'r' || tolower(m->subject[1]) != 'e' || m->subject[2] != ':')
7905d459b5aSDavid du Colombier pm->attr->value = estrstrdup("Re: ", m->subject);
7915d459b5aSDavid du Colombier else
7925d459b5aSDavid du Colombier pm->attr->value = estrdup(m->subject);
7935d459b5aSDavid du Colombier pm->attr->next = nil;
7945d459b5aSDavid du Colombier }
7955d459b5aSDavid du Colombier if(plumbsend(plumbsendfd, pm) < 0)
7965d459b5aSDavid du Colombier fprint(2, "error writing plumb message: %r\n");
7975d459b5aSDavid du Colombier plumbfree(pm);
7985d459b5aSDavid du Colombier }
7995d459b5aSDavid du Colombier free(buf);
8005d459b5aSDavid du Colombier return did;
8015d459b5aSDavid du Colombier }
8025d459b5aSDavid du Colombier
8035d459b5aSDavid du Colombier
8047dd7cddfSDavid du Colombier void
mesgctl(void * v)8057dd7cddfSDavid du Colombier mesgctl(void *v)
8067dd7cddfSDavid du Colombier {
8077dd7cddfSDavid du Colombier Message *m;
8087dd7cddfSDavid du Colombier Window *w;
8097dd7cddfSDavid du Colombier Event *e, *eq, *e2, *ea;
8107dd7cddfSDavid du Colombier int na, nopen, i, j;
8115d459b5aSDavid du Colombier char *os, *s, *t, *buf;
8127dd7cddfSDavid du Colombier
8137dd7cddfSDavid du Colombier m = v;
8147dd7cddfSDavid du Colombier w = m->w;
8157dd7cddfSDavid du Colombier threadsetname("mesgctl");
8167dd7cddfSDavid du Colombier proccreate(wineventproc, w, STACK);
8177dd7cddfSDavid du Colombier for(;;){
8187dd7cddfSDavid du Colombier e = recvp(w->cevent);
8197dd7cddfSDavid du Colombier switch(e->c1){
8207dd7cddfSDavid du Colombier default:
8217dd7cddfSDavid du Colombier Unk:
8227dd7cddfSDavid du Colombier print("unknown message %c%c\n", e->c1, e->c2);
8237dd7cddfSDavid du Colombier break;
8247dd7cddfSDavid du Colombier
8257dd7cddfSDavid du Colombier case 'E': /* write to body; can't affect us */
8267dd7cddfSDavid du Colombier break;
8277dd7cddfSDavid du Colombier
8287dd7cddfSDavid du Colombier case 'F': /* generated by our actions; ignore */
8297dd7cddfSDavid du Colombier break;
8307dd7cddfSDavid du Colombier
8317dd7cddfSDavid du Colombier case 'K': /* type away; we don't care */
8327dd7cddfSDavid du Colombier case 'M':
8337dd7cddfSDavid du Colombier switch(e->c2){
8347dd7cddfSDavid du Colombier case 'x': /* mouse only */
8357dd7cddfSDavid du Colombier case 'X':
8367dd7cddfSDavid du Colombier ea = nil;
8377dd7cddfSDavid du Colombier eq = e;
8387dd7cddfSDavid du Colombier if(e->flag & 2){
8397dd7cddfSDavid du Colombier e2 = recvp(w->cevent);
8407dd7cddfSDavid du Colombier eq = e2;
8417dd7cddfSDavid du Colombier }
8427dd7cddfSDavid du Colombier if(e->flag & 8){
8437dd7cddfSDavid du Colombier ea = recvp(w->cevent);
8447dd7cddfSDavid du Colombier recvp(w->cevent);
8457dd7cddfSDavid du Colombier na = ea->nb;
8467dd7cddfSDavid du Colombier }else
8477dd7cddfSDavid du Colombier na = 0;
8487dd7cddfSDavid du Colombier if(eq->q1>eq->q0 && eq->nb==0){
8497dd7cddfSDavid du Colombier s = emalloc((eq->q1-eq->q0)*UTFmax+1);
8507dd7cddfSDavid du Colombier winread(w, eq->q0, eq->q1, s);
8517dd7cddfSDavid du Colombier }else
8527dd7cddfSDavid du Colombier s = estrdup(eq->b);
8537dd7cddfSDavid du Colombier if(na){
8547dd7cddfSDavid du Colombier t = emalloc(strlen(s)+1+na+1);
8557dd7cddfSDavid du Colombier sprint(t, "%s %s", s, ea->b);
8567dd7cddfSDavid du Colombier free(s);
8577dd7cddfSDavid du Colombier s = t;
8587dd7cddfSDavid du Colombier }
8597dd7cddfSDavid du Colombier if(!mesgcommand(m, s)) /* send it back */
8607dd7cddfSDavid du Colombier winwriteevent(w, e);
8617dd7cddfSDavid du Colombier break;
8627dd7cddfSDavid du Colombier
8637dd7cddfSDavid du Colombier case 'l': /* mouse only */
8647dd7cddfSDavid du Colombier case 'L':
8657dd7cddfSDavid du Colombier buf = nil;
8667dd7cddfSDavid du Colombier eq = e;
8677dd7cddfSDavid du Colombier if(e->flag & 2){
8687dd7cddfSDavid du Colombier e2 = recvp(w->cevent);
8697dd7cddfSDavid du Colombier eq = e2;
8707dd7cddfSDavid du Colombier }
8717dd7cddfSDavid du Colombier s = eq->b;
8727dd7cddfSDavid du Colombier if(eq->q1>eq->q0 && eq->nb==0){
8737dd7cddfSDavid du Colombier buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
8747dd7cddfSDavid du Colombier winread(w, eq->q0, eq->q1, buf);
8757dd7cddfSDavid du Colombier s = buf;
8767dd7cddfSDavid du Colombier }
8775d459b5aSDavid du Colombier os = s;
8787dd7cddfSDavid du Colombier nopen = 0;
8797dd7cddfSDavid du Colombier do{
8807dd7cddfSDavid du Colombier /* skip mail box name if present */
8817dd7cddfSDavid du Colombier if(strncmp(s, mbox.name, strlen(mbox.name)) == 0)
8827dd7cddfSDavid du Colombier s += strlen(mbox.name);
8837dd7cddfSDavid du Colombier if(strstr(s, "body") != nil){
8847dd7cddfSDavid du Colombier /* strip any known extensions */
8857dd7cddfSDavid du Colombier for(i=0; exts[i].ext!=nil; i++){
8867dd7cddfSDavid du Colombier j = strlen(exts[i].ext);
8877dd7cddfSDavid du Colombier if(strlen(s)>j && strcmp(s+strlen(s)-j, exts[i].ext)==0){
8887dd7cddfSDavid du Colombier s[strlen(s)-j] = '\0';
8897dd7cddfSDavid du Colombier break;
8907dd7cddfSDavid du Colombier }
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier if(strlen(s)>5 && strcmp(s+strlen(s)-5, "/body")==0)
8937dd7cddfSDavid du Colombier s[strlen(s)-4] = '\0'; /* leave / in place */
8947dd7cddfSDavid du Colombier }
8957dd7cddfSDavid du Colombier nopen += mesgopen(&mbox, mbox.name, s, m, 0, nil);
8967dd7cddfSDavid du Colombier while(*s!=0 && *s++!='\n')
8977dd7cddfSDavid du Colombier ;
8987dd7cddfSDavid du Colombier }while(*s);
8993ff48bf5SDavid du Colombier if(nopen == 0 && e->c1 == 'L')
9005d459b5aSDavid du Colombier nopen += replytoaddr(w, m, e, os);
9015d459b5aSDavid du Colombier if(nopen == 0)
9027dd7cddfSDavid du Colombier winwriteevent(w, e);
9037dd7cddfSDavid du Colombier free(buf);
9047dd7cddfSDavid du Colombier break;
9057dd7cddfSDavid du Colombier
9067dd7cddfSDavid du Colombier case 'I': /* modify away; we don't care */
9077dd7cddfSDavid du Colombier case 'D':
9087dd7cddfSDavid du Colombier mesgtagpost(m);
9097dd7cddfSDavid du Colombier /* fall through */
9107dd7cddfSDavid du Colombier case 'd':
9117dd7cddfSDavid du Colombier case 'i':
9127dd7cddfSDavid du Colombier break;
9137dd7cddfSDavid du Colombier
9147dd7cddfSDavid du Colombier default:
9157dd7cddfSDavid du Colombier goto Unk;
9167dd7cddfSDavid du Colombier }
9177dd7cddfSDavid du Colombier }
9187dd7cddfSDavid du Colombier }
9197dd7cddfSDavid du Colombier }
9207dd7cddfSDavid du Colombier
9217dd7cddfSDavid du Colombier void
mesgline(Message * m,char * header,char * value)9227dd7cddfSDavid du Colombier mesgline(Message *m, char *header, char *value)
9237dd7cddfSDavid du Colombier {
9247dd7cddfSDavid du Colombier if(strlen(value) > 0)
9257dd7cddfSDavid du Colombier Bprint(m->w->body, "%s: %s\n", header, value);
9267dd7cddfSDavid du Colombier }
9277dd7cddfSDavid du Colombier
9287dd7cddfSDavid du Colombier int
isprintable(char * type)9297dd7cddfSDavid du Colombier isprintable(char *type)
9307dd7cddfSDavid du Colombier {
9317dd7cddfSDavid du Colombier int i;
9327dd7cddfSDavid du Colombier
9337dd7cddfSDavid du Colombier for(i=0; goodtypes[i]!=nil; i++)
9347dd7cddfSDavid du Colombier if(strcmp(type, goodtypes[i])==0)
9357dd7cddfSDavid du Colombier return 1;
9367dd7cddfSDavid du Colombier return 0;
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier
9397dd7cddfSDavid du Colombier char*
ext(char * type)9407dd7cddfSDavid du Colombier ext(char *type)
9417dd7cddfSDavid du Colombier {
9427dd7cddfSDavid du Colombier int i;
9437dd7cddfSDavid du Colombier
9447dd7cddfSDavid du Colombier for(i=0; exts[i].type!=nil; i++)
9457dd7cddfSDavid du Colombier if(strcmp(type, exts[i].type)==0)
9467dd7cddfSDavid du Colombier return exts[i].ext;
9477dd7cddfSDavid du Colombier return "";
9487dd7cddfSDavid du Colombier }
9497dd7cddfSDavid du Colombier
9507dd7cddfSDavid du Colombier void
mimedisplay(Message * m,char * name,char * rootdir,Window * w,int fileonly)9517dd7cddfSDavid du Colombier mimedisplay(Message *m, char *name, char *rootdir, Window *w, int fileonly)
9527dd7cddfSDavid du Colombier {
953671dfc47SDavid du Colombier char *dest, *maildest;
9547dd7cddfSDavid du Colombier
9557dd7cddfSDavid du Colombier if(strcmp(m->disposition, "file")==0 || strlen(m->filename)!=0){
9567dd7cddfSDavid du Colombier if(strlen(m->filename) == 0){
9577dd7cddfSDavid du Colombier dest = estrdup(m->name);
9587dd7cddfSDavid du Colombier dest[strlen(dest)-1] = '\0';
9597dd7cddfSDavid du Colombier }else
9607dd7cddfSDavid du Colombier dest = estrdup(m->filename);
961671dfc47SDavid du Colombier if(maildest = getenv("maildest")){
962671dfc47SDavid du Colombier maildest = eappend(maildest, "/", dest);
963671dfc47SDavid du Colombier Bprint(w->body, "\tcp %s%sbody%s %q\n", rootdir, name, ext(m->type), maildest);
964671dfc47SDavid du Colombier free(maildest);
965671dfc47SDavid du Colombier }
966671dfc47SDavid du Colombier if(m->filename[0] != '/'){
9677dd7cddfSDavid du Colombier dest = egrow(estrdup(home), "/", dest);
968671dfc47SDavid du Colombier }
969d9306527SDavid du Colombier Bprint(w->body, "\tcp %s%sbody%s %q\n", rootdir, name, ext(m->type), dest);
9707dd7cddfSDavid du Colombier free(dest);
9717dd7cddfSDavid du Colombier }else if(!fileonly)
9727dd7cddfSDavid du Colombier Bprint(w->body, "\tfile is %s%sbody%s\n", rootdir, name, ext(m->type));
9737dd7cddfSDavid du Colombier }
9747dd7cddfSDavid du Colombier
9757dd7cddfSDavid du Colombier void
printheader(char * dir,Biobuf * b,char ** okheaders)976c27b0bc9SDavid du Colombier printheader(char *dir, Biobuf *b, char **okheaders)
9779a747e4fSDavid du Colombier {
9789a747e4fSDavid du Colombier char *s;
9799a747e4fSDavid du Colombier char *lines[100];
9809a747e4fSDavid du Colombier int i, j, n;
9819a747e4fSDavid du Colombier
9829a747e4fSDavid du Colombier s = readfile(dir, "header", nil);
9839a747e4fSDavid du Colombier if(s == nil)
9849a747e4fSDavid du Colombier return;
9859a747e4fSDavid du Colombier n = getfields(s, lines, nelem(lines), 0, "\n");
9869a747e4fSDavid du Colombier for(i=0; i<n; i++)
9879a747e4fSDavid du Colombier for(j=0; okheaders[j]; j++)
9889a747e4fSDavid du Colombier if(cistrncmp(lines[i], okheaders[j], strlen(okheaders[j])) == 0)
9899a747e4fSDavid du Colombier Bprint(b, "%s\n", lines[i]);
9909a747e4fSDavid du Colombier free(s);
9919a747e4fSDavid du Colombier }
9929a747e4fSDavid du Colombier
993*8ccc32efSDavid du Colombier /*
994*8ccc32efSDavid du Colombier * find the best alternative part.
995*8ccc32efSDavid du Colombier *
996*8ccc32efSDavid du Colombier * turkeys have started emitting empty text/plain parts,
997*8ccc32efSDavid du Colombier * with the actual content in a text/html part, which complicates the choice.
998*8ccc32efSDavid du Colombier *
999*8ccc32efSDavid du Colombier * bigger turkeys emit a tiny base64-encoded text/plain part,
1000*8ccc32efSDavid du Colombier * a small base64-encoded text/html part, and the real content is in
1001*8ccc32efSDavid du Colombier * a text/calendar part.
1002*8ccc32efSDavid du Colombier *
1003*8ccc32efSDavid du Colombier * the magic lengths are empirically derived.
1004*8ccc32efSDavid du Colombier * as turkeys devolve and mutate, this will only get worse.
1005*8ccc32efSDavid du Colombier */
1006*8ccc32efSDavid du Colombier static Message*
bestalt(Message * m,char * dir)1007*8ccc32efSDavid du Colombier bestalt(Message *m, char *dir)
1008*8ccc32efSDavid du Colombier {
1009*8ccc32efSDavid du Colombier int len;
1010*8ccc32efSDavid du Colombier char *subdir;
1011*8ccc32efSDavid du Colombier Message *nm;
1012*8ccc32efSDavid du Colombier Message *realplain, *realhtml, *realcal;
1013*8ccc32efSDavid du Colombier
1014*8ccc32efSDavid du Colombier realplain = realhtml = realcal = nil;
1015*8ccc32efSDavid du Colombier for(nm = m->head; nm != nil; nm = nm->next){
1016*8ccc32efSDavid du Colombier subdir = estrstrdup(dir, nm->name);
1017*8ccc32efSDavid du Colombier len = 0;
1018*8ccc32efSDavid du Colombier free(readbody(nm->type, subdir, &len));
1019*8ccc32efSDavid du Colombier free(subdir);
1020*8ccc32efSDavid du Colombier if(strcmp(nm->type, "text/plain") == 0 && len >= 8)
1021*8ccc32efSDavid du Colombier realplain = nm;
1022*8ccc32efSDavid du Colombier else if(strcmp(nm->type, "text/html") == 0 && len >= 600)
1023*8ccc32efSDavid du Colombier realhtml = nm;
1024*8ccc32efSDavid du Colombier else if(strcmp(nm->type, "text/calendar") == 0)
1025*8ccc32efSDavid du Colombier realcal = nm;
1026*8ccc32efSDavid du Colombier }
1027*8ccc32efSDavid du Colombier if(realplain == nil && realhtml == nil && realcal)
1028*8ccc32efSDavid du Colombier return realcal; /* super-turkey */
1029*8ccc32efSDavid du Colombier else if(realplain == nil && realhtml)
1030*8ccc32efSDavid du Colombier return realhtml; /* regular turkey */
1031*8ccc32efSDavid du Colombier else
1032*8ccc32efSDavid du Colombier return realplain;
1033*8ccc32efSDavid du Colombier }
1034*8ccc32efSDavid du Colombier
10359a747e4fSDavid du Colombier void
mesgload(Message * m,char * rootdir,char * file,Window * w)10367dd7cddfSDavid du Colombier mesgload(Message *m, char *rootdir, char *file, Window *w)
10377dd7cddfSDavid du Colombier {
10387dd7cddfSDavid du Colombier char *s, *subdir, *name, *dir;
10397dd7cddfSDavid du Colombier Message *mp, *thisone;
10407dd7cddfSDavid du Colombier int n;
10417dd7cddfSDavid du Colombier
10427dd7cddfSDavid du Colombier dir = estrstrdup(rootdir, file);
10439a747e4fSDavid du Colombier
10449a747e4fSDavid du Colombier if(strcmp(m->type, "message/rfc822") != 0){ /* suppress headers of envelopes */
10459a747e4fSDavid du Colombier if(strlen(m->from) > 0){
10467dd7cddfSDavid du Colombier Bprint(w->body, "From: %s\n", m->from);
10477dd7cddfSDavid du Colombier mesgline(m, "Date", m->date);
10487dd7cddfSDavid du Colombier mesgline(m, "To", m->to);
10497dd7cddfSDavid du Colombier mesgline(m, "CC", m->cc);
10507dd7cddfSDavid du Colombier mesgline(m, "Subject", m->subject);
1051c27b0bc9SDavid du Colombier printheader(dir, w->body, extraheaders);
1052c27b0bc9SDavid du Colombier }else{
1053c27b0bc9SDavid du Colombier printheader(dir, w->body, okheaders);
1054c27b0bc9SDavid du Colombier printheader(dir, w->body, extraheaders);
1055c27b0bc9SDavid du Colombier }
10567dd7cddfSDavid du Colombier Bprint(w->body, "\n");
10579a747e4fSDavid du Colombier }
10587dd7cddfSDavid du Colombier
10599a747e4fSDavid du Colombier if(m->level == 1 && m->recursed == 0){
10609a747e4fSDavid du Colombier m->recursed = 1;
10619a747e4fSDavid du Colombier readmbox(m, rootdir, m->name);
10629a747e4fSDavid du Colombier }
10637dd7cddfSDavid du Colombier if(m->head == nil){ /* single part message */
10647dd7cddfSDavid du Colombier if(strcmp(m->type, "text")==0 || strncmp(m->type, "text/", 5)==0){
10657dd7cddfSDavid du Colombier mimedisplay(m, m->name, rootdir, w, 1);
10669a747e4fSDavid du Colombier s = readbody(m->type, dir, &n);
10677dd7cddfSDavid du Colombier winwritebody(w, s, n);
10687dd7cddfSDavid du Colombier free(s);
10697dd7cddfSDavid du Colombier }else
10707dd7cddfSDavid du Colombier mimedisplay(m, m->name, rootdir, w, 0);
10719a747e4fSDavid du Colombier }else{
10729a747e4fSDavid du Colombier /* multi-part message, either multipart/* or message/rfc822 */
10737dd7cddfSDavid du Colombier thisone = nil;
10747dd7cddfSDavid du Colombier if(strcmp(m->type, "multipart/alternative") == 0){
1075*8ccc32efSDavid du Colombier thisone = bestalt(m, dir);
1076*8ccc32efSDavid du Colombier if(thisone == nil){
10777dd7cddfSDavid du Colombier thisone = m->head; /* in case we can't find a good one */
10787dd7cddfSDavid du Colombier for(mp=m->head; mp!=nil; mp=mp->next)
10797dd7cddfSDavid du Colombier if(isprintable(mp->type)){
10807dd7cddfSDavid du Colombier thisone = mp;
10817dd7cddfSDavid du Colombier break;
10827dd7cddfSDavid du Colombier }
10837dd7cddfSDavid du Colombier }
1084*8ccc32efSDavid du Colombier }
10857dd7cddfSDavid du Colombier for(mp=m->head; mp!=nil; mp=mp->next){
10867dd7cddfSDavid du Colombier if(thisone!=nil && mp!=thisone)
10877dd7cddfSDavid du Colombier continue;
10887dd7cddfSDavid du Colombier subdir = estrstrdup(dir, mp->name);
10897dd7cddfSDavid du Colombier name = estrstrdup(file, mp->name);
10907dd7cddfSDavid du Colombier /* skip first element in name because it's already in window name */
10917dd7cddfSDavid du Colombier if(mp != m->head)
1092*8ccc32efSDavid du Colombier Bprint(w->body, "\n===> %s (%s) [%s]\n",
1093*8ccc32efSDavid du Colombier strchr(name, '/')+1, mp->type,
1094*8ccc32efSDavid du Colombier mp->disposition);
1095*8ccc32efSDavid du Colombier if(strcmp(mp->type, "text")==0 ||
1096*8ccc32efSDavid du Colombier strncmp(mp->type, "text/", 5)==0){
10977dd7cddfSDavid du Colombier mimedisplay(mp, name, rootdir, w, 1);
1098c27b0bc9SDavid du Colombier printheader(subdir, w->body, okheaders);
1099c27b0bc9SDavid du Colombier printheader(subdir, w->body, extraheaders);
11007dd7cddfSDavid du Colombier winwritebody(w, "\n", 1);
11019a747e4fSDavid du Colombier s = readbody(mp->type, subdir, &n);
11027dd7cddfSDavid du Colombier winwritebody(w, s, n);
11037dd7cddfSDavid du Colombier free(s);
11047dd7cddfSDavid du Colombier }else{
1105*8ccc32efSDavid du Colombier if(strncmp(mp->type, "multipart/", 10)==0 ||
1106*8ccc32efSDavid du Colombier strcmp(mp->type, "message/rfc822")==0){
11077dd7cddfSDavid du Colombier mp->w = w;
11087dd7cddfSDavid du Colombier mesgload(mp, rootdir, name, w);
11097dd7cddfSDavid du Colombier mp->w = nil;
11107dd7cddfSDavid du Colombier }else
11117dd7cddfSDavid du Colombier mimedisplay(mp, name, rootdir, w, 0);
11127dd7cddfSDavid du Colombier }
11137dd7cddfSDavid du Colombier free(name);
11147dd7cddfSDavid du Colombier free(subdir);
11157dd7cddfSDavid du Colombier }
11167dd7cddfSDavid du Colombier }
11177dd7cddfSDavid du Colombier free(dir);
11187dd7cddfSDavid du Colombier }
11197dd7cddfSDavid du Colombier
11207dd7cddfSDavid du Colombier int
tokenizec(char * str,char ** args,int max,char * splitc)11217dd7cddfSDavid du Colombier tokenizec(char *str, char **args, int max, char *splitc)
11227dd7cddfSDavid du Colombier {
11237dd7cddfSDavid du Colombier int na;
11247dd7cddfSDavid du Colombier int intok = 0;
11257dd7cddfSDavid du Colombier
11267dd7cddfSDavid du Colombier if(max <= 0)
11277dd7cddfSDavid du Colombier return 0;
11287dd7cddfSDavid du Colombier for(na=0; *str != '\0';str++){
11297dd7cddfSDavid du Colombier if(strchr(splitc, *str) == nil){
11307dd7cddfSDavid du Colombier if(intok)
11317dd7cddfSDavid du Colombier continue;
11327dd7cddfSDavid du Colombier args[na++] = str;
11337dd7cddfSDavid du Colombier intok = 1;
11347dd7cddfSDavid du Colombier }else{
11357dd7cddfSDavid du Colombier /* it's a separator/skip character */
11367dd7cddfSDavid du Colombier *str = '\0';
11377dd7cddfSDavid du Colombier if(intok){
11387dd7cddfSDavid du Colombier intok = 0;
11397dd7cddfSDavid du Colombier if(na >= max)
11407dd7cddfSDavid du Colombier break;
11417dd7cddfSDavid du Colombier }
11427dd7cddfSDavid du Colombier }
11437dd7cddfSDavid du Colombier }
11447dd7cddfSDavid du Colombier return na;
11457dd7cddfSDavid du Colombier }
11467dd7cddfSDavid du Colombier
11477dd7cddfSDavid du Colombier Message*
mesglookup(Message * mbox,char * name,char * digest)11487dd7cddfSDavid du Colombier mesglookup(Message *mbox, char *name, char *digest)
11497dd7cddfSDavid du Colombier {
11507dd7cddfSDavid du Colombier int n;
11517dd7cddfSDavid du Colombier Message *m;
11527dd7cddfSDavid du Colombier char *t;
11537dd7cddfSDavid du Colombier
11547dd7cddfSDavid du Colombier if(digest){
11557dd7cddfSDavid du Colombier /* can find exactly */
11567dd7cddfSDavid du Colombier for(m=mbox->head; m!=nil; m=m->next)
11577dd7cddfSDavid du Colombier if(strcmp(digest, m->digest) == 0)
11587dd7cddfSDavid du Colombier break;
11597dd7cddfSDavid du Colombier return m;
11607dd7cddfSDavid du Colombier }
11617dd7cddfSDavid du Colombier
11627dd7cddfSDavid du Colombier n = strlen(name);
11637dd7cddfSDavid du Colombier if(n == 0)
11647dd7cddfSDavid du Colombier return nil;
11657dd7cddfSDavid du Colombier if(name[n-1] == '/')
11667dd7cddfSDavid du Colombier t = estrdup(name);
11677dd7cddfSDavid du Colombier else
11687dd7cddfSDavid du Colombier t = estrstrdup(name, "/");
11697dd7cddfSDavid du Colombier for(m=mbox->head; m!=nil; m=m->next)
11707dd7cddfSDavid du Colombier if(strcmp(t, m->name) == 0)
11717dd7cddfSDavid du Colombier break;
11727dd7cddfSDavid du Colombier free(t);
11737dd7cddfSDavid du Colombier return m;
11747dd7cddfSDavid du Colombier }
11757dd7cddfSDavid du Colombier
11769a747e4fSDavid du Colombier /*
11779a747e4fSDavid du Colombier * Find plumb port, knowing type is text, given file name (by extension)
11789a747e4fSDavid du Colombier */
11797dd7cddfSDavid du Colombier int
plumbportbysuffix(char * file)11809a747e4fSDavid du Colombier plumbportbysuffix(char *file)
11819a747e4fSDavid du Colombier {
11829a747e4fSDavid du Colombier char *suf;
11839a747e4fSDavid du Colombier int i, nsuf, nfile;
11849a747e4fSDavid du Colombier
11859a747e4fSDavid du Colombier nfile = strlen(file);
11869a747e4fSDavid du Colombier for(i=0; ports[i].type!=nil; i++){
11879a747e4fSDavid du Colombier suf = ports[i].suffix;
11889a747e4fSDavid du Colombier nsuf = strlen(suf);
11899a747e4fSDavid du Colombier if(nfile > nsuf)
11909a747e4fSDavid du Colombier if(cistrncmp(file+nfile-nsuf, suf, nsuf) == 0)
11919a747e4fSDavid du Colombier return i;
11929a747e4fSDavid du Colombier }
11939a747e4fSDavid du Colombier return 0;
11949a747e4fSDavid du Colombier }
11959a747e4fSDavid du Colombier
11969a747e4fSDavid du Colombier /*
11979a747e4fSDavid du Colombier * Find plumb port using type and file name (by extension)
11989a747e4fSDavid du Colombier */
11999a747e4fSDavid du Colombier int
plumbport(char * type,char * file)12009a747e4fSDavid du Colombier plumbport(char *type, char *file)
12017dd7cddfSDavid du Colombier {
12027dd7cddfSDavid du Colombier int i;
12037dd7cddfSDavid du Colombier
12047dd7cddfSDavid du Colombier for(i=0; ports[i].type!=nil; i++)
12059a747e4fSDavid du Colombier if(strncmp(type, ports[i].type, strlen(ports[i].type)) == 0)
12067dd7cddfSDavid du Colombier return i;
12077dd7cddfSDavid du Colombier /* see if it's a text type */
12087dd7cddfSDavid du Colombier for(i=0; goodtypes[i]!=nil; i++)
12099a747e4fSDavid du Colombier if(strncmp(type, goodtypes[i], strlen(goodtypes[i])) == 0)
12109a747e4fSDavid du Colombier return plumbportbysuffix(file);
12117dd7cddfSDavid du Colombier return -1;
12127dd7cddfSDavid du Colombier }
12137dd7cddfSDavid du Colombier
12147dd7cddfSDavid du Colombier void
plumb(Message * m,char * dir)12157dd7cddfSDavid du Colombier plumb(Message *m, char *dir)
12167dd7cddfSDavid du Colombier {
12177dd7cddfSDavid du Colombier int i;
12187dd7cddfSDavid du Colombier char *port;
12197dd7cddfSDavid du Colombier Plumbmsg *pm;
12207dd7cddfSDavid du Colombier
12217dd7cddfSDavid du Colombier if(strlen(m->type) == 0)
12227dd7cddfSDavid du Colombier return;
12239a747e4fSDavid du Colombier i = plumbport(m->type, m->filename);
12247dd7cddfSDavid du Colombier if(i < 0)
12259a747e4fSDavid du Colombier fprint(2, "can't find destination for message subpart\n");
12267dd7cddfSDavid du Colombier else{
12277dd7cddfSDavid du Colombier port = ports[i].port;
12287dd7cddfSDavid du Colombier pm = emalloc(sizeof(Plumbmsg));
12297dd7cddfSDavid du Colombier pm->src = estrdup("Mail");
12307dd7cddfSDavid du Colombier if(port)
12317dd7cddfSDavid du Colombier pm->dst = estrdup(port);
12327dd7cddfSDavid du Colombier else
12337dd7cddfSDavid du Colombier pm->dst = nil;
12347dd7cddfSDavid du Colombier pm->wdir = nil;
12357dd7cddfSDavid du Colombier pm->type = estrdup("text");
12367dd7cddfSDavid du Colombier pm->ndata = -1;
12377dd7cddfSDavid du Colombier pm->data = estrstrdup(dir, "body");
12389a747e4fSDavid du Colombier pm->data = eappend(pm->data, "", ports[i].suffix);
12397dd7cddfSDavid du Colombier if(plumbsend(plumbsendfd, pm) < 0)
12409a747e4fSDavid du Colombier fprint(2, "error writing plumb message: %r\n");
12417dd7cddfSDavid du Colombier plumbfree(pm);
12427dd7cddfSDavid du Colombier }
12437dd7cddfSDavid du Colombier }
12447dd7cddfSDavid du Colombier
12457dd7cddfSDavid du Colombier int
mesgopen(Message * mbox,char * dir,char * s,Message * mesg,int plumbed,char * digest)12467dd7cddfSDavid du Colombier mesgopen(Message *mbox, char *dir, char *s, Message *mesg, int plumbed, char *digest)
12477dd7cddfSDavid du Colombier {
12487dd7cddfSDavid du Colombier char *t, *u, *v;
12497dd7cddfSDavid du Colombier Message *m;
12507dd7cddfSDavid du Colombier char *direlem[10];
12519a747e4fSDavid du Colombier int i, ndirelem, reuse;
12527dd7cddfSDavid du Colombier
12537dd7cddfSDavid du Colombier /* find white-space-delimited first word */
12547dd7cddfSDavid du Colombier for(t=s; *t!='\0' && !isspace(*t); t++)
12557dd7cddfSDavid du Colombier ;
12567dd7cddfSDavid du Colombier u = emalloc(t-s+1);
12577dd7cddfSDavid du Colombier memmove(u, s, t-s);
12587dd7cddfSDavid du Colombier /* separate it on slashes */
12597dd7cddfSDavid du Colombier ndirelem = tokenizec(u, direlem, nelem(direlem), "/");
12607dd7cddfSDavid du Colombier if(ndirelem <= 0){
12617dd7cddfSDavid du Colombier Error:
12627dd7cddfSDavid du Colombier free(u);
12637dd7cddfSDavid du Colombier return 0;
12647dd7cddfSDavid du Colombier }
12657dd7cddfSDavid du Colombier if(plumbed){
12667dd7cddfSDavid du Colombier write(wctlfd, "top", 3);
12677dd7cddfSDavid du Colombier write(wctlfd, "current", 7);
12687dd7cddfSDavid du Colombier }
12697dd7cddfSDavid du Colombier /* open window for message */
12707dd7cddfSDavid du Colombier m = mesglookup(mbox, direlem[0], digest);
12717dd7cddfSDavid du Colombier if(m == nil)
12727dd7cddfSDavid du Colombier goto Error;
12737dd7cddfSDavid du Colombier if(mesg!=nil && m!=mesg) /* string looked like subpart but isn't part of this message */
12747dd7cddfSDavid du Colombier goto Error;
12757dd7cddfSDavid du Colombier if(m->opened == 0){
12769a747e4fSDavid du Colombier if(m->w == nil){
12779a747e4fSDavid du Colombier reuse = 0;
12787dd7cddfSDavid du Colombier m->w = newwindow();
12799a747e4fSDavid du Colombier }else{
12809a747e4fSDavid du Colombier reuse = 1;
12819a747e4fSDavid du Colombier /* re-use existing window */
12829a747e4fSDavid du Colombier if(winsetaddr(m->w, "0,$", 1)){
12839a747e4fSDavid du Colombier if(m->w->data < 0)
12849a747e4fSDavid du Colombier m->w->data = winopenfile(m->w, "data");
12859a747e4fSDavid du Colombier write(m->w->data, "", 0);
12869a747e4fSDavid du Colombier }
12879a747e4fSDavid du Colombier }
12887dd7cddfSDavid du Colombier v = estrstrdup(mbox->name, m->name);
12897dd7cddfSDavid du Colombier winname(m->w, v);
12907dd7cddfSDavid du Colombier free(v);
12919a747e4fSDavid du Colombier if(!reuse){
12927dd7cddfSDavid du Colombier if(m->deleted)
12939a747e4fSDavid du Colombier wintagwrite(m->w, "Q Reply all UnDelmesg Save ", 2+6+4+10+5);
12947dd7cddfSDavid du Colombier else
12959a747e4fSDavid du Colombier wintagwrite(m->w, "Q Reply all Delmesg Save ", 2+6+4+8+5);
12969a747e4fSDavid du Colombier }
12977dd7cddfSDavid du Colombier threadcreate(mesgctl, m, STACK);
12987dd7cddfSDavid du Colombier winopenbody(m->w, OWRITE);
12997dd7cddfSDavid du Colombier mesgload(m, dir, m->name, m->w);
13007dd7cddfSDavid du Colombier winclosebody(m->w);
13017dd7cddfSDavid du Colombier winclean(m->w);
13027dd7cddfSDavid du Colombier m->opened = 1;
13037dd7cddfSDavid du Colombier if(ndirelem == 1){
13047dd7cddfSDavid du Colombier free(u);
13057dd7cddfSDavid du Colombier return 1;
13067dd7cddfSDavid du Colombier }
13077dd7cddfSDavid du Colombier }
13089a747e4fSDavid du Colombier if(ndirelem == 1 && plumbport(m->type, m->filename) <= 0){
13097dd7cddfSDavid du Colombier /* make sure dot is visible */
13107dd7cddfSDavid du Colombier ctlprint(m->w->ctl, "show\n");
13117dd7cddfSDavid du Colombier return 0;
13127dd7cddfSDavid du Colombier }
13137dd7cddfSDavid du Colombier /* walk to subpart */
13147dd7cddfSDavid du Colombier dir = estrstrdup(dir, m->name);
13157dd7cddfSDavid du Colombier for(i=1; i<ndirelem; i++){
13167dd7cddfSDavid du Colombier m = mesglookup(m, direlem[i], digest);
13177dd7cddfSDavid du Colombier if(m == nil)
13187dd7cddfSDavid du Colombier break;
13197dd7cddfSDavid du Colombier dir = egrow(dir, m->name, nil);
13207dd7cddfSDavid du Colombier }
13219a747e4fSDavid du Colombier if(m != nil && plumbport(m->type, m->filename) > 0)
13227dd7cddfSDavid du Colombier plumb(m, dir);
13237dd7cddfSDavid du Colombier free(dir);
13247dd7cddfSDavid du Colombier free(u);
13257dd7cddfSDavid du Colombier return 1;
13267dd7cddfSDavid du Colombier }
13277dd7cddfSDavid du Colombier
13287dd7cddfSDavid du Colombier void
rewritembox(Window * w,Message * mbox)13297dd7cddfSDavid du Colombier rewritembox(Window *w, Message *mbox)
13307dd7cddfSDavid du Colombier {
13317dd7cddfSDavid du Colombier Message *m, *next;
13327dd7cddfSDavid du Colombier char *deletestr, *t;
13337dd7cddfSDavid du Colombier int nopen;
13347dd7cddfSDavid du Colombier
133580ee5cbfSDavid du Colombier deletestr = estrstrdup("delete ", fsname);
13367dd7cddfSDavid du Colombier
13377dd7cddfSDavid du Colombier nopen = 0;
13387dd7cddfSDavid du Colombier for(m=mbox->head; m!=nil; m=next){
13397dd7cddfSDavid du Colombier next = m->next;
13407dd7cddfSDavid du Colombier if(m->deleted == 0)
13417dd7cddfSDavid du Colombier continue;
13427dd7cddfSDavid du Colombier if(m->opened){
13437dd7cddfSDavid du Colombier nopen++;
13447dd7cddfSDavid du Colombier continue;
13457dd7cddfSDavid du Colombier }
13467dd7cddfSDavid du Colombier if(m->writebackdel){
13477dd7cddfSDavid du Colombier /* messages deleted by plumb message are not removed again */
13487dd7cddfSDavid du Colombier t = estrdup(m->name);
13497dd7cddfSDavid du Colombier if(strlen(t) > 0)
13507dd7cddfSDavid du Colombier t[strlen(t)-1] = '\0';
13517dd7cddfSDavid du Colombier deletestr = egrow(deletestr, " ", t);
13527dd7cddfSDavid du Colombier }
13537dd7cddfSDavid du Colombier mesgmenudel(w, mbox, m);
13547dd7cddfSDavid du Colombier mesgdel(mbox, m);
13557dd7cddfSDavid du Colombier }
13567dd7cddfSDavid du Colombier if(write(mbox->ctlfd, deletestr, strlen(deletestr)) < 0)
13579a747e4fSDavid du Colombier fprint(2, "Mail: warning: error removing mail message files: %r\n");
13587dd7cddfSDavid du Colombier free(deletestr);
13597dd7cddfSDavid du Colombier winselect(w, "0", 0);
13607dd7cddfSDavid du Colombier if(nopen == 0)
13617dd7cddfSDavid du Colombier winclean(w);
13627dd7cddfSDavid du Colombier mbox->dirty = 0;
13637dd7cddfSDavid du Colombier }
13647dd7cddfSDavid du Colombier
13657dd7cddfSDavid du Colombier /* name is a full file name, but it might not belong to us */
13667dd7cddfSDavid du Colombier Message*
mesglookupfile(Message * mbox,char * name,char * digest)13677dd7cddfSDavid du Colombier mesglookupfile(Message *mbox, char *name, char *digest)
13687dd7cddfSDavid du Colombier {
13697dd7cddfSDavid du Colombier int k, n;
13707dd7cddfSDavid du Colombier
13717dd7cddfSDavid du Colombier k = strlen(name);
13727dd7cddfSDavid du Colombier n = strlen(mbox->name);
13737dd7cddfSDavid du Colombier if(k==0 || strncmp(name, mbox->name, n) != 0){
13749a747e4fSDavid du Colombier // fprint(2, "Mail: message %s not in this mailbox\n", name);
13757dd7cddfSDavid du Colombier return nil;
13767dd7cddfSDavid du Colombier }
13777dd7cddfSDavid du Colombier return mesglookup(mbox, name+n, digest);
13787dd7cddfSDavid du Colombier }
1379