17dd7cddfSDavid du Colombier #include "common.h" 27dd7cddfSDavid du Colombier #include <ctype.h> 37dd7cddfSDavid du Colombier #include <plumb.h> 47dd7cddfSDavid du Colombier #include <libsec.h> 57dd7cddfSDavid du Colombier #include "dat.h" 67dd7cddfSDavid du Colombier 77dd7cddfSDavid du Colombier typedef struct Header Header; 87dd7cddfSDavid du Colombier 97dd7cddfSDavid du Colombier struct Header { 107dd7cddfSDavid du Colombier char *type; 117dd7cddfSDavid du Colombier void (*f)(Message*, Header*, char*); 127dd7cddfSDavid du Colombier int len; 137dd7cddfSDavid du Colombier }; 147dd7cddfSDavid du Colombier 157dd7cddfSDavid du Colombier /* headers */ 167dd7cddfSDavid du Colombier static void ctype(Message*, Header*, char*); 177dd7cddfSDavid du Colombier static void cencoding(Message*, Header*, char*); 187dd7cddfSDavid du Colombier static void cdisposition(Message*, Header*, char*); 197dd7cddfSDavid du Colombier static void date822(Message*, Header*, char*); 207dd7cddfSDavid du Colombier static void from822(Message*, Header*, char*); 217dd7cddfSDavid du Colombier static void to822(Message*, Header*, char*); 227dd7cddfSDavid du Colombier static void sender822(Message*, Header*, char*); 237dd7cddfSDavid du Colombier static void replyto822(Message*, Header*, char*); 247dd7cddfSDavid du Colombier static void subject822(Message*, Header*, char*); 257dd7cddfSDavid du Colombier static void inreplyto822(Message*, Header*, char*); 267dd7cddfSDavid du Colombier static void cc822(Message*, Header*, char*); 277dd7cddfSDavid du Colombier static void bcc822(Message*, Header*, char*); 287dd7cddfSDavid du Colombier static void messageid822(Message*, Header*, char*); 297dd7cddfSDavid du Colombier static void mimeversion(Message*, Header*, char*); 307dd7cddfSDavid du Colombier 317dd7cddfSDavid du Colombier enum 327dd7cddfSDavid du Colombier { 337dd7cddfSDavid du Colombier Mhead= 11, /* offset of first mime header */ 347dd7cddfSDavid du Colombier }; 357dd7cddfSDavid du Colombier 367dd7cddfSDavid du Colombier Header head[] = 377dd7cddfSDavid du Colombier { 387dd7cddfSDavid du Colombier { "date:", date822, }, 397dd7cddfSDavid du Colombier { "from:", from822, }, 407dd7cddfSDavid du Colombier { "to:", to822, }, 417dd7cddfSDavid du Colombier { "sender:", sender822, }, 427dd7cddfSDavid du Colombier { "reply-to:", replyto822, }, 437dd7cddfSDavid du Colombier { "subject:", subject822, }, 447dd7cddfSDavid du Colombier { "cc:", cc822, }, 457dd7cddfSDavid du Colombier { "bcc:", bcc822, }, 467dd7cddfSDavid du Colombier { "in-reply-to:", inreplyto822, }, 477dd7cddfSDavid du Colombier { "mime-version:", mimeversion, }, 487dd7cddfSDavid du Colombier { "message-id:", messageid822, }, 497dd7cddfSDavid du Colombier 507dd7cddfSDavid du Colombier [Mhead] { "content-type:", ctype, }, 517dd7cddfSDavid du Colombier { "content-transfer-encoding:", cencoding, }, 527dd7cddfSDavid du Colombier { "content-disposition:", cdisposition, }, 537dd7cddfSDavid du Colombier { 0, }, 547dd7cddfSDavid du Colombier }; 557dd7cddfSDavid du Colombier 567dd7cddfSDavid du Colombier static void fatal(char *fmt, ...); 577dd7cddfSDavid du Colombier static void initquoted(void); 587dd7cddfSDavid du Colombier static void startheader(Message*); 597dd7cddfSDavid du Colombier static void startbody(Message*); 607dd7cddfSDavid du Colombier static char* skipwhite(char*); 617dd7cddfSDavid du Colombier static char* skiptosemi(char*); 627dd7cddfSDavid du Colombier static char* getstring(char*, String*, int); 637dd7cddfSDavid du Colombier static void setfilename(Message*, char*); 647dd7cddfSDavid du Colombier static char* lowercase(char*); 657dd7cddfSDavid du Colombier static int is8bit(Message*); 667dd7cddfSDavid du Colombier static int headerline(char**, String*); 677dd7cddfSDavid du Colombier static void initheaders(void); 687dd7cddfSDavid du Colombier static void parseattachments(Message*, Mailbox*); 697dd7cddfSDavid du Colombier 707dd7cddfSDavid du Colombier int debug; 719a747e4fSDavid du Colombier char stdmbox[Pathlen]; 7280ee5cbfSDavid du Colombier 7380ee5cbfSDavid du Colombier char *Enotme = "path not served by this file server"; 747dd7cddfSDavid du Colombier 757dd7cddfSDavid du Colombier enum 767dd7cddfSDavid du Colombier { 777dd7cddfSDavid du Colombier Chunksize = 1024, 787dd7cddfSDavid du Colombier }; 797dd7cddfSDavid du Colombier 8080ee5cbfSDavid du Colombier Mailboxinit *boxinit[] = { 8180ee5cbfSDavid du Colombier imap4mbox, 8280ee5cbfSDavid du Colombier pop3mbox, 8380ee5cbfSDavid du Colombier plan9mbox, 8480ee5cbfSDavid du Colombier }; 8580ee5cbfSDavid du Colombier 8680ee5cbfSDavid du Colombier char* 8780ee5cbfSDavid du Colombier syncmbox(Mailbox *mb, int doplumb) 8880ee5cbfSDavid du Colombier { 8980ee5cbfSDavid du Colombier return (*mb->sync)(mb, doplumb); 9080ee5cbfSDavid du Colombier } 9180ee5cbfSDavid du Colombier 927dd7cddfSDavid du Colombier /* create a new mailbox */ 937dd7cddfSDavid du Colombier char* 947dd7cddfSDavid du Colombier newmbox(char *path, char *name, int std) 957dd7cddfSDavid du Colombier { 967dd7cddfSDavid du Colombier Mailbox *mb, **l; 977dd7cddfSDavid du Colombier char *p, *rv; 9880ee5cbfSDavid du Colombier int i; 9980ee5cbfSDavid du Colombier 10080ee5cbfSDavid du Colombier initheaders(); 10180ee5cbfSDavid du Colombier 10280ee5cbfSDavid du Colombier if(stdmbox[0] == 0) 10380ee5cbfSDavid du Colombier snprint(stdmbox, sizeof(stdmbox), "/mail/box/%s/mbox", user); 1047dd7cddfSDavid du Colombier 1057dd7cddfSDavid du Colombier mb = emalloc(sizeof(*mb)); 1067dd7cddfSDavid du Colombier strncpy(mb->path, path, sizeof(mb->path)-1); 1077dd7cddfSDavid du Colombier if(name == nil){ 1087dd7cddfSDavid du Colombier p = strrchr(path, '/'); 1097dd7cddfSDavid du Colombier if(p == nil) 1107dd7cddfSDavid du Colombier p = path; 1117dd7cddfSDavid du Colombier else 1127dd7cddfSDavid du Colombier p++; 1137dd7cddfSDavid du Colombier if(*p == 0){ 1147dd7cddfSDavid du Colombier free(mb); 1157dd7cddfSDavid du Colombier return "bad mbox name"; 1167dd7cddfSDavid du Colombier } 1177dd7cddfSDavid du Colombier strncpy(mb->name, p, sizeof(mb->name)-1); 1187dd7cddfSDavid du Colombier } else { 1197dd7cddfSDavid du Colombier strncpy(mb->name, name, sizeof(mb->name)-1); 1207dd7cddfSDavid du Colombier } 1217dd7cddfSDavid du Colombier 12280ee5cbfSDavid du Colombier rv = nil; 12380ee5cbfSDavid du Colombier // check for a mailbox type 12480ee5cbfSDavid du Colombier for(i=0; i<nelem(boxinit); i++) 12580ee5cbfSDavid du Colombier if((rv = (*boxinit[i])(mb, path)) != Enotme) 12680ee5cbfSDavid du Colombier break; 12780ee5cbfSDavid du Colombier if(i == nelem(boxinit)){ 12880ee5cbfSDavid du Colombier free(mb); 12980ee5cbfSDavid du Colombier return "bad path"; 13080ee5cbfSDavid du Colombier } 13180ee5cbfSDavid du Colombier 13280ee5cbfSDavid du Colombier // on error, give up 133*5d459b5aSDavid du Colombier if(rv){ 134*5d459b5aSDavid du Colombier free(mb); 13580ee5cbfSDavid du Colombier return rv; 136*5d459b5aSDavid du Colombier } 13780ee5cbfSDavid du Colombier 1387dd7cddfSDavid du Colombier // make sure name isn't taken 1397dd7cddfSDavid du Colombier qlock(&mbllock); 14059cc4ca5SDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next){ 1417dd7cddfSDavid du Colombier if(strcmp((*l)->name, mb->name) == 0){ 14259cc4ca5SDavid du Colombier if(strcmp(path, (*l)->path) == 0) 1437dd7cddfSDavid du Colombier rv = nil; 1447dd7cddfSDavid du Colombier else 1457dd7cddfSDavid du Colombier rv = "mbox name in use"; 14680ee5cbfSDavid du Colombier if(mb->close) 14780ee5cbfSDavid du Colombier (*mb->close)(mb); 1487dd7cddfSDavid du Colombier free(mb); 1497dd7cddfSDavid du Colombier qunlock(&mbllock); 1507dd7cddfSDavid du Colombier return rv; 1517dd7cddfSDavid du Colombier } 15259cc4ca5SDavid du Colombier } 15359cc4ca5SDavid du Colombier 15459cc4ca5SDavid du Colombier // all mailboxes in /mail/box/$user are locked using /mail/box/$user/mbox 15559cc4ca5SDavid du Colombier p = strrchr(stdmbox, '/'); 15659cc4ca5SDavid du Colombier mb->dolock = strncmp(mb->path, stdmbox, p - stdmbox) == 0; 15759cc4ca5SDavid du Colombier 1587dd7cddfSDavid du Colombier mb->refs = 1; 1597dd7cddfSDavid du Colombier mb->next = nil; 1607dd7cddfSDavid du Colombier mb->id = newid(); 1617dd7cddfSDavid du Colombier mb->root = newmessage(nil); 1627dd7cddfSDavid du Colombier mb->std = std; 1637dd7cddfSDavid du Colombier *l = mb; 1647dd7cddfSDavid du Colombier qunlock(&mbllock); 1657dd7cddfSDavid du Colombier 1667dd7cddfSDavid du Colombier qlock(mb); 16780ee5cbfSDavid du Colombier if(mb->ctl){ 1689a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), "ctl", 1699a747e4fSDavid du Colombier (Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb); 17080ee5cbfSDavid du Colombier } 1717dd7cddfSDavid du Colombier rv = syncmbox(mb, 0); 1727dd7cddfSDavid du Colombier qunlock(mb); 1737dd7cddfSDavid du Colombier 1747dd7cddfSDavid du Colombier return rv; 1757dd7cddfSDavid du Colombier } 1767dd7cddfSDavid du Colombier 1777dd7cddfSDavid du Colombier // close the named mailbox 1787dd7cddfSDavid du Colombier void 1797dd7cddfSDavid du Colombier freembox(char *name) 1807dd7cddfSDavid du Colombier { 181*5d459b5aSDavid du Colombier Mailbox **l, *mb; 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier qlock(&mbllock); 184*5d459b5aSDavid du Colombier for(l=&mbl; *l != nil; l=&(*l)->next){ 185*5d459b5aSDavid du Colombier if(strcmp(name, (*l)->name) == 0){ 186*5d459b5aSDavid du Colombier mb = *l; 187*5d459b5aSDavid du Colombier *l = mb->next; 1887dd7cddfSDavid du Colombier mboxdecref(mb); 1897dd7cddfSDavid du Colombier break; 1907dd7cddfSDavid du Colombier } 191*5d459b5aSDavid du Colombier } 1929a747e4fSDavid du Colombier hfree(PATH(0, Qtop), name); 1937dd7cddfSDavid du Colombier qunlock(&mbllock); 1947dd7cddfSDavid du Colombier } 1957dd7cddfSDavid du Colombier 1967dd7cddfSDavid du Colombier static void 1977dd7cddfSDavid du Colombier initheaders(void) 1987dd7cddfSDavid du Colombier { 1997dd7cddfSDavid du Colombier Header *h; 2007dd7cddfSDavid du Colombier static int already; 2017dd7cddfSDavid du Colombier 2027dd7cddfSDavid du Colombier if(already) 2037dd7cddfSDavid du Colombier return; 2047dd7cddfSDavid du Colombier already = 1; 2057dd7cddfSDavid du Colombier 2067dd7cddfSDavid du Colombier for(h = head; h->type != nil; h++) 2077dd7cddfSDavid du Colombier h->len = strlen(h->type); 2087dd7cddfSDavid du Colombier } 2097dd7cddfSDavid du Colombier 2107dd7cddfSDavid du Colombier /* 2117dd7cddfSDavid du Colombier * parse a Unix style header 2127dd7cddfSDavid du Colombier */ 21380ee5cbfSDavid du Colombier void 2147dd7cddfSDavid du Colombier parseunix(Message *m) 2157dd7cddfSDavid du Colombier { 2167dd7cddfSDavid du Colombier char *p; 2177dd7cddfSDavid du Colombier String *h; 2187dd7cddfSDavid du Colombier 2197dd7cddfSDavid du Colombier h = s_new(); 2207dd7cddfSDavid du Colombier for(p = m->start + 5; *p && *p != '\r' && *p != '\n'; p++) 2217dd7cddfSDavid du Colombier s_putc(h, *p); 2227dd7cddfSDavid du Colombier s_terminate(h); 2237dd7cddfSDavid du Colombier s_restart(h); 2247dd7cddfSDavid du Colombier 2257dd7cddfSDavid du Colombier m->unixfrom = s_parse(h, s_reset(m->unixfrom)); 2267dd7cddfSDavid du Colombier m->unixdate = s_append(s_reset(m->unixdate), h->ptr); 2277dd7cddfSDavid du Colombier 2287dd7cddfSDavid du Colombier s_free(h); 2297dd7cddfSDavid du Colombier } 2307dd7cddfSDavid du Colombier 2317dd7cddfSDavid du Colombier /* 2327dd7cddfSDavid du Colombier * parse a message 2337dd7cddfSDavid du Colombier */ 23480ee5cbfSDavid du Colombier void 23580ee5cbfSDavid du Colombier parseheaders(Message *m, int justmime, Mailbox *mb) 2367dd7cddfSDavid du Colombier { 2377dd7cddfSDavid du Colombier String *hl; 2387dd7cddfSDavid du Colombier Header *h; 23980ee5cbfSDavid du Colombier char *p, *q; 2407dd7cddfSDavid du Colombier int i; 2417dd7cddfSDavid du Colombier 2427dd7cddfSDavid du Colombier if(m->whole == m->whole->whole){ 2439a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), m->name, 2449a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2457dd7cddfSDavid du Colombier } else { 2469a747e4fSDavid du Colombier henter(PATH(m->whole->id, Qdir), m->name, 2479a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2487dd7cddfSDavid du Colombier } 2497dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 2509a747e4fSDavid du Colombier henter(PATH(m->id, Qdir), dirtab[i], 2519a747e4fSDavid du Colombier (Qid){PATH(m->id, i), 0, QTFILE}, m, mb); 2527dd7cddfSDavid du Colombier 2537dd7cddfSDavid du Colombier // parse mime headers 2547dd7cddfSDavid du Colombier p = m->header; 2557dd7cddfSDavid du Colombier hl = s_new(); 2567dd7cddfSDavid du Colombier while(headerline(&p, hl)){ 2577dd7cddfSDavid du Colombier if(justmime) 2587dd7cddfSDavid du Colombier h = &head[Mhead]; 2597dd7cddfSDavid du Colombier else 2607dd7cddfSDavid du Colombier h = head; 2617dd7cddfSDavid du Colombier for(; h->type; h++){ 2627dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(hl), h->type, h->len) == 0){ 2637dd7cddfSDavid du Colombier (*h->f)(m, h, s_to_c(hl)); 2647dd7cddfSDavid du Colombier break; 2657dd7cddfSDavid du Colombier } 2667dd7cddfSDavid du Colombier } 2677dd7cddfSDavid du Colombier s_reset(hl); 2687dd7cddfSDavid du Colombier } 2697dd7cddfSDavid du Colombier s_free(hl); 2707dd7cddfSDavid du Colombier 2717dd7cddfSDavid du Colombier // the blank line isn't really part of the body or header 2727dd7cddfSDavid du Colombier if(justmime){ 2737dd7cddfSDavid du Colombier m->mhend = p; 2747dd7cddfSDavid du Colombier m->hend = m->header; 2757dd7cddfSDavid du Colombier } else { 2767dd7cddfSDavid du Colombier m->hend = p; 2777dd7cddfSDavid du Colombier } 2787dd7cddfSDavid du Colombier if(*p == '\n') 2797dd7cddfSDavid du Colombier p++; 2807dd7cddfSDavid du Colombier m->rbody = m->body = p; 2817dd7cddfSDavid du Colombier 28280ee5cbfSDavid du Colombier // 28380ee5cbfSDavid du Colombier // cobble together Unix-style from line 28480ee5cbfSDavid du Colombier // for local mailbox messages, we end up recreating the 28580ee5cbfSDavid du Colombier // original header. 28680ee5cbfSDavid du Colombier // for pop3 messages, the best we can do is 28780ee5cbfSDavid du Colombier // use the From: information and the RFC822 date. 28880ee5cbfSDavid du Colombier // 28980ee5cbfSDavid du Colombier if(m->unixdate == nil){ 29080ee5cbfSDavid du Colombier // look for the date in the first Received: line. 29180ee5cbfSDavid du Colombier // it's likely to be the right time zone (it's 29280ee5cbfSDavid du Colombier // the local system) and in a convenient format. 29380ee5cbfSDavid du Colombier if(cistrncmp(m->header, "received:", 9)==0){ 29480ee5cbfSDavid du Colombier if((q = strchr(m->header, ';')) 29580ee5cbfSDavid du Colombier && (p = strchr(q, '\n'))){ 29680ee5cbfSDavid du Colombier *p = '\0'; 29780ee5cbfSDavid du Colombier m->unixdate = date822tounix(q+1); 29880ee5cbfSDavid du Colombier *p = '\n'; 29980ee5cbfSDavid du Colombier } 30080ee5cbfSDavid du Colombier } 30180ee5cbfSDavid du Colombier 30280ee5cbfSDavid du Colombier // fall back on the rfc822 date 30380ee5cbfSDavid du Colombier if(m->unixdate==nil && m->date822) 30480ee5cbfSDavid du Colombier m->unixdate = date822tounix(s_to_c(m->date822)); 30580ee5cbfSDavid du Colombier } 30680ee5cbfSDavid du Colombier 3079a747e4fSDavid du Colombier if(m->unixheader != nil) 3089a747e4fSDavid du Colombier s_free(m->unixheader); 30980ee5cbfSDavid du Colombier m->unixheader = s_copy("From "); 31080ee5cbfSDavid du Colombier if(m->unixfrom) 31180ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixfrom)); 31280ee5cbfSDavid du Colombier else if(m->from822) 31380ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->from822)); 31480ee5cbfSDavid du Colombier else 31580ee5cbfSDavid du Colombier s_append(m->unixheader, "???"); 31680ee5cbfSDavid du Colombier 31780ee5cbfSDavid du Colombier s_append(m->unixheader, " "); 31880ee5cbfSDavid du Colombier if(m->unixdate) 31980ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixdate)); 32080ee5cbfSDavid du Colombier else 32180ee5cbfSDavid du Colombier s_append(m->unixheader, "Thu Jan 1 00:00:00 EST 1970"); 32280ee5cbfSDavid du Colombier 32380ee5cbfSDavid du Colombier s_append(m->unixheader, "\n"); 32480ee5cbfSDavid du Colombier } 32580ee5cbfSDavid du Colombier 3269a747e4fSDavid du Colombier String* 3279a747e4fSDavid du Colombier promote(String **sp) 3289a747e4fSDavid du Colombier { 3299a747e4fSDavid du Colombier String *s; 3309a747e4fSDavid du Colombier 3319a747e4fSDavid du Colombier if(*sp != nil) 3329a747e4fSDavid du Colombier s = s_clone(*sp); 3339a747e4fSDavid du Colombier else 3349a747e4fSDavid du Colombier s = nil; 3359a747e4fSDavid du Colombier return s; 3369a747e4fSDavid du Colombier } 3379a747e4fSDavid du Colombier 33880ee5cbfSDavid du Colombier void 33980ee5cbfSDavid du Colombier parsebody(Message *m, Mailbox *mb) 34080ee5cbfSDavid du Colombier { 3419a747e4fSDavid du Colombier Message *nm; 3429a747e4fSDavid du Colombier 3437dd7cddfSDavid du Colombier // recurse 3447dd7cddfSDavid du Colombier if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){ 3457dd7cddfSDavid du Colombier parseattachments(m, mb); 3467dd7cddfSDavid du Colombier } else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 3477dd7cddfSDavid du Colombier decode(m); 3487dd7cddfSDavid du Colombier parseattachments(m, mb); 3499a747e4fSDavid du Colombier nm = m->part; 3509a747e4fSDavid du Colombier 3519a747e4fSDavid du Colombier // promote headers 352*5d459b5aSDavid du Colombier if(m->replyto822 == nil && m->from822 == nil && m->sender822 == nil){ 3539a747e4fSDavid du Colombier m->from822 = promote(&nm->from822); 3549a747e4fSDavid du Colombier m->to822 = promote(&nm->to822); 3559a747e4fSDavid du Colombier m->date822 = promote(&nm->date822); 3569a747e4fSDavid du Colombier m->sender822 = promote(&nm->sender822); 3579a747e4fSDavid du Colombier m->replyto822 = promote(&nm->replyto822); 3589a747e4fSDavid du Colombier m->subject822 = promote(&nm->subject822); 3599a747e4fSDavid du Colombier m->unixdate = promote(&nm->unixdate); 3607dd7cddfSDavid du Colombier } 3617dd7cddfSDavid du Colombier } 362*5d459b5aSDavid du Colombier } 3637dd7cddfSDavid du Colombier 36480ee5cbfSDavid du Colombier void 36580ee5cbfSDavid du Colombier parse(Message *m, int justmime, Mailbox *mb) 36680ee5cbfSDavid du Colombier { 36780ee5cbfSDavid du Colombier parseheaders(m, justmime, mb); 36880ee5cbfSDavid du Colombier parsebody(m, mb); 36980ee5cbfSDavid du Colombier } 37080ee5cbfSDavid du Colombier 3717dd7cddfSDavid du Colombier static void 3727dd7cddfSDavid du Colombier parseattachments(Message *m, Mailbox *mb) 3737dd7cddfSDavid du Colombier { 3747dd7cddfSDavid du Colombier Message *nm, **l; 3757dd7cddfSDavid du Colombier char *p, *x; 3767dd7cddfSDavid du Colombier 3777dd7cddfSDavid du Colombier // if there's a boundary, recurse... 3787dd7cddfSDavid du Colombier if(m->boundary != nil){ 3797dd7cddfSDavid du Colombier p = m->body; 3807dd7cddfSDavid du Colombier nm = nil; 3817dd7cddfSDavid du Colombier l = &m->part; 3827dd7cddfSDavid du Colombier for(;;){ 3837dd7cddfSDavid du Colombier x = strstr(p, s_to_c(m->boundary)); 3847dd7cddfSDavid du Colombier if(x == nil || (x != m->body && *(x-1) != '\n')){ 3857dd7cddfSDavid du Colombier if(nm != nil) 3867dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = m->bend; 3877dd7cddfSDavid du Colombier break; 3887dd7cddfSDavid du Colombier } 3897dd7cddfSDavid du Colombier if(nm != nil) 3907dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = x; 3917dd7cddfSDavid du Colombier x += strlen(s_to_c(m->boundary)); 3927dd7cddfSDavid du Colombier 3937dd7cddfSDavid du Colombier /* is this the last part? ignore anything after it */ 3947dd7cddfSDavid du Colombier if(strncmp(x, "--", 2) == 0) 3957dd7cddfSDavid du Colombier break; 3967dd7cddfSDavid du Colombier 3977dd7cddfSDavid du Colombier p = strchr(x, '\n'); 3987dd7cddfSDavid du Colombier if(p == nil) 3997dd7cddfSDavid du Colombier break; 4007dd7cddfSDavid du Colombier nm = newmessage(m); 4017dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = ++p; 4027dd7cddfSDavid du Colombier nm->mheader = nm->header; 4037dd7cddfSDavid du Colombier *l = nm; 4047dd7cddfSDavid du Colombier l = &nm->next; 4057dd7cddfSDavid du Colombier } 4067dd7cddfSDavid du Colombier for(nm = m->part; nm != nil; nm = nm->next) 4077dd7cddfSDavid du Colombier parse(nm, 1, mb); 4089a747e4fSDavid du Colombier return; 4097dd7cddfSDavid du Colombier } 4109a747e4fSDavid du Colombier 4119a747e4fSDavid du Colombier // if we've got an rfc822 message, recurse... 4129a747e4fSDavid du Colombier if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 4137dd7cddfSDavid du Colombier nm = newmessage(m); 4147dd7cddfSDavid du Colombier m->part = nm; 4157dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = m->body; 4167dd7cddfSDavid du Colombier nm->end = nm->bend = nm->rbend = m->bend; 4177dd7cddfSDavid du Colombier parse(nm, 0, mb); 4187dd7cddfSDavid du Colombier } 4197dd7cddfSDavid du Colombier } 4207dd7cddfSDavid du Colombier 4217dd7cddfSDavid du Colombier /* 4227dd7cddfSDavid du Colombier * pick up a header line 4237dd7cddfSDavid du Colombier */ 4247dd7cddfSDavid du Colombier static int 4257dd7cddfSDavid du Colombier headerline(char **pp, String *hl) 4267dd7cddfSDavid du Colombier { 4277dd7cddfSDavid du Colombier char *p, *x; 4287dd7cddfSDavid du Colombier 4297dd7cddfSDavid du Colombier s_reset(hl); 4307dd7cddfSDavid du Colombier p = *pp; 4317dd7cddfSDavid du Colombier x = strpbrk(p, ":\n"); 4327dd7cddfSDavid du Colombier if(x == nil || *x == '\n') 4337dd7cddfSDavid du Colombier return 0; 4347dd7cddfSDavid du Colombier for(;;){ 4357dd7cddfSDavid du Colombier x = strchr(p, '\n'); 4367dd7cddfSDavid du Colombier if(x == nil) 4377dd7cddfSDavid du Colombier x = p + strlen(p); 4387dd7cddfSDavid du Colombier s_nappend(hl, p, x-p); 4397dd7cddfSDavid du Colombier p = x; 440223a736eSDavid du Colombier if(*p != '\n' || *++p != ' ' && *p != '\t') 4417dd7cddfSDavid du Colombier break; 442223a736eSDavid du Colombier while(*p == ' ' || *p == '\t') 443223a736eSDavid du Colombier p++; 444223a736eSDavid du Colombier s_putc(hl, ' '); 4457dd7cddfSDavid du Colombier } 4467dd7cddfSDavid du Colombier *pp = p; 4477dd7cddfSDavid du Colombier return 1; 4487dd7cddfSDavid du Colombier } 4497dd7cddfSDavid du Colombier 4507dd7cddfSDavid du Colombier static String* 4517dd7cddfSDavid du Colombier addr822(char *p) 4527dd7cddfSDavid du Colombier { 4537dd7cddfSDavid du Colombier String *s, *list; 4547dd7cddfSDavid du Colombier int incomment, addrdone, inanticomment, quoted; 4557dd7cddfSDavid du Colombier int n; 4567dd7cddfSDavid du Colombier int c; 4577dd7cddfSDavid du Colombier 4587dd7cddfSDavid du Colombier list = s_new(); 4597dd7cddfSDavid du Colombier s = s_new(); 4607dd7cddfSDavid du Colombier quoted = incomment = addrdone = inanticomment = 0; 4617dd7cddfSDavid du Colombier n = 0; 4627dd7cddfSDavid du Colombier for(; *p; p++){ 4637dd7cddfSDavid du Colombier c = *p; 4647dd7cddfSDavid du Colombier 4657dd7cddfSDavid du Colombier // whitespace is ignored 4667dd7cddfSDavid du Colombier if(!quoted && isspace(c) || c == '\r') 4677dd7cddfSDavid du Colombier continue; 4687dd7cddfSDavid du Colombier 4697dd7cddfSDavid du Colombier // strings are always treated as atoms 4707dd7cddfSDavid du Colombier if(!quoted && c == '"'){ 4717dd7cddfSDavid du Colombier if(!addrdone && !incomment) 4727dd7cddfSDavid du Colombier s_putc(s, c); 4737dd7cddfSDavid du Colombier for(p++; *p; p++){ 4747dd7cddfSDavid du Colombier if(!addrdone && !incomment) 4757dd7cddfSDavid du Colombier s_putc(s, *p); 4767dd7cddfSDavid du Colombier if(!quoted && *p == '"') 4777dd7cddfSDavid du Colombier break; 4787dd7cddfSDavid du Colombier if(*p == '\\') 4797dd7cddfSDavid du Colombier quoted = 1; 4807dd7cddfSDavid du Colombier else 4817dd7cddfSDavid du Colombier quoted = 0; 4827dd7cddfSDavid du Colombier } 4837dd7cddfSDavid du Colombier if(*p == 0) 4847dd7cddfSDavid du Colombier break; 4857dd7cddfSDavid du Colombier quoted = 0; 4867dd7cddfSDavid du Colombier continue; 4877dd7cddfSDavid du Colombier } 4887dd7cddfSDavid du Colombier 4897dd7cddfSDavid du Colombier // ignore everything in an expicit comment 4907dd7cddfSDavid du Colombier if(!quoted && c == '('){ 4917dd7cddfSDavid du Colombier incomment = 1; 4927dd7cddfSDavid du Colombier continue; 4937dd7cddfSDavid du Colombier } 4947dd7cddfSDavid du Colombier if(incomment){ 4957dd7cddfSDavid du Colombier if(!quoted && c == ')') 4967dd7cddfSDavid du Colombier incomment = 0; 4977dd7cddfSDavid du Colombier quoted = 0; 4987dd7cddfSDavid du Colombier continue; 4997dd7cddfSDavid du Colombier } 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier // anticomments makes everything outside of them comments 5027dd7cddfSDavid du Colombier if(!quoted && c == '<' && !inanticomment){ 5037dd7cddfSDavid du Colombier inanticomment = 1; 5047dd7cddfSDavid du Colombier s = s_reset(s); 5057dd7cddfSDavid du Colombier continue; 5067dd7cddfSDavid du Colombier } 5077dd7cddfSDavid du Colombier if(!quoted && c == '>' && inanticomment){ 5087dd7cddfSDavid du Colombier addrdone = 1; 5097dd7cddfSDavid du Colombier inanticomment = 0; 5107dd7cddfSDavid du Colombier continue; 5117dd7cddfSDavid du Colombier } 5127dd7cddfSDavid du Colombier 5137dd7cddfSDavid du Colombier // commas separate addresses 5147dd7cddfSDavid du Colombier if(!quoted && c == ',' && !inanticomment){ 5157dd7cddfSDavid du Colombier s_terminate(s); 5167dd7cddfSDavid du Colombier addrdone = 0; 5177dd7cddfSDavid du Colombier if(n++ != 0) 5187dd7cddfSDavid du Colombier s_append(list, " "); 5197dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5207dd7cddfSDavid du Colombier s = s_reset(s); 5217dd7cddfSDavid du Colombier continue; 5227dd7cddfSDavid du Colombier } 5237dd7cddfSDavid du Colombier 5247dd7cddfSDavid du Colombier // what's left is part of the address 5257dd7cddfSDavid du Colombier s_putc(s, c); 5267dd7cddfSDavid du Colombier 5277dd7cddfSDavid du Colombier // quoted characters are recognized only as characters 5287dd7cddfSDavid du Colombier if(c == '\\') 5297dd7cddfSDavid du Colombier quoted = 1; 5307dd7cddfSDavid du Colombier else 5317dd7cddfSDavid du Colombier quoted = 0; 5327dd7cddfSDavid du Colombier 5337dd7cddfSDavid du Colombier } 5347dd7cddfSDavid du Colombier 5357dd7cddfSDavid du Colombier if(*s_to_c(s) != 0){ 5367dd7cddfSDavid du Colombier s_terminate(s); 5377dd7cddfSDavid du Colombier if(n++ != 0) 5387dd7cddfSDavid du Colombier s_append(list, " "); 5397dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5407dd7cddfSDavid du Colombier } 5417dd7cddfSDavid du Colombier s_free(s); 5427dd7cddfSDavid du Colombier 5437dd7cddfSDavid du Colombier if(n == 0){ 5447dd7cddfSDavid du Colombier s_free(list); 5457dd7cddfSDavid du Colombier return nil; 5467dd7cddfSDavid du Colombier } 5477dd7cddfSDavid du Colombier return list; 5487dd7cddfSDavid du Colombier } 5497dd7cddfSDavid du Colombier 5507dd7cddfSDavid du Colombier static void 5517dd7cddfSDavid du Colombier to822(Message *m, Header *h, char *p) 5527dd7cddfSDavid du Colombier { 5537dd7cddfSDavid du Colombier p += strlen(h->type); 5547dd7cddfSDavid du Colombier s_free(m->to822); 5557dd7cddfSDavid du Colombier m->to822 = addr822(p); 5567dd7cddfSDavid du Colombier } 5577dd7cddfSDavid du Colombier 5587dd7cddfSDavid du Colombier static void 5597dd7cddfSDavid du Colombier cc822(Message *m, Header *h, char *p) 5607dd7cddfSDavid du Colombier { 5617dd7cddfSDavid du Colombier p += strlen(h->type); 5627dd7cddfSDavid du Colombier s_free(m->cc822); 5637dd7cddfSDavid du Colombier m->cc822 = addr822(p); 5647dd7cddfSDavid du Colombier } 5657dd7cddfSDavid du Colombier 5667dd7cddfSDavid du Colombier static void 5677dd7cddfSDavid du Colombier bcc822(Message *m, Header *h, char *p) 5687dd7cddfSDavid du Colombier { 5697dd7cddfSDavid du Colombier p += strlen(h->type); 5707dd7cddfSDavid du Colombier s_free(m->bcc822); 5717dd7cddfSDavid du Colombier m->bcc822 = addr822(p); 5727dd7cddfSDavid du Colombier } 5737dd7cddfSDavid du Colombier 5747dd7cddfSDavid du Colombier static void 5757dd7cddfSDavid du Colombier from822(Message *m, Header *h, char *p) 5767dd7cddfSDavid du Colombier { 5777dd7cddfSDavid du Colombier p += strlen(h->type); 5787dd7cddfSDavid du Colombier s_free(m->from822); 5797dd7cddfSDavid du Colombier m->from822 = addr822(p); 5807dd7cddfSDavid du Colombier } 5817dd7cddfSDavid du Colombier 5827dd7cddfSDavid du Colombier static void 5837dd7cddfSDavid du Colombier sender822(Message *m, Header *h, char *p) 5847dd7cddfSDavid du Colombier { 5857dd7cddfSDavid du Colombier p += strlen(h->type); 5867dd7cddfSDavid du Colombier s_free(m->sender822); 5877dd7cddfSDavid du Colombier m->sender822 = addr822(p); 5887dd7cddfSDavid du Colombier } 5897dd7cddfSDavid du Colombier 5907dd7cddfSDavid du Colombier static void 5917dd7cddfSDavid du Colombier replyto822(Message *m, Header *h, char *p) 5927dd7cddfSDavid du Colombier { 5937dd7cddfSDavid du Colombier p += strlen(h->type); 5947dd7cddfSDavid du Colombier s_free(m->replyto822); 5957dd7cddfSDavid du Colombier m->replyto822 = addr822(p); 5967dd7cddfSDavid du Colombier } 5977dd7cddfSDavid du Colombier 5987dd7cddfSDavid du Colombier static void 5997dd7cddfSDavid du Colombier mimeversion(Message *m, Header *h, char *p) 6007dd7cddfSDavid du Colombier { 6017dd7cddfSDavid du Colombier p += strlen(h->type); 6027dd7cddfSDavid du Colombier s_free(m->mimeversion); 6037dd7cddfSDavid du Colombier m->mimeversion = addr822(p); 6047dd7cddfSDavid du Colombier } 6057dd7cddfSDavid du Colombier 6067dd7cddfSDavid du Colombier static void 6077dd7cddfSDavid du Colombier killtrailingwhite(char *p) 6087dd7cddfSDavid du Colombier { 6097dd7cddfSDavid du Colombier char *e; 6107dd7cddfSDavid du Colombier 6117dd7cddfSDavid du Colombier e = p + strlen(p) - 1; 6127dd7cddfSDavid du Colombier while(e > p && isspace(*e)) 6137dd7cddfSDavid du Colombier *e-- = 0; 6147dd7cddfSDavid du Colombier } 6157dd7cddfSDavid du Colombier 6167dd7cddfSDavid du Colombier static void 6177dd7cddfSDavid du Colombier date822(Message *m, Header *h, char *p) 6187dd7cddfSDavid du Colombier { 6197dd7cddfSDavid du Colombier p += strlen(h->type); 6207dd7cddfSDavid du Colombier p = skipwhite(p); 6217dd7cddfSDavid du Colombier s_free(m->date822); 6227dd7cddfSDavid du Colombier m->date822 = s_copy(p); 6237dd7cddfSDavid du Colombier p = s_to_c(m->date822); 6247dd7cddfSDavid du Colombier killtrailingwhite(p); 6257dd7cddfSDavid du Colombier } 6267dd7cddfSDavid du Colombier 6277dd7cddfSDavid du Colombier static void 6287dd7cddfSDavid du Colombier subject822(Message *m, Header *h, char *p) 6297dd7cddfSDavid du Colombier { 6307dd7cddfSDavid du Colombier p += strlen(h->type); 6317dd7cddfSDavid du Colombier p = skipwhite(p); 6327dd7cddfSDavid du Colombier s_free(m->subject822); 6337dd7cddfSDavid du Colombier m->subject822 = s_copy(p); 6347dd7cddfSDavid du Colombier p = s_to_c(m->subject822); 6357dd7cddfSDavid du Colombier killtrailingwhite(p); 6367dd7cddfSDavid du Colombier } 6377dd7cddfSDavid du Colombier 6387dd7cddfSDavid du Colombier static void 6397dd7cddfSDavid du Colombier inreplyto822(Message *m, Header *h, char *p) 6407dd7cddfSDavid du Colombier { 6417dd7cddfSDavid du Colombier p += strlen(h->type); 6427dd7cddfSDavid du Colombier p = skipwhite(p); 6437dd7cddfSDavid du Colombier s_free(m->inreplyto822); 6447dd7cddfSDavid du Colombier m->inreplyto822 = s_copy(p); 6457dd7cddfSDavid du Colombier p = s_to_c(m->inreplyto822); 6467dd7cddfSDavid du Colombier killtrailingwhite(p); 6477dd7cddfSDavid du Colombier } 6487dd7cddfSDavid du Colombier 6497dd7cddfSDavid du Colombier static void 6507dd7cddfSDavid du Colombier messageid822(Message *m, Header *h, char *p) 6517dd7cddfSDavid du Colombier { 6527dd7cddfSDavid du Colombier p += strlen(h->type); 6537dd7cddfSDavid du Colombier p = skipwhite(p); 6547dd7cddfSDavid du Colombier s_free(m->messageid822); 6557dd7cddfSDavid du Colombier m->messageid822 = s_copy(p); 6567dd7cddfSDavid du Colombier p = s_to_c(m->messageid822); 6577dd7cddfSDavid du Colombier killtrailingwhite(p); 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier 6607dd7cddfSDavid du Colombier static int 6617dd7cddfSDavid du Colombier isattribute(char **pp, char *attr) 6627dd7cddfSDavid du Colombier { 6637dd7cddfSDavid du Colombier char *p; 6647dd7cddfSDavid du Colombier int n; 6657dd7cddfSDavid du Colombier 6667dd7cddfSDavid du Colombier n = strlen(attr); 6677dd7cddfSDavid du Colombier p = *pp; 6687dd7cddfSDavid du Colombier if(cistrncmp(p, attr, n) != 0) 6697dd7cddfSDavid du Colombier return 0; 6707dd7cddfSDavid du Colombier p += n; 6717dd7cddfSDavid du Colombier while(*p == ' ') 6727dd7cddfSDavid du Colombier p++; 6737dd7cddfSDavid du Colombier if(*p++ != '=') 6747dd7cddfSDavid du Colombier return 0; 6757dd7cddfSDavid du Colombier while(*p == ' ') 6767dd7cddfSDavid du Colombier p++; 6777dd7cddfSDavid du Colombier *pp = p; 6787dd7cddfSDavid du Colombier return 1; 6797dd7cddfSDavid du Colombier } 6807dd7cddfSDavid du Colombier 6817dd7cddfSDavid du Colombier static void 6827dd7cddfSDavid du Colombier ctype(Message *m, Header *h, char *p) 6837dd7cddfSDavid du Colombier { 6847dd7cddfSDavid du Colombier String *s; 6857dd7cddfSDavid du Colombier 6867dd7cddfSDavid du Colombier p += h->len; 6877dd7cddfSDavid du Colombier p = skipwhite(p); 6887dd7cddfSDavid du Colombier 6897dd7cddfSDavid du Colombier p = getstring(p, m->type, 1); 6907dd7cddfSDavid du Colombier 6917dd7cddfSDavid du Colombier while(*p){ 6927dd7cddfSDavid du Colombier if(isattribute(&p, "boundary")){ 6937dd7cddfSDavid du Colombier s = s_new(); 6947dd7cddfSDavid du Colombier p = getstring(p, s, 0); 6957dd7cddfSDavid du Colombier m->boundary = s_reset(m->boundary); 6967dd7cddfSDavid du Colombier s_append(m->boundary, "--"); 6977dd7cddfSDavid du Colombier s_append(m->boundary, s_to_c(s)); 6987dd7cddfSDavid du Colombier s_free(s); 6997dd7cddfSDavid du Colombier } else if(cistrncmp(p, "multipart", 9) == 0){ 7007dd7cddfSDavid du Colombier /* 7017dd7cddfSDavid du Colombier * the first unbounded part of a multipart message, 7027dd7cddfSDavid du Colombier * the preamble, is not displayed or saved 7037dd7cddfSDavid du Colombier */ 7047dd7cddfSDavid du Colombier } else if(isattribute(&p, "name")){ 7057dd7cddfSDavid du Colombier if(m->filename == nil) 7067dd7cddfSDavid du Colombier setfilename(m, p); 7077dd7cddfSDavid du Colombier } else if(isattribute(&p, "charset")){ 7087dd7cddfSDavid du Colombier p = getstring(p, s_reset(m->charset), 0); 7097dd7cddfSDavid du Colombier } 7107dd7cddfSDavid du Colombier 7117dd7cddfSDavid du Colombier p = skiptosemi(p); 7127dd7cddfSDavid du Colombier } 7137dd7cddfSDavid du Colombier } 7147dd7cddfSDavid du Colombier 7157dd7cddfSDavid du Colombier static void 7167dd7cddfSDavid du Colombier cencoding(Message *m, Header *h, char *p) 7177dd7cddfSDavid du Colombier { 7187dd7cddfSDavid du Colombier p += h->len; 7197dd7cddfSDavid du Colombier p = skipwhite(p); 7207dd7cddfSDavid du Colombier if(cistrncmp(p, "base64", 6) == 0) 7217dd7cddfSDavid du Colombier m->encoding = Ebase64; 7227dd7cddfSDavid du Colombier else if(cistrncmp(p, "quoted-printable", 16) == 0) 7237dd7cddfSDavid du Colombier m->encoding = Equoted; 7247dd7cddfSDavid du Colombier } 7257dd7cddfSDavid du Colombier 7267dd7cddfSDavid du Colombier static void 7277dd7cddfSDavid du Colombier cdisposition(Message *m, Header *h, char *p) 7287dd7cddfSDavid du Colombier { 7297dd7cddfSDavid du Colombier p += h->len; 7307dd7cddfSDavid du Colombier p = skipwhite(p); 7317dd7cddfSDavid du Colombier while(*p){ 7327dd7cddfSDavid du Colombier if(cistrncmp(p, "inline", 6) == 0){ 7337dd7cddfSDavid du Colombier m->disposition = Dinline; 7347dd7cddfSDavid du Colombier } else if(cistrncmp(p, "attachment", 10) == 0){ 7357dd7cddfSDavid du Colombier m->disposition = Dfile; 7367dd7cddfSDavid du Colombier } else if(cistrncmp(p, "filename=", 9) == 0){ 7377dd7cddfSDavid du Colombier p += 9; 7387dd7cddfSDavid du Colombier setfilename(m, p); 7397dd7cddfSDavid du Colombier } 7407dd7cddfSDavid du Colombier p = skiptosemi(p); 7417dd7cddfSDavid du Colombier } 7427dd7cddfSDavid du Colombier 7437dd7cddfSDavid du Colombier } 7447dd7cddfSDavid du Colombier 7457dd7cddfSDavid du Colombier ulong msgallocd, msgfreed; 7467dd7cddfSDavid du Colombier 7477dd7cddfSDavid du Colombier Message* 7487dd7cddfSDavid du Colombier newmessage(Message *parent) 7497dd7cddfSDavid du Colombier { 7507dd7cddfSDavid du Colombier static int id; 7517dd7cddfSDavid du Colombier Message *m; 7527dd7cddfSDavid du Colombier 7537dd7cddfSDavid du Colombier msgallocd++; 7547dd7cddfSDavid du Colombier 7557dd7cddfSDavid du Colombier m = emalloc(sizeof(*m)); 7567dd7cddfSDavid du Colombier memset(m, 0, sizeof(*m)); 7577dd7cddfSDavid du Colombier m->disposition = Dnone; 7587dd7cddfSDavid du Colombier m->type = s_copy("text/plain"); 7597dd7cddfSDavid du Colombier m->charset = s_copy("iso-8859-1"); 7607dd7cddfSDavid du Colombier m->id = newid(); 7617dd7cddfSDavid du Colombier if(parent) 7627dd7cddfSDavid du Colombier sprint(m->name, "%d", ++(parent->subname)); 7637dd7cddfSDavid du Colombier if(parent == nil) 7647dd7cddfSDavid du Colombier parent = m; 7657dd7cddfSDavid du Colombier m->whole = parent; 7667dd7cddfSDavid du Colombier m->hlen = -1; 7677dd7cddfSDavid du Colombier return m; 7687dd7cddfSDavid du Colombier } 7697dd7cddfSDavid du Colombier 7707dd7cddfSDavid du Colombier // delete a message from a mailbox 7717dd7cddfSDavid du Colombier void 7727dd7cddfSDavid du Colombier delmessage(Mailbox *mb, Message *m) 7737dd7cddfSDavid du Colombier { 7747dd7cddfSDavid du Colombier Message **l; 7757dd7cddfSDavid du Colombier int i; 7767dd7cddfSDavid du Colombier 7777dd7cddfSDavid du Colombier mb->vers++; 7787dd7cddfSDavid du Colombier msgfreed++; 7797dd7cddfSDavid du Colombier 7807dd7cddfSDavid du Colombier if(m->whole != m){ 7817dd7cddfSDavid du Colombier // unchain from parent 7827dd7cddfSDavid du Colombier for(l = &m->whole->part; *l && *l != m; l = &(*l)->next) 7837dd7cddfSDavid du Colombier ; 7847dd7cddfSDavid du Colombier if(*l != nil) 7857dd7cddfSDavid du Colombier *l = m->next; 7867dd7cddfSDavid du Colombier 7877dd7cddfSDavid du Colombier // clear out of name lookup hash table 7887dd7cddfSDavid du Colombier if(m->whole->whole == m->whole) 7899a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), m->name); 7907dd7cddfSDavid du Colombier else 7919a747e4fSDavid du Colombier hfree(PATH(m->whole->id, Qdir), m->name); 7927dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 7939a747e4fSDavid du Colombier hfree(PATH(m->id, Qdir), dirtab[i]); 7947dd7cddfSDavid du Colombier } 7957dd7cddfSDavid du Colombier 7967dd7cddfSDavid du Colombier /* recurse through sub-parts */ 7977dd7cddfSDavid du Colombier while(m->part) 7987dd7cddfSDavid du Colombier delmessage(mb, m->part); 7997dd7cddfSDavid du Colombier 8007dd7cddfSDavid du Colombier /* free memory */ 8017dd7cddfSDavid du Colombier if(m->mallocd) 8027dd7cddfSDavid du Colombier free(m->start); 8037dd7cddfSDavid du Colombier if(m->hallocd) 8047dd7cddfSDavid du Colombier free(m->header); 8057dd7cddfSDavid du Colombier if(m->ballocd) 8067dd7cddfSDavid du Colombier free(m->body); 8077dd7cddfSDavid du Colombier s_free(m->unixfrom); 8087dd7cddfSDavid du Colombier s_free(m->unixdate); 8099a747e4fSDavid du Colombier s_free(m->unixheader); 8107dd7cddfSDavid du Colombier s_free(m->from822); 8117dd7cddfSDavid du Colombier s_free(m->sender822); 8127dd7cddfSDavid du Colombier s_free(m->to822); 8137dd7cddfSDavid du Colombier s_free(m->bcc822); 81459cc4ca5SDavid du Colombier s_free(m->cc822); 8157dd7cddfSDavid du Colombier s_free(m->replyto822); 8167dd7cddfSDavid du Colombier s_free(m->date822); 8177dd7cddfSDavid du Colombier s_free(m->inreplyto822); 81859cc4ca5SDavid du Colombier s_free(m->subject822); 8197dd7cddfSDavid du Colombier s_free(m->messageid822); 8207dd7cddfSDavid du Colombier s_free(m->addrs); 8217dd7cddfSDavid du Colombier s_free(m->mimeversion); 82259cc4ca5SDavid du Colombier s_free(m->sdigest); 8237dd7cddfSDavid du Colombier s_free(m->boundary); 8247dd7cddfSDavid du Colombier s_free(m->type); 8257dd7cddfSDavid du Colombier s_free(m->charset); 8267dd7cddfSDavid du Colombier s_free(m->filename); 8277dd7cddfSDavid du Colombier 8287dd7cddfSDavid du Colombier free(m); 8297dd7cddfSDavid du Colombier } 8307dd7cddfSDavid du Colombier 8317dd7cddfSDavid du Colombier // mark messages (identified by path) for deletion 8327dd7cddfSDavid du Colombier void 8337dd7cddfSDavid du Colombier delmessages(int ac, char **av) 8347dd7cddfSDavid du Colombier { 8357dd7cddfSDavid du Colombier Mailbox *mb; 8367dd7cddfSDavid du Colombier Message *m; 8377dd7cddfSDavid du Colombier int i, needwrite; 8387dd7cddfSDavid du Colombier 8397dd7cddfSDavid du Colombier qlock(&mbllock); 8407dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 8417dd7cddfSDavid du Colombier if(strcmp(av[0], mb->name) == 0){ 8427dd7cddfSDavid du Colombier qlock(mb); 8437dd7cddfSDavid du Colombier break; 8447dd7cddfSDavid du Colombier } 8457dd7cddfSDavid du Colombier qunlock(&mbllock); 8467dd7cddfSDavid du Colombier if(mb == nil) 8477dd7cddfSDavid du Colombier return; 8487dd7cddfSDavid du Colombier 8497dd7cddfSDavid du Colombier needwrite = 0; 8507dd7cddfSDavid du Colombier for(i = 1; i < ac; i++){ 8517dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = m->next) 8527dd7cddfSDavid du Colombier if(strcmp(m->name, av[i]) == 0){ 8537dd7cddfSDavid du Colombier if(!m->deleted){ 8547dd7cddfSDavid du Colombier mailplumb(mb, m, 1); 8557dd7cddfSDavid du Colombier needwrite = 1; 8567dd7cddfSDavid du Colombier m->deleted = 1; 85759cc4ca5SDavid du Colombier logmsg("deleting", m); 8587dd7cddfSDavid du Colombier } 8597dd7cddfSDavid du Colombier break; 8607dd7cddfSDavid du Colombier } 8617dd7cddfSDavid du Colombier } 8627dd7cddfSDavid du Colombier if(needwrite) 8637dd7cddfSDavid du Colombier syncmbox(mb, 1); 8647dd7cddfSDavid du Colombier qunlock(mb); 8657dd7cddfSDavid du Colombier } 8667dd7cddfSDavid du Colombier 8677dd7cddfSDavid du Colombier /* 8687dd7cddfSDavid du Colombier * the following are called with the mailbox qlocked 8697dd7cddfSDavid du Colombier */ 8707dd7cddfSDavid du Colombier void 8717dd7cddfSDavid du Colombier msgincref(Message *m) 8727dd7cddfSDavid du Colombier { 8737dd7cddfSDavid du Colombier m->refs++; 8747dd7cddfSDavid du Colombier } 8757dd7cddfSDavid du Colombier void 8767dd7cddfSDavid du Colombier msgdecref(Mailbox *mb, Message *m) 8777dd7cddfSDavid du Colombier { 8787dd7cddfSDavid du Colombier m->refs--; 8797dd7cddfSDavid du Colombier if(m->refs == 0 && m->deleted) 8807dd7cddfSDavid du Colombier syncmbox(mb, 1); 8817dd7cddfSDavid du Colombier } 8827dd7cddfSDavid du Colombier 8837dd7cddfSDavid du Colombier /* 8847dd7cddfSDavid du Colombier * the following are called with mbllock'd 8857dd7cddfSDavid du Colombier */ 8867dd7cddfSDavid du Colombier void 8877dd7cddfSDavid du Colombier mboxincref(Mailbox *mb) 8887dd7cddfSDavid du Colombier { 8899a747e4fSDavid du Colombier assert(mb->refs > 0); 8907dd7cddfSDavid du Colombier mb->refs++; 8917dd7cddfSDavid du Colombier } 8927dd7cddfSDavid du Colombier void 8937dd7cddfSDavid du Colombier mboxdecref(Mailbox *mb) 8947dd7cddfSDavid du Colombier { 8959a747e4fSDavid du Colombier assert(mb->refs > 0); 8967dd7cddfSDavid du Colombier qlock(mb); 8977dd7cddfSDavid du Colombier mb->refs--; 8987dd7cddfSDavid du Colombier if(mb->refs == 0){ 8997dd7cddfSDavid du Colombier delmessage(mb, mb->root); 90080ee5cbfSDavid du Colombier if(mb->ctl) 9019a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), "ctl"); 90280ee5cbfSDavid du Colombier if(mb->close) 90380ee5cbfSDavid du Colombier (*mb->close)(mb); 9047dd7cddfSDavid du Colombier free(mb); 9057dd7cddfSDavid du Colombier } else 9067dd7cddfSDavid du Colombier qunlock(mb); 9077dd7cddfSDavid du Colombier } 9087dd7cddfSDavid du Colombier 9097dd7cddfSDavid du Colombier int 9107dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 9117dd7cddfSDavid du Colombier { 9127dd7cddfSDavid du Colombier while(n-- > 0){ 9137dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 9147dd7cddfSDavid du Colombier return -1; 9157dd7cddfSDavid du Colombier } 9167dd7cddfSDavid du Colombier return 0; 9177dd7cddfSDavid du Colombier } 9187dd7cddfSDavid du Colombier 9197dd7cddfSDavid du Colombier int 9207dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 9217dd7cddfSDavid du Colombier { 9227dd7cddfSDavid du Colombier for(;;){ 9237dd7cddfSDavid du Colombier if(tolower(*a) != tolower(*b++)) 9247dd7cddfSDavid du Colombier return -1; 9257dd7cddfSDavid du Colombier if(*a++ == 0) 9267dd7cddfSDavid du Colombier break; 9277dd7cddfSDavid du Colombier } 9287dd7cddfSDavid du Colombier return 0; 9297dd7cddfSDavid du Colombier } 9307dd7cddfSDavid du Colombier 9317dd7cddfSDavid du Colombier static char* 9327dd7cddfSDavid du Colombier skipwhite(char *p) 9337dd7cddfSDavid du Colombier { 9347dd7cddfSDavid du Colombier while(isspace(*p)) 9357dd7cddfSDavid du Colombier p++; 9367dd7cddfSDavid du Colombier return p; 9377dd7cddfSDavid du Colombier } 9387dd7cddfSDavid du Colombier 9397dd7cddfSDavid du Colombier static char* 9407dd7cddfSDavid du Colombier skiptosemi(char *p) 9417dd7cddfSDavid du Colombier { 9427dd7cddfSDavid du Colombier while(*p && *p != ';') 9437dd7cddfSDavid du Colombier p++; 9447dd7cddfSDavid du Colombier while(*p == ';' || isspace(*p)) 9457dd7cddfSDavid du Colombier p++; 9467dd7cddfSDavid du Colombier return p; 9477dd7cddfSDavid du Colombier } 9487dd7cddfSDavid du Colombier 9497dd7cddfSDavid du Colombier static char* 9507dd7cddfSDavid du Colombier getstring(char *p, String *s, int dolower) 9517dd7cddfSDavid du Colombier { 9527dd7cddfSDavid du Colombier s = s_reset(s); 9537dd7cddfSDavid du Colombier p = skipwhite(p); 9547dd7cddfSDavid du Colombier if(*p == '"'){ 9557dd7cddfSDavid du Colombier p++; 9567dd7cddfSDavid du Colombier for(;*p && *p != '"'; p++) 9577dd7cddfSDavid du Colombier if(dolower) 9587dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 9597dd7cddfSDavid du Colombier else 9607dd7cddfSDavid du Colombier s_putc(s, *p); 9617dd7cddfSDavid du Colombier if(*p == '"') 9627dd7cddfSDavid du Colombier p++; 9637dd7cddfSDavid du Colombier s_terminate(s); 9647dd7cddfSDavid du Colombier 9657dd7cddfSDavid du Colombier return p; 9667dd7cddfSDavid du Colombier } 9677dd7cddfSDavid du Colombier 9689a747e4fSDavid du Colombier for(; *p && !isspace(*p) && *p != ';'; p++) 9697dd7cddfSDavid du Colombier if(dolower) 9707dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 9717dd7cddfSDavid du Colombier else 9727dd7cddfSDavid du Colombier s_putc(s, *p); 9737dd7cddfSDavid du Colombier s_terminate(s); 9747dd7cddfSDavid du Colombier 9757dd7cddfSDavid du Colombier return p; 9767dd7cddfSDavid du Colombier } 9777dd7cddfSDavid du Colombier 9787dd7cddfSDavid du Colombier static void 9797dd7cddfSDavid du Colombier setfilename(Message *m, char *p) 9807dd7cddfSDavid du Colombier { 9817dd7cddfSDavid du Colombier m->filename = s_reset(m->filename); 9827dd7cddfSDavid du Colombier getstring(p, m->filename, 0); 9837dd7cddfSDavid du Colombier for(p = s_to_c(m->filename); *p; p++) 9847dd7cddfSDavid du Colombier if(*p == ' ' || *p == '\t' || *p == ';') 9857dd7cddfSDavid du Colombier *p = '_'; 9867dd7cddfSDavid du Colombier } 9877dd7cddfSDavid du Colombier 9887dd7cddfSDavid du Colombier // 9897dd7cddfSDavid du Colombier // undecode message body 9907dd7cddfSDavid du Colombier // 9917dd7cddfSDavid du Colombier void 9927dd7cddfSDavid du Colombier decode(Message *m) 9937dd7cddfSDavid du Colombier { 9947dd7cddfSDavid du Colombier int i, len; 9957dd7cddfSDavid du Colombier char *x; 9967dd7cddfSDavid du Colombier 9977dd7cddfSDavid du Colombier if(m->decoded) 9987dd7cddfSDavid du Colombier return; 9997dd7cddfSDavid du Colombier switch(m->encoding){ 10007dd7cddfSDavid du Colombier case Ebase64: 10017dd7cddfSDavid du Colombier len = m->bend - m->body; 10027dd7cddfSDavid du Colombier i = (len*3)/4+1; // room for max chars + null 10037dd7cddfSDavid du Colombier x = emalloc(i); 10047dd7cddfSDavid du Colombier len = dec64((uchar*)x, i, m->body, len); 10057dd7cddfSDavid du Colombier if(m->ballocd) 10067dd7cddfSDavid du Colombier free(m->body); 10077dd7cddfSDavid du Colombier m->body = x; 10087dd7cddfSDavid du Colombier m->bend = x + len; 10097dd7cddfSDavid du Colombier m->ballocd = 1; 10107dd7cddfSDavid du Colombier break; 10117dd7cddfSDavid du Colombier case Equoted: 10127dd7cddfSDavid du Colombier len = m->bend - m->body; 10137dd7cddfSDavid du Colombier x = emalloc(len+2); // room for null and possible extra nl 10147dd7cddfSDavid du Colombier len = decquoted(x, m->body, m->bend); 10157dd7cddfSDavid du Colombier if(m->ballocd) 10167dd7cddfSDavid du Colombier free(m->body); 10177dd7cddfSDavid du Colombier m->body = x; 10187dd7cddfSDavid du Colombier m->bend = x + len; 10197dd7cddfSDavid du Colombier m->ballocd = 1; 10207dd7cddfSDavid du Colombier break; 10217dd7cddfSDavid du Colombier default: 10227dd7cddfSDavid du Colombier break; 10237dd7cddfSDavid du Colombier } 10247dd7cddfSDavid du Colombier m->decoded = 1; 10257dd7cddfSDavid du Colombier } 10267dd7cddfSDavid du Colombier 10277dd7cddfSDavid du Colombier // convert latin1 to utf 10287dd7cddfSDavid du Colombier void 10297dd7cddfSDavid du Colombier convert(Message *m) 10307dd7cddfSDavid du Colombier { 10317dd7cddfSDavid du Colombier int len; 10327dd7cddfSDavid du Colombier char *x; 10337dd7cddfSDavid du Colombier 10347dd7cddfSDavid du Colombier // don't convert if we're not a leaf, not text, or already converted 10357dd7cddfSDavid du Colombier if(m->converted) 10367dd7cddfSDavid du Colombier return; 10377dd7cddfSDavid du Colombier if(m->part != nil) 10387dd7cddfSDavid du Colombier return; 10397dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(m->type), "text", 4) != 0) 10407dd7cddfSDavid du Colombier return; 10417dd7cddfSDavid du Colombier 10427dd7cddfSDavid du Colombier if(cistrcmp(s_to_c(m->charset), "us-ascii") == 0 || 10437dd7cddfSDavid du Colombier cistrcmp(s_to_c(m->charset), "iso-8859-1") == 0){ 10447dd7cddfSDavid du Colombier len = is8bit(m); 10457dd7cddfSDavid du Colombier if(len > 0){ 10467dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 10477dd7cddfSDavid du Colombier x = emalloc(len); 10487dd7cddfSDavid du Colombier len = latin1toutf(x, m->body, m->bend); 10497dd7cddfSDavid du Colombier if(m->ballocd) 10507dd7cddfSDavid du Colombier free(m->body); 10517dd7cddfSDavid du Colombier m->body = x; 10527dd7cddfSDavid du Colombier m->bend = x + len; 10537dd7cddfSDavid du Colombier m->ballocd = 1; 10547dd7cddfSDavid du Colombier } 10557dd7cddfSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "big5") == 0){ 10567dd7cddfSDavid du Colombier len = xtoutf("big5", &x, m->body, m->bend); 10577dd7cddfSDavid du Colombier if(len != 0){ 10587dd7cddfSDavid du Colombier if(m->ballocd) 10597dd7cddfSDavid du Colombier free(m->body); 10607dd7cddfSDavid du Colombier m->body = x; 10617dd7cddfSDavid du Colombier m->bend = x + len; 10627dd7cddfSDavid du Colombier m->ballocd = 1; 10637dd7cddfSDavid du Colombier } 1064*5d459b5aSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "windows-1257") == 0 1065*5d459b5aSDavid du Colombier || cistrcmp(s_to_c(m->charset), "windows-1252") == 0){ 10667dd7cddfSDavid du Colombier len = is8bit(m); 10677dd7cddfSDavid du Colombier if(len > 0){ 10687dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 10697dd7cddfSDavid du Colombier x = emalloc(len); 10707dd7cddfSDavid du Colombier len = windows1257toutf(x, m->body, m->bend); 10717dd7cddfSDavid du Colombier if(m->ballocd) 10727dd7cddfSDavid du Colombier free(m->body); 10737dd7cddfSDavid du Colombier m->body = x; 10747dd7cddfSDavid du Colombier m->bend = x + len; 10757dd7cddfSDavid du Colombier m->ballocd = 1; 10767dd7cddfSDavid du Colombier } 10777dd7cddfSDavid du Colombier } 10787dd7cddfSDavid du Colombier 10797dd7cddfSDavid du Colombier m->converted = 1; 10807dd7cddfSDavid du Colombier } 10817dd7cddfSDavid du Colombier 10827dd7cddfSDavid du Colombier enum 10837dd7cddfSDavid du Colombier { 10847dd7cddfSDavid du Colombier Self= 1, 10857dd7cddfSDavid du Colombier Hex= 2, 10867dd7cddfSDavid du Colombier }; 10877dd7cddfSDavid du Colombier uchar tableqp[256]; 10887dd7cddfSDavid du Colombier 10897dd7cddfSDavid du Colombier static void 10907dd7cddfSDavid du Colombier initquoted(void) 10917dd7cddfSDavid du Colombier { 10927dd7cddfSDavid du Colombier int c; 10937dd7cddfSDavid du Colombier 10947dd7cddfSDavid du Colombier memset(tableqp, 0, 256); 10957dd7cddfSDavid du Colombier for(c = ' '; c <= '<'; c++) 10967dd7cddfSDavid du Colombier tableqp[c] = Self; 10977dd7cddfSDavid du Colombier for(c = '>'; c <= '~'; c++) 10987dd7cddfSDavid du Colombier tableqp[c] = Self; 10997dd7cddfSDavid du Colombier tableqp['\t'] = Self; 11007dd7cddfSDavid du Colombier tableqp['='] = Hex; 11017dd7cddfSDavid du Colombier } 11027dd7cddfSDavid du Colombier 11037dd7cddfSDavid du Colombier static int 11047dd7cddfSDavid du Colombier hex2int(int x) 11057dd7cddfSDavid du Colombier { 11067dd7cddfSDavid du Colombier if(x >= '0' && x <= '9') 11077dd7cddfSDavid du Colombier return x - '0'; 11087dd7cddfSDavid du Colombier if(x >= 'A' && x <= 'F') 11097dd7cddfSDavid du Colombier return (x - 'A') + 10; 11107dd7cddfSDavid du Colombier if(x >= 'a' && x <= 'f') 11117dd7cddfSDavid du Colombier return (x - 'a') + 10; 11127dd7cddfSDavid du Colombier return 0; 11137dd7cddfSDavid du Colombier } 11147dd7cddfSDavid du Colombier 11157dd7cddfSDavid du Colombier static char* 11167dd7cddfSDavid du Colombier decquotedline(char *out, char *in, char *e) 11177dd7cddfSDavid du Colombier { 11187dd7cddfSDavid du Colombier int c, soft; 11197dd7cddfSDavid du Colombier 11207dd7cddfSDavid du Colombier /* dump trailing white space */ 11217dd7cddfSDavid du Colombier while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) 11227dd7cddfSDavid du Colombier e--; 11237dd7cddfSDavid du Colombier 11247dd7cddfSDavid du Colombier /* trailing '=' means no newline */ 11257dd7cddfSDavid du Colombier if(*e == '='){ 11267dd7cddfSDavid du Colombier soft = 1; 11277dd7cddfSDavid du Colombier e--; 11287dd7cddfSDavid du Colombier } else 11297dd7cddfSDavid du Colombier soft = 0; 11307dd7cddfSDavid du Colombier 11317dd7cddfSDavid du Colombier while(in <= e){ 11327dd7cddfSDavid du Colombier c = (*in++) & 0xff; 11337dd7cddfSDavid du Colombier switch(tableqp[c]){ 11347dd7cddfSDavid du Colombier case Self: 11357dd7cddfSDavid du Colombier *out++ = c; 11367dd7cddfSDavid du Colombier break; 11377dd7cddfSDavid du Colombier case Hex: 11387dd7cddfSDavid du Colombier c = hex2int(*in++)<<4; 11397dd7cddfSDavid du Colombier c |= hex2int(*in++); 11407dd7cddfSDavid du Colombier *out++ = c; 11417dd7cddfSDavid du Colombier break; 11427dd7cddfSDavid du Colombier } 11437dd7cddfSDavid du Colombier } 11447dd7cddfSDavid du Colombier if(!soft) 11457dd7cddfSDavid du Colombier *out++ = '\n'; 11467dd7cddfSDavid du Colombier *out = 0; 11477dd7cddfSDavid du Colombier 11487dd7cddfSDavid du Colombier return out; 11497dd7cddfSDavid du Colombier } 11507dd7cddfSDavid du Colombier 11517dd7cddfSDavid du Colombier int 11527dd7cddfSDavid du Colombier decquoted(char *out, char *in, char *e) 11537dd7cddfSDavid du Colombier { 11547dd7cddfSDavid du Colombier char *p, *nl; 11557dd7cddfSDavid du Colombier 11567dd7cddfSDavid du Colombier if(tableqp[' '] == 0) 11577dd7cddfSDavid du Colombier initquoted(); 11587dd7cddfSDavid du Colombier 11597dd7cddfSDavid du Colombier p = out; 11607dd7cddfSDavid du Colombier while((nl = strchr(in, '\n')) != nil && nl < e){ 11617dd7cddfSDavid du Colombier p = decquotedline(p, in, nl); 11627dd7cddfSDavid du Colombier in = nl + 1; 11637dd7cddfSDavid du Colombier } 11647dd7cddfSDavid du Colombier if(in < e) 11657dd7cddfSDavid du Colombier p = decquotedline(p, in, e-1); 11667dd7cddfSDavid du Colombier 11677dd7cddfSDavid du Colombier // make sure we end with a new line 11687dd7cddfSDavid du Colombier if(*(p-1) != '\n'){ 11697dd7cddfSDavid du Colombier *p++ = '\n'; 11707dd7cddfSDavid du Colombier *p = 0; 11717dd7cddfSDavid du Colombier } 11727dd7cddfSDavid du Colombier 11737dd7cddfSDavid du Colombier return p - out; 11747dd7cddfSDavid du Colombier } 11757dd7cddfSDavid du Colombier 11767dd7cddfSDavid du Colombier static char* 11777dd7cddfSDavid du Colombier lowercase(char *p) 11787dd7cddfSDavid du Colombier { 11797dd7cddfSDavid du Colombier char *op; 11807dd7cddfSDavid du Colombier int c; 11817dd7cddfSDavid du Colombier 11827dd7cddfSDavid du Colombier for(op = p; c = *p; p++) 11837dd7cddfSDavid du Colombier if(isupper(c)) 11847dd7cddfSDavid du Colombier *p = tolower(c); 11857dd7cddfSDavid du Colombier return op; 11867dd7cddfSDavid du Colombier } 11877dd7cddfSDavid du Colombier 11887dd7cddfSDavid du Colombier /* 11897dd7cddfSDavid du Colombier * return number of 8 bit characters 11907dd7cddfSDavid du Colombier */ 11917dd7cddfSDavid du Colombier static int 11927dd7cddfSDavid du Colombier is8bit(Message *m) 11937dd7cddfSDavid du Colombier { 11947dd7cddfSDavid du Colombier int count = 0; 11957dd7cddfSDavid du Colombier char *p; 11967dd7cddfSDavid du Colombier 11977dd7cddfSDavid du Colombier for(p = m->body; p < m->bend; p++) 11987dd7cddfSDavid du Colombier if(*p & 0x80) 11997dd7cddfSDavid du Colombier count++; 12007dd7cddfSDavid du Colombier return count; 12017dd7cddfSDavid du Colombier } 12027dd7cddfSDavid du Colombier 12037dd7cddfSDavid du Colombier // translate latin1 directly since it fits neatly in utf 12047dd7cddfSDavid du Colombier int 12057dd7cddfSDavid du Colombier latin1toutf(char *out, char *in, char *e) 12067dd7cddfSDavid du Colombier { 12077dd7cddfSDavid du Colombier Rune r; 12087dd7cddfSDavid du Colombier char *p; 12097dd7cddfSDavid du Colombier 12107dd7cddfSDavid du Colombier p = out; 12117dd7cddfSDavid du Colombier for(; in < e; in++){ 12127dd7cddfSDavid du Colombier r = (*in) & 0xff; 12137dd7cddfSDavid du Colombier p += runetochar(p, &r); 12147dd7cddfSDavid du Colombier } 12157dd7cddfSDavid du Colombier *p = 0; 12167dd7cddfSDavid du Colombier return p - out; 12177dd7cddfSDavid du Colombier } 12187dd7cddfSDavid du Colombier 12197dd7cddfSDavid du Colombier // translate any thing else using the tcs program 12207dd7cddfSDavid du Colombier int 12217dd7cddfSDavid du Colombier xtoutf(char *charset, char **out, char *in, char *e) 12227dd7cddfSDavid du Colombier { 12237dd7cddfSDavid du Colombier char *av[4]; 12247dd7cddfSDavid du Colombier int totcs[2]; 12257dd7cddfSDavid du Colombier int fromtcs[2]; 12267dd7cddfSDavid du Colombier int n, len, sofar; 12277dd7cddfSDavid du Colombier char *p; 12287dd7cddfSDavid du Colombier 12297dd7cddfSDavid du Colombier len = e-in+1; 12307dd7cddfSDavid du Colombier sofar = 0; 12317dd7cddfSDavid du Colombier *out = p = malloc(len+1); 12327dd7cddfSDavid du Colombier if(p == nil) 12337dd7cddfSDavid du Colombier return 0; 12347dd7cddfSDavid du Colombier 12357dd7cddfSDavid du Colombier av[0] = charset; 12367dd7cddfSDavid du Colombier av[1] = "-f"; 12377dd7cddfSDavid du Colombier av[2] = charset; 12387dd7cddfSDavid du Colombier av[3] = 0; 12397dd7cddfSDavid du Colombier if(pipe(totcs) < 0) 12407dd7cddfSDavid du Colombier return 0; 12417dd7cddfSDavid du Colombier if(pipe(fromtcs) < 0){ 12427dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 12437dd7cddfSDavid du Colombier return 0; 12447dd7cddfSDavid du Colombier } 12457dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12467dd7cddfSDavid du Colombier case -1: 12477dd7cddfSDavid du Colombier close(fromtcs[0]); close(fromtcs[1]); 12487dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 12497dd7cddfSDavid du Colombier return 0; 12507dd7cddfSDavid du Colombier case 0: 12517dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 12527dd7cddfSDavid du Colombier dup(fromtcs[1], 1); 12537dd7cddfSDavid du Colombier dup(totcs[0], 0); 12547dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 12559a747e4fSDavid du Colombier dup(open("/dev/null", OWRITE), 2); 12567dd7cddfSDavid du Colombier exec("/bin/tcs", av); 12577dd7cddfSDavid du Colombier _exits(0); 12587dd7cddfSDavid du Colombier default: 12597dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 12607dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12617dd7cddfSDavid du Colombier case -1: 12627dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 12637dd7cddfSDavid du Colombier return 0; 12647dd7cddfSDavid du Colombier case 0: 12657dd7cddfSDavid du Colombier close(fromtcs[0]); 12667dd7cddfSDavid du Colombier while(in < e){ 12677dd7cddfSDavid du Colombier n = write(totcs[1], in, e-in); 12687dd7cddfSDavid du Colombier if(n <= 0) 12697dd7cddfSDavid du Colombier break; 12707dd7cddfSDavid du Colombier in += n; 12717dd7cddfSDavid du Colombier } 12727dd7cddfSDavid du Colombier close(totcs[1]); 12737dd7cddfSDavid du Colombier _exits(0); 12747dd7cddfSDavid du Colombier default: 12757dd7cddfSDavid du Colombier close(totcs[1]); 12767dd7cddfSDavid du Colombier for(;;){ 12777dd7cddfSDavid du Colombier n = read(fromtcs[0], &p[sofar], len-sofar); 12787dd7cddfSDavid du Colombier if(n <= 0) 12797dd7cddfSDavid du Colombier break; 12807dd7cddfSDavid du Colombier sofar += n; 12817dd7cddfSDavid du Colombier p[sofar] = 0; 12827dd7cddfSDavid du Colombier if(sofar == len){ 12837dd7cddfSDavid du Colombier len += 1024; 12847dd7cddfSDavid du Colombier *out = p = realloc(p, len+1); 12857dd7cddfSDavid du Colombier if(p == nil) 12867dd7cddfSDavid du Colombier return 0; 12877dd7cddfSDavid du Colombier } 12887dd7cddfSDavid du Colombier } 12897dd7cddfSDavid du Colombier close(fromtcs[0]); 12907dd7cddfSDavid du Colombier break; 12917dd7cddfSDavid du Colombier } 12927dd7cddfSDavid du Colombier break; 12937dd7cddfSDavid du Colombier } 12947dd7cddfSDavid du Colombier return sofar; 12957dd7cddfSDavid du Colombier } 12967dd7cddfSDavid du Colombier 12977dd7cddfSDavid du Colombier enum { 12987dd7cddfSDavid du Colombier Winstart= 0x7f, 12997dd7cddfSDavid du Colombier Winend= 0x9f, 13007dd7cddfSDavid du Colombier }; 13017dd7cddfSDavid du Colombier 13027dd7cddfSDavid du Colombier Rune winchars[] = { 13037dd7cddfSDavid du Colombier L'•', 13047dd7cddfSDavid du Colombier L'•', L'•', L'‚', L'ƒ', L'„', L'…', L'†', L'‡', 13057dd7cddfSDavid du Colombier L'ˆ', L'‰', L'Š', L'‹', L'Œ', L'•', L'•', L'•', 13067dd7cddfSDavid du Colombier L'•', L'‘', L'’', L'“', L'”', L'•', L'–', L'—', 13077dd7cddfSDavid du Colombier L'˜', L'™', L'š', L'›', L'œ', L'•', L'•', L'Ÿ', 13087dd7cddfSDavid du Colombier }; 13097dd7cddfSDavid du Colombier 13107dd7cddfSDavid du Colombier int 13117dd7cddfSDavid du Colombier windows1257toutf(char *out, char *in, char *e) 13127dd7cddfSDavid du Colombier { 13137dd7cddfSDavid du Colombier Rune r; 13147dd7cddfSDavid du Colombier char *p; 13157dd7cddfSDavid du Colombier 13167dd7cddfSDavid du Colombier p = out; 13177dd7cddfSDavid du Colombier for(; in < e; in++){ 13187dd7cddfSDavid du Colombier r = (*in) & 0xff; 13197dd7cddfSDavid du Colombier if(r >= 0x7f && r <= 0x9f) 13207dd7cddfSDavid du Colombier r = winchars[r-0x7f]; 13217dd7cddfSDavid du Colombier p += runetochar(p, &r); 13227dd7cddfSDavid du Colombier } 13237dd7cddfSDavid du Colombier *p = 0; 13247dd7cddfSDavid du Colombier return p - out; 13257dd7cddfSDavid du Colombier } 13267dd7cddfSDavid du Colombier 13277dd7cddfSDavid du Colombier void * 13287dd7cddfSDavid du Colombier emalloc(ulong n) 13297dd7cddfSDavid du Colombier { 13307dd7cddfSDavid du Colombier void *p; 13317dd7cddfSDavid du Colombier 13327dd7cddfSDavid du Colombier p = mallocz(n, 1); 13337dd7cddfSDavid du Colombier if(!p){ 133480ee5cbfSDavid du Colombier fprint(2, "%s: out of memory alloc %lud\n", argv0, n); 13357dd7cddfSDavid du Colombier exits("out of memory"); 13367dd7cddfSDavid du Colombier } 133780ee5cbfSDavid du Colombier setmalloctag(p, getcallerpc(&n)); 13387dd7cddfSDavid du Colombier return p; 13397dd7cddfSDavid du Colombier } 13407dd7cddfSDavid du Colombier 13417dd7cddfSDavid du Colombier void * 13427dd7cddfSDavid du Colombier erealloc(void *p, ulong n) 13437dd7cddfSDavid du Colombier { 13447dd7cddfSDavid du Colombier p = realloc(p, n); 13457dd7cddfSDavid du Colombier if(!p){ 134680ee5cbfSDavid du Colombier fprint(2, "%s: out of memory realloc %lud\n", argv0, n); 13477dd7cddfSDavid du Colombier exits("out of memory"); 13487dd7cddfSDavid du Colombier } 134980ee5cbfSDavid du Colombier setrealloctag(p, getcallerpc(&p)); 13507dd7cddfSDavid du Colombier return p; 13517dd7cddfSDavid du Colombier } 13527dd7cddfSDavid du Colombier 13537dd7cddfSDavid du Colombier void 13547dd7cddfSDavid du Colombier mailplumb(Mailbox *mb, Message *m, int delete) 13557dd7cddfSDavid du Colombier { 13567dd7cddfSDavid du Colombier Plumbmsg p; 13577dd7cddfSDavid du Colombier Plumbattr a[7]; 13587dd7cddfSDavid du Colombier char buf[256]; 13597dd7cddfSDavid du Colombier int ai; 13607dd7cddfSDavid du Colombier char lenstr[10], *from, *subject, *date; 13617dd7cddfSDavid du Colombier static int fd = -1; 13627dd7cddfSDavid du Colombier 13637dd7cddfSDavid du Colombier if(m->subject822 == nil) 13647dd7cddfSDavid du Colombier subject = ""; 13657dd7cddfSDavid du Colombier else 13667dd7cddfSDavid du Colombier subject = s_to_c(m->subject822); 13677dd7cddfSDavid du Colombier 13687dd7cddfSDavid du Colombier if(m->from822 != nil) 13697dd7cddfSDavid du Colombier from = s_to_c(m->from822); 13707dd7cddfSDavid du Colombier else if(m->unixfrom != nil) 13717dd7cddfSDavid du Colombier from = s_to_c(m->unixfrom); 13727dd7cddfSDavid du Colombier else 13737dd7cddfSDavid du Colombier from = ""; 13747dd7cddfSDavid du Colombier 13757dd7cddfSDavid du Colombier if(m->unixdate != nil) 13767dd7cddfSDavid du Colombier date = s_to_c(m->unixdate); 13777dd7cddfSDavid du Colombier else 13787dd7cddfSDavid du Colombier date = ""; 13797dd7cddfSDavid du Colombier 13807dd7cddfSDavid du Colombier sprint(lenstr, "%ld", m->end-m->start); 13817dd7cddfSDavid du Colombier 13827dd7cddfSDavid du Colombier if(biffing && !delete) 13837dd7cddfSDavid du Colombier print("[ %s / %s / %s ]\n", from, subject, lenstr); 13847dd7cddfSDavid du Colombier 13857dd7cddfSDavid du Colombier if(!plumbing) 13867dd7cddfSDavid du Colombier return; 13877dd7cddfSDavid du Colombier 13887dd7cddfSDavid du Colombier if(fd < 0) 13897dd7cddfSDavid du Colombier fd = plumbopen("send", OWRITE); 13907dd7cddfSDavid du Colombier if(fd < 0) 13917dd7cddfSDavid du Colombier return; 13927dd7cddfSDavid du Colombier 13937dd7cddfSDavid du Colombier p.src = "mailfs"; 13947dd7cddfSDavid du Colombier p.dst = "seemail"; 13957dd7cddfSDavid du Colombier p.wdir = "/mail/fs"; 13967dd7cddfSDavid du Colombier p.type = "text"; 13977dd7cddfSDavid du Colombier 13987dd7cddfSDavid du Colombier ai = 0; 13997dd7cddfSDavid du Colombier a[ai].name = "filetype"; 14007dd7cddfSDavid du Colombier a[ai].value = "mail"; 14017dd7cddfSDavid du Colombier 14027dd7cddfSDavid du Colombier a[++ai].name = "sender"; 14037dd7cddfSDavid du Colombier a[ai].value = from; 14047dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14057dd7cddfSDavid du Colombier 14067dd7cddfSDavid du Colombier a[++ai].name = "length"; 14077dd7cddfSDavid du Colombier a[ai].value = lenstr; 14087dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14097dd7cddfSDavid du Colombier 14107dd7cddfSDavid du Colombier a[++ai].name = "mailtype"; 14117dd7cddfSDavid du Colombier a[ai].value = delete?"delete":"new"; 14127dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14137dd7cddfSDavid du Colombier 14147dd7cddfSDavid du Colombier a[++ai].name = "date"; 14157dd7cddfSDavid du Colombier a[ai].value = date; 14167dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14177dd7cddfSDavid du Colombier 14189a747e4fSDavid du Colombier if(m->sdigest){ 14197dd7cddfSDavid du Colombier a[++ai].name = "digest"; 14207dd7cddfSDavid du Colombier a[ai].value = s_to_c(m->sdigest); 14217dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14229a747e4fSDavid du Colombier } 14237dd7cddfSDavid du Colombier 14247dd7cddfSDavid du Colombier a[ai].next = nil; 14257dd7cddfSDavid du Colombier 14267dd7cddfSDavid du Colombier p.attr = a; 14277dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/%s/%s", 14287dd7cddfSDavid du Colombier mntpt, mb->name, m->name); 14297dd7cddfSDavid du Colombier p.ndata = strlen(buf); 14307dd7cddfSDavid du Colombier p.data = buf; 14317dd7cddfSDavid du Colombier 14327dd7cddfSDavid du Colombier plumbsend(fd, &p); 14337dd7cddfSDavid du Colombier } 14347dd7cddfSDavid du Colombier 14357dd7cddfSDavid du Colombier // 14367dd7cddfSDavid du Colombier // count the number of lines in the body (for imap4) 14377dd7cddfSDavid du Colombier // 14387dd7cddfSDavid du Colombier void 14397dd7cddfSDavid du Colombier countlines(Message *m) 14407dd7cddfSDavid du Colombier { 14417dd7cddfSDavid du Colombier int i; 14427dd7cddfSDavid du Colombier char *p; 14437dd7cddfSDavid du Colombier 14447dd7cddfSDavid du Colombier i = 0; 14457dd7cddfSDavid du Colombier for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n')) 14467dd7cddfSDavid du Colombier i++; 14477dd7cddfSDavid du Colombier sprint(m->lines, "%d", i); 14487dd7cddfSDavid du Colombier } 144959cc4ca5SDavid du Colombier 145059cc4ca5SDavid du Colombier char *LOG = "fs"; 145159cc4ca5SDavid du Colombier 145259cc4ca5SDavid du Colombier void 145359cc4ca5SDavid du Colombier logmsg(char *s, Message *m) 145459cc4ca5SDavid du Colombier { 145559cc4ca5SDavid du Colombier int pid; 145659cc4ca5SDavid du Colombier 145759cc4ca5SDavid du Colombier if(!logging) 145859cc4ca5SDavid du Colombier return; 145959cc4ca5SDavid du Colombier pid = getpid(); 146059cc4ca5SDavid du Colombier if(m == nil) 146159cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s", user, pid, s); 146259cc4ca5SDavid du Colombier else 146359cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s msg from %s digest %s", 146459cc4ca5SDavid du Colombier user, pid, s, 146559cc4ca5SDavid du Colombier m->from822 ? s_to_c(m->from822) : "?", 146659cc4ca5SDavid du Colombier s_to_c(m->sdigest)); 146759cc4ca5SDavid du Colombier } 146880ee5cbfSDavid du Colombier 146980ee5cbfSDavid du Colombier // 147080ee5cbfSDavid du Colombier // convert an RFC822 date into a Unix style date 147180ee5cbfSDavid du Colombier // for when the Unix From line isn't there (e.g. POP3). 147280ee5cbfSDavid du Colombier // enough client programs depend on having a Unix date 147380ee5cbfSDavid du Colombier // that it's easiest to write this conversion code once, right here. 147480ee5cbfSDavid du Colombier // 147580ee5cbfSDavid du Colombier // people don't follow RFC822 particularly closely, 147680ee5cbfSDavid du Colombier // so we use strtotm, which is a bunch of heuristics. 147780ee5cbfSDavid du Colombier // 147880ee5cbfSDavid du Colombier 147980ee5cbfSDavid du Colombier extern int strtotm(char*, Tm*); 148080ee5cbfSDavid du Colombier String* 148180ee5cbfSDavid du Colombier date822tounix(char *s) 148280ee5cbfSDavid du Colombier { 148380ee5cbfSDavid du Colombier char *p, *q; 148480ee5cbfSDavid du Colombier Tm tm; 148580ee5cbfSDavid du Colombier 148680ee5cbfSDavid du Colombier if(strtotm(s, &tm) < 0) 148780ee5cbfSDavid du Colombier return nil; 148880ee5cbfSDavid du Colombier 148980ee5cbfSDavid du Colombier p = asctime(&tm); 149080ee5cbfSDavid du Colombier if(q = strchr(p, '\n')) 149180ee5cbfSDavid du Colombier *q = '\0'; 149280ee5cbfSDavid du Colombier return s_copy(p); 149380ee5cbfSDavid du Colombier } 149480ee5cbfSDavid du Colombier 1495