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*); 303ff48bf5SDavid du Colombier static void nullsqueeze(Message*); 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; 7180ee5cbfSDavid du Colombier 7280ee5cbfSDavid du Colombier char *Enotme = "path not served by this file server"; 737dd7cddfSDavid du Colombier 747dd7cddfSDavid du Colombier enum 757dd7cddfSDavid du Colombier { 767dd7cddfSDavid du Colombier Chunksize = 1024, 777dd7cddfSDavid du Colombier }; 787dd7cddfSDavid du Colombier 7980ee5cbfSDavid du Colombier Mailboxinit *boxinit[] = { 8080ee5cbfSDavid du Colombier imap4mbox, 8180ee5cbfSDavid du Colombier pop3mbox, 8280ee5cbfSDavid du Colombier plan9mbox, 8380ee5cbfSDavid du Colombier }; 8480ee5cbfSDavid du Colombier 8580ee5cbfSDavid du Colombier char* 8680ee5cbfSDavid du Colombier syncmbox(Mailbox *mb, int doplumb) 8780ee5cbfSDavid du Colombier { 8880ee5cbfSDavid du Colombier return (*mb->sync)(mb, doplumb); 8980ee5cbfSDavid du Colombier } 9080ee5cbfSDavid du Colombier 917dd7cddfSDavid du Colombier /* create a new mailbox */ 927dd7cddfSDavid du Colombier char* 937dd7cddfSDavid du Colombier newmbox(char *path, char *name, int std) 947dd7cddfSDavid du Colombier { 957dd7cddfSDavid du Colombier Mailbox *mb, **l; 967dd7cddfSDavid du Colombier char *p, *rv; 9780ee5cbfSDavid du Colombier int i; 9880ee5cbfSDavid du Colombier 9980ee5cbfSDavid du Colombier initheaders(); 10080ee5cbfSDavid du Colombier 1017dd7cddfSDavid du Colombier mb = emalloc(sizeof(*mb)); 1027dd7cddfSDavid du Colombier strncpy(mb->path, path, sizeof(mb->path)-1); 1037dd7cddfSDavid du Colombier if(name == nil){ 1047dd7cddfSDavid du Colombier p = strrchr(path, '/'); 1057dd7cddfSDavid du Colombier if(p == nil) 1067dd7cddfSDavid du Colombier p = path; 1077dd7cddfSDavid du Colombier else 1087dd7cddfSDavid du Colombier p++; 1097dd7cddfSDavid du Colombier if(*p == 0){ 1107dd7cddfSDavid du Colombier free(mb); 1117dd7cddfSDavid du Colombier return "bad mbox name"; 1127dd7cddfSDavid du Colombier } 1137dd7cddfSDavid du Colombier strncpy(mb->name, p, sizeof(mb->name)-1); 1147dd7cddfSDavid du Colombier } else { 1157dd7cddfSDavid du Colombier strncpy(mb->name, name, sizeof(mb->name)-1); 1167dd7cddfSDavid du Colombier } 1177dd7cddfSDavid du Colombier 11880ee5cbfSDavid du Colombier rv = nil; 11980ee5cbfSDavid du Colombier // check for a mailbox type 12080ee5cbfSDavid du Colombier for(i=0; i<nelem(boxinit); i++) 12180ee5cbfSDavid du Colombier if((rv = (*boxinit[i])(mb, path)) != Enotme) 12280ee5cbfSDavid du Colombier break; 12380ee5cbfSDavid du Colombier if(i == nelem(boxinit)){ 12480ee5cbfSDavid du Colombier free(mb); 12580ee5cbfSDavid du Colombier return "bad path"; 12680ee5cbfSDavid du Colombier } 12780ee5cbfSDavid du Colombier 12880ee5cbfSDavid du Colombier // on error, give up 1295d459b5aSDavid du Colombier if(rv){ 1305d459b5aSDavid du Colombier free(mb); 13180ee5cbfSDavid du Colombier return rv; 1325d459b5aSDavid du Colombier } 13380ee5cbfSDavid du Colombier 1347dd7cddfSDavid du Colombier // make sure name isn't taken 1357dd7cddfSDavid du Colombier qlock(&mbllock); 13659cc4ca5SDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next){ 1377dd7cddfSDavid du Colombier if(strcmp((*l)->name, mb->name) == 0){ 13859cc4ca5SDavid du Colombier if(strcmp(path, (*l)->path) == 0) 1397dd7cddfSDavid du Colombier rv = nil; 1407dd7cddfSDavid du Colombier else 1417dd7cddfSDavid du Colombier rv = "mbox name in use"; 14280ee5cbfSDavid du Colombier if(mb->close) 14380ee5cbfSDavid du Colombier (*mb->close)(mb); 1447dd7cddfSDavid du Colombier free(mb); 1457dd7cddfSDavid du Colombier qunlock(&mbllock); 1467dd7cddfSDavid du Colombier return rv; 1477dd7cddfSDavid du Colombier } 14859cc4ca5SDavid du Colombier } 14959cc4ca5SDavid du Colombier 150ed250ae1SDavid du Colombier // always try locking 151ed250ae1SDavid du Colombier mb->dolock = 1; 15259cc4ca5SDavid du Colombier 1537dd7cddfSDavid du Colombier mb->refs = 1; 1547dd7cddfSDavid du Colombier mb->next = nil; 1557dd7cddfSDavid du Colombier mb->id = newid(); 1567dd7cddfSDavid du Colombier mb->root = newmessage(nil); 1577dd7cddfSDavid du Colombier mb->std = std; 1587dd7cddfSDavid du Colombier *l = mb; 1597dd7cddfSDavid du Colombier qunlock(&mbllock); 1607dd7cddfSDavid du Colombier 1617dd7cddfSDavid du Colombier qlock(mb); 16280ee5cbfSDavid du Colombier if(mb->ctl){ 1639a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), "ctl", 1649a747e4fSDavid du Colombier (Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb); 16580ee5cbfSDavid du Colombier } 1667dd7cddfSDavid du Colombier rv = syncmbox(mb, 0); 1677dd7cddfSDavid du Colombier qunlock(mb); 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier return rv; 1707dd7cddfSDavid du Colombier } 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier // close the named mailbox 1737dd7cddfSDavid du Colombier void 1747dd7cddfSDavid du Colombier freembox(char *name) 1757dd7cddfSDavid du Colombier { 1765d459b5aSDavid du Colombier Mailbox **l, *mb; 1777dd7cddfSDavid du Colombier 1787dd7cddfSDavid du Colombier qlock(&mbllock); 1795d459b5aSDavid du Colombier for(l=&mbl; *l != nil; l=&(*l)->next){ 1805d459b5aSDavid du Colombier if(strcmp(name, (*l)->name) == 0){ 1815d459b5aSDavid du Colombier mb = *l; 1825d459b5aSDavid du Colombier *l = mb->next; 1837dd7cddfSDavid du Colombier mboxdecref(mb); 1847dd7cddfSDavid du Colombier break; 1857dd7cddfSDavid du Colombier } 1865d459b5aSDavid du Colombier } 1879a747e4fSDavid du Colombier hfree(PATH(0, Qtop), name); 1887dd7cddfSDavid du Colombier qunlock(&mbllock); 1897dd7cddfSDavid du Colombier } 1907dd7cddfSDavid du Colombier 1917dd7cddfSDavid du Colombier static void 1927dd7cddfSDavid du Colombier initheaders(void) 1937dd7cddfSDavid du Colombier { 1947dd7cddfSDavid du Colombier Header *h; 1957dd7cddfSDavid du Colombier static int already; 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier if(already) 1987dd7cddfSDavid du Colombier return; 1997dd7cddfSDavid du Colombier already = 1; 2007dd7cddfSDavid du Colombier 2017dd7cddfSDavid du Colombier for(h = head; h->type != nil; h++) 2027dd7cddfSDavid du Colombier h->len = strlen(h->type); 2037dd7cddfSDavid du Colombier } 2047dd7cddfSDavid du Colombier 2057dd7cddfSDavid du Colombier /* 2067dd7cddfSDavid du Colombier * parse a Unix style header 2077dd7cddfSDavid du Colombier */ 20880ee5cbfSDavid du Colombier void 2097dd7cddfSDavid du Colombier parseunix(Message *m) 2107dd7cddfSDavid du Colombier { 2117dd7cddfSDavid du Colombier char *p; 2127dd7cddfSDavid du Colombier String *h; 2137dd7cddfSDavid du Colombier 2147dd7cddfSDavid du Colombier h = s_new(); 2157dd7cddfSDavid du Colombier for(p = m->start + 5; *p && *p != '\r' && *p != '\n'; p++) 2167dd7cddfSDavid du Colombier s_putc(h, *p); 2177dd7cddfSDavid du Colombier s_terminate(h); 2187dd7cddfSDavid du Colombier s_restart(h); 2197dd7cddfSDavid du Colombier 2207dd7cddfSDavid du Colombier m->unixfrom = s_parse(h, s_reset(m->unixfrom)); 2217dd7cddfSDavid du Colombier m->unixdate = s_append(s_reset(m->unixdate), h->ptr); 2227dd7cddfSDavid du Colombier 2237dd7cddfSDavid du Colombier s_free(h); 2247dd7cddfSDavid du Colombier } 2257dd7cddfSDavid du Colombier 2267dd7cddfSDavid du Colombier /* 2277dd7cddfSDavid du Colombier * parse a message 2287dd7cddfSDavid du Colombier */ 22980ee5cbfSDavid du Colombier void 2307a02f3c0SDavid du Colombier parseheaders(Message *m, int justmime, Mailbox *mb, int addfrom) 2317dd7cddfSDavid du Colombier { 2327dd7cddfSDavid du Colombier String *hl; 2337dd7cddfSDavid du Colombier Header *h; 23480ee5cbfSDavid du Colombier char *p, *q; 2357dd7cddfSDavid du Colombier int i; 2367dd7cddfSDavid du Colombier 2377dd7cddfSDavid du Colombier if(m->whole == m->whole->whole){ 2389a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), m->name, 2399a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2407dd7cddfSDavid du Colombier } else { 2419a747e4fSDavid du Colombier henter(PATH(m->whole->id, Qdir), m->name, 2429a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2437dd7cddfSDavid du Colombier } 2447dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 2459a747e4fSDavid du Colombier henter(PATH(m->id, Qdir), dirtab[i], 2469a747e4fSDavid du Colombier (Qid){PATH(m->id, i), 0, QTFILE}, m, mb); 2477dd7cddfSDavid du Colombier 2487dd7cddfSDavid du Colombier // parse mime headers 2497dd7cddfSDavid du Colombier p = m->header; 2507dd7cddfSDavid du Colombier hl = s_new(); 2517dd7cddfSDavid du Colombier while(headerline(&p, hl)){ 2527dd7cddfSDavid du Colombier if(justmime) 2537dd7cddfSDavid du Colombier h = &head[Mhead]; 2547dd7cddfSDavid du Colombier else 2557dd7cddfSDavid du Colombier h = head; 2567dd7cddfSDavid du Colombier for(; h->type; h++){ 2577dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(hl), h->type, h->len) == 0){ 2587dd7cddfSDavid du Colombier (*h->f)(m, h, s_to_c(hl)); 2597dd7cddfSDavid du Colombier break; 2607dd7cddfSDavid du Colombier } 2617dd7cddfSDavid du Colombier } 2627dd7cddfSDavid du Colombier s_reset(hl); 2637dd7cddfSDavid du Colombier } 2647dd7cddfSDavid du Colombier s_free(hl); 2657dd7cddfSDavid du Colombier 2667dd7cddfSDavid du Colombier // the blank line isn't really part of the body or header 2677dd7cddfSDavid du Colombier if(justmime){ 2687dd7cddfSDavid du Colombier m->mhend = p; 2697dd7cddfSDavid du Colombier m->hend = m->header; 2707dd7cddfSDavid du Colombier } else { 2717dd7cddfSDavid du Colombier m->hend = p; 2727dd7cddfSDavid du Colombier } 2737dd7cddfSDavid du Colombier if(*p == '\n') 2747dd7cddfSDavid du Colombier p++; 2757dd7cddfSDavid du Colombier m->rbody = m->body = p; 2767dd7cddfSDavid du Colombier 2773ff48bf5SDavid du Colombier // if type is text, get any nulls out of the body. This is 2783ff48bf5SDavid du Colombier // for the two seans and imap clients that get confused. 2793ff48bf5SDavid du Colombier if(strncmp(s_to_c(m->type), "text/", 5) == 0) 2803ff48bf5SDavid du Colombier nullsqueeze(m); 2813ff48bf5SDavid 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 // 28967031067SDavid du Colombier if(m->unixdate == nil || strcmp(s_to_c(m->unixdate), "???") == 0 29067031067SDavid du Colombier || strcmp(s_to_c(m->unixdate), "Thu Jan 1 00:00:00 GMT 1970") == 0){ 29167031067SDavid du Colombier if(m->unixdate){ 29267031067SDavid du Colombier s_free(m->unixdate); 29367031067SDavid du Colombier m->unixdate = nil; 29467031067SDavid du Colombier } 29580ee5cbfSDavid du Colombier // look for the date in the first Received: line. 29680ee5cbfSDavid du Colombier // it's likely to be the right time zone (it's 29780ee5cbfSDavid du Colombier // the local system) and in a convenient format. 29880ee5cbfSDavid du Colombier if(cistrncmp(m->header, "received:", 9)==0){ 299d9306527SDavid du Colombier if((q = strchr(m->header, ';')) != nil){ 300d9306527SDavid du Colombier p = q; 301d9306527SDavid du Colombier while((p = strchr(p, '\n')) != nil){ 302d9306527SDavid du Colombier if(p[1] != ' ' && p[1] != '\t' && p[1] != '\n') 303d9306527SDavid du Colombier break; 304d9306527SDavid du Colombier p++; 305d9306527SDavid du Colombier } 306d9306527SDavid du Colombier if(p){ 30780ee5cbfSDavid du Colombier *p = '\0'; 30880ee5cbfSDavid du Colombier m->unixdate = date822tounix(q+1); 30980ee5cbfSDavid du Colombier *p = '\n'; 31080ee5cbfSDavid du Colombier } 31180ee5cbfSDavid du Colombier } 312d9306527SDavid du Colombier } 31380ee5cbfSDavid du Colombier 31480ee5cbfSDavid du Colombier // fall back on the rfc822 date 31580ee5cbfSDavid du Colombier if(m->unixdate==nil && m->date822) 31680ee5cbfSDavid du Colombier m->unixdate = date822tounix(s_to_c(m->date822)); 31780ee5cbfSDavid du Colombier } 31880ee5cbfSDavid du Colombier 3199a747e4fSDavid du Colombier if(m->unixheader != nil) 3209a747e4fSDavid du Colombier s_free(m->unixheader); 3217a02f3c0SDavid du Colombier 3227a02f3c0SDavid du Colombier // only fake header for top-level messages for pop3 and imap4 3237a02f3c0SDavid du Colombier // clients (those protocols don't include the unix header). 3247a02f3c0SDavid du Colombier // adding the unix header all the time screws up mime-attached 3257a02f3c0SDavid du Colombier // rfc822 messages. 3267a02f3c0SDavid du Colombier if(!addfrom && !m->unixfrom){ 3277a02f3c0SDavid du Colombier m->unixheader = nil; 3287a02f3c0SDavid du Colombier return; 3297a02f3c0SDavid du Colombier } 3307a02f3c0SDavid du Colombier 33180ee5cbfSDavid du Colombier m->unixheader = s_copy("From "); 33267031067SDavid du Colombier if(m->unixfrom && strcmp(s_to_c(m->unixfrom), "???") != 0) 33380ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixfrom)); 33480ee5cbfSDavid du Colombier else if(m->from822) 33580ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->from822)); 33680ee5cbfSDavid du Colombier else 33780ee5cbfSDavid du Colombier s_append(m->unixheader, "???"); 33880ee5cbfSDavid du Colombier 33980ee5cbfSDavid du Colombier s_append(m->unixheader, " "); 34080ee5cbfSDavid du Colombier if(m->unixdate) 34180ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixdate)); 34280ee5cbfSDavid du Colombier else 34367031067SDavid du Colombier s_append(m->unixheader, "Thu Jan 1 00:00:00 GMT 1970"); 34480ee5cbfSDavid du Colombier 34580ee5cbfSDavid du Colombier s_append(m->unixheader, "\n"); 34680ee5cbfSDavid du Colombier } 34780ee5cbfSDavid du Colombier 3489a747e4fSDavid du Colombier String* 3499a747e4fSDavid du Colombier promote(String **sp) 3509a747e4fSDavid du Colombier { 3519a747e4fSDavid du Colombier String *s; 3529a747e4fSDavid du Colombier 3539a747e4fSDavid du Colombier if(*sp != nil) 3549a747e4fSDavid du Colombier s = s_clone(*sp); 3559a747e4fSDavid du Colombier else 3569a747e4fSDavid du Colombier s = nil; 3579a747e4fSDavid du Colombier return s; 3589a747e4fSDavid du Colombier } 3599a747e4fSDavid du Colombier 36080ee5cbfSDavid du Colombier void 36180ee5cbfSDavid du Colombier parsebody(Message *m, Mailbox *mb) 36280ee5cbfSDavid du Colombier { 3639a747e4fSDavid du Colombier Message *nm; 3649a747e4fSDavid du Colombier 3657dd7cddfSDavid du Colombier // recurse 3667dd7cddfSDavid du Colombier if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){ 3677dd7cddfSDavid du Colombier parseattachments(m, mb); 3687dd7cddfSDavid du Colombier } else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 3697dd7cddfSDavid du Colombier decode(m); 3707dd7cddfSDavid du Colombier parseattachments(m, mb); 3719a747e4fSDavid du Colombier nm = m->part; 3729a747e4fSDavid du Colombier 3739a747e4fSDavid du Colombier // promote headers 3745d459b5aSDavid du Colombier if(m->replyto822 == nil && m->from822 == nil && m->sender822 == nil){ 3759a747e4fSDavid du Colombier m->from822 = promote(&nm->from822); 3769a747e4fSDavid du Colombier m->to822 = promote(&nm->to822); 3779a747e4fSDavid du Colombier m->date822 = promote(&nm->date822); 3789a747e4fSDavid du Colombier m->sender822 = promote(&nm->sender822); 3799a747e4fSDavid du Colombier m->replyto822 = promote(&nm->replyto822); 3809a747e4fSDavid du Colombier m->subject822 = promote(&nm->subject822); 3819a747e4fSDavid du Colombier m->unixdate = promote(&nm->unixdate); 3827dd7cddfSDavid du Colombier } 3837dd7cddfSDavid du Colombier } 3845d459b5aSDavid du Colombier } 3857dd7cddfSDavid du Colombier 38680ee5cbfSDavid du Colombier void 3877a02f3c0SDavid du Colombier parse(Message *m, int justmime, Mailbox *mb, int addfrom) 38880ee5cbfSDavid du Colombier { 3897a02f3c0SDavid du Colombier parseheaders(m, justmime, mb, addfrom); 39080ee5cbfSDavid du Colombier parsebody(m, mb); 39180ee5cbfSDavid du Colombier } 39280ee5cbfSDavid du Colombier 3937dd7cddfSDavid du Colombier static void 3947dd7cddfSDavid du Colombier parseattachments(Message *m, Mailbox *mb) 3957dd7cddfSDavid du Colombier { 3967dd7cddfSDavid du Colombier Message *nm, **l; 3977dd7cddfSDavid du Colombier char *p, *x; 3987dd7cddfSDavid du Colombier 3997dd7cddfSDavid du Colombier // if there's a boundary, recurse... 4007dd7cddfSDavid du Colombier if(m->boundary != nil){ 4017dd7cddfSDavid du Colombier p = m->body; 4027dd7cddfSDavid du Colombier nm = nil; 4037dd7cddfSDavid du Colombier l = &m->part; 4047dd7cddfSDavid du Colombier for(;;){ 4057dd7cddfSDavid du Colombier x = strstr(p, s_to_c(m->boundary)); 4063ff48bf5SDavid du Colombier 4073ff48bf5SDavid du Colombier /* no boundary, we're done */ 4083ff48bf5SDavid du Colombier if(x == nil){ 4097dd7cddfSDavid du Colombier if(nm != nil) 4107dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = m->bend; 4117dd7cddfSDavid du Colombier break; 4127dd7cddfSDavid du Colombier } 4133ff48bf5SDavid du Colombier 4143ff48bf5SDavid du Colombier /* boundary must be at the start of a line */ 4153ff48bf5SDavid du Colombier if(x != m->body && *(x-1) != '\n'){ 4163ff48bf5SDavid du Colombier p = x+1; 4173ff48bf5SDavid du Colombier continue; 4183ff48bf5SDavid du Colombier } 4193ff48bf5SDavid du Colombier 4207dd7cddfSDavid du Colombier if(nm != nil) 4217dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = x; 4227dd7cddfSDavid du Colombier x += strlen(s_to_c(m->boundary)); 4237dd7cddfSDavid du Colombier 4247dd7cddfSDavid du Colombier /* is this the last part? ignore anything after it */ 4257dd7cddfSDavid du Colombier if(strncmp(x, "--", 2) == 0) 4267dd7cddfSDavid du Colombier break; 4277dd7cddfSDavid du Colombier 4287dd7cddfSDavid du Colombier p = strchr(x, '\n'); 4297dd7cddfSDavid du Colombier if(p == nil) 4307dd7cddfSDavid du Colombier break; 4317dd7cddfSDavid du Colombier nm = newmessage(m); 4327dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = ++p; 4337dd7cddfSDavid du Colombier nm->mheader = nm->header; 4347dd7cddfSDavid du Colombier *l = nm; 4357dd7cddfSDavid du Colombier l = &nm->next; 4367dd7cddfSDavid du Colombier } 4377dd7cddfSDavid du Colombier for(nm = m->part; nm != nil; nm = nm->next) 4387a02f3c0SDavid du Colombier parse(nm, 1, mb, 0); 4399a747e4fSDavid du Colombier return; 4407dd7cddfSDavid du Colombier } 4419a747e4fSDavid du Colombier 4429a747e4fSDavid du Colombier // if we've got an rfc822 message, recurse... 4439a747e4fSDavid du Colombier if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 4447dd7cddfSDavid du Colombier nm = newmessage(m); 4457dd7cddfSDavid du Colombier m->part = nm; 4467dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = m->body; 4477dd7cddfSDavid du Colombier nm->end = nm->bend = nm->rbend = m->bend; 4487a02f3c0SDavid du Colombier parse(nm, 0, mb, 0); 4497dd7cddfSDavid du Colombier } 4507dd7cddfSDavid du Colombier } 4517dd7cddfSDavid du Colombier 4527dd7cddfSDavid du Colombier /* 4537dd7cddfSDavid du Colombier * pick up a header line 4547dd7cddfSDavid du Colombier */ 4557dd7cddfSDavid du Colombier static int 4567dd7cddfSDavid du Colombier headerline(char **pp, String *hl) 4577dd7cddfSDavid du Colombier { 4587dd7cddfSDavid du Colombier char *p, *x; 4597dd7cddfSDavid du Colombier 4607dd7cddfSDavid du Colombier s_reset(hl); 4617dd7cddfSDavid du Colombier p = *pp; 4627dd7cddfSDavid du Colombier x = strpbrk(p, ":\n"); 4637dd7cddfSDavid du Colombier if(x == nil || *x == '\n') 4647dd7cddfSDavid du Colombier return 0; 4657dd7cddfSDavid du Colombier for(;;){ 4667dd7cddfSDavid du Colombier x = strchr(p, '\n'); 4677dd7cddfSDavid du Colombier if(x == nil) 4687dd7cddfSDavid du Colombier x = p + strlen(p); 4697dd7cddfSDavid du Colombier s_nappend(hl, p, x-p); 4707dd7cddfSDavid du Colombier p = x; 471223a736eSDavid du Colombier if(*p != '\n' || *++p != ' ' && *p != '\t') 4727dd7cddfSDavid du Colombier break; 473223a736eSDavid du Colombier while(*p == ' ' || *p == '\t') 474223a736eSDavid du Colombier p++; 475223a736eSDavid du Colombier s_putc(hl, ' '); 4767dd7cddfSDavid du Colombier } 4777dd7cddfSDavid du Colombier *pp = p; 4787dd7cddfSDavid du Colombier return 1; 4797dd7cddfSDavid du Colombier } 4807dd7cddfSDavid du Colombier 481*34e11723SDavid du Colombier /* returns nil iff there are no addressees */ 4827dd7cddfSDavid du Colombier static String* 4837dd7cddfSDavid du Colombier addr822(char *p) 4847dd7cddfSDavid du Colombier { 4857dd7cddfSDavid du Colombier String *s, *list; 4867dd7cddfSDavid du Colombier int incomment, addrdone, inanticomment, quoted; 4877dd7cddfSDavid du Colombier int n; 4887dd7cddfSDavid du Colombier int c; 4897dd7cddfSDavid du Colombier 4907dd7cddfSDavid du Colombier list = s_new(); 4917dd7cddfSDavid du Colombier s = s_new(); 4927dd7cddfSDavid du Colombier quoted = incomment = addrdone = inanticomment = 0; 4937dd7cddfSDavid du Colombier n = 0; 4947dd7cddfSDavid du Colombier for(; *p; p++){ 4957dd7cddfSDavid du Colombier c = *p; 4967dd7cddfSDavid du Colombier 4977dd7cddfSDavid du Colombier // whitespace is ignored 4987dd7cddfSDavid du Colombier if(!quoted && isspace(c) || c == '\r') 4997dd7cddfSDavid du Colombier continue; 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier // strings are always treated as atoms 5027dd7cddfSDavid du Colombier if(!quoted && c == '"'){ 5037dd7cddfSDavid du Colombier if(!addrdone && !incomment) 5047dd7cddfSDavid du Colombier s_putc(s, c); 5057dd7cddfSDavid du Colombier for(p++; *p; p++){ 5067dd7cddfSDavid du Colombier if(!addrdone && !incomment) 5077dd7cddfSDavid du Colombier s_putc(s, *p); 5087dd7cddfSDavid du Colombier if(!quoted && *p == '"') 5097dd7cddfSDavid du Colombier break; 5107dd7cddfSDavid du Colombier if(*p == '\\') 5117dd7cddfSDavid du Colombier quoted = 1; 5127dd7cddfSDavid du Colombier else 5137dd7cddfSDavid du Colombier quoted = 0; 5147dd7cddfSDavid du Colombier } 5157dd7cddfSDavid du Colombier if(*p == 0) 5167dd7cddfSDavid du Colombier break; 5177dd7cddfSDavid du Colombier quoted = 0; 5187dd7cddfSDavid du Colombier continue; 5197dd7cddfSDavid du Colombier } 5207dd7cddfSDavid du Colombier 5217dd7cddfSDavid du Colombier // ignore everything in an expicit comment 5227dd7cddfSDavid du Colombier if(!quoted && c == '('){ 5237dd7cddfSDavid du Colombier incomment = 1; 5247dd7cddfSDavid du Colombier continue; 5257dd7cddfSDavid du Colombier } 5267dd7cddfSDavid du Colombier if(incomment){ 5277dd7cddfSDavid du Colombier if(!quoted && c == ')') 5287dd7cddfSDavid du Colombier incomment = 0; 5297dd7cddfSDavid du Colombier quoted = 0; 5307dd7cddfSDavid du Colombier continue; 5317dd7cddfSDavid du Colombier } 5327dd7cddfSDavid du Colombier 5337dd7cddfSDavid du Colombier // anticomments makes everything outside of them comments 5347dd7cddfSDavid du Colombier if(!quoted && c == '<' && !inanticomment){ 5357dd7cddfSDavid du Colombier inanticomment = 1; 5367dd7cddfSDavid du Colombier s = s_reset(s); 5377dd7cddfSDavid du Colombier continue; 5387dd7cddfSDavid du Colombier } 5397dd7cddfSDavid du Colombier if(!quoted && c == '>' && inanticomment){ 5407dd7cddfSDavid du Colombier addrdone = 1; 5417dd7cddfSDavid du Colombier inanticomment = 0; 5427dd7cddfSDavid du Colombier continue; 5437dd7cddfSDavid du Colombier } 5447dd7cddfSDavid du Colombier 5457dd7cddfSDavid du Colombier // commas separate addresses 5467dd7cddfSDavid du Colombier if(!quoted && c == ',' && !inanticomment){ 5477dd7cddfSDavid du Colombier s_terminate(s); 5487dd7cddfSDavid du Colombier addrdone = 0; 5497dd7cddfSDavid du Colombier if(n++ != 0) 5507dd7cddfSDavid du Colombier s_append(list, " "); 5517dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5527dd7cddfSDavid du Colombier s = s_reset(s); 5537dd7cddfSDavid du Colombier continue; 5547dd7cddfSDavid du Colombier } 5557dd7cddfSDavid du Colombier 5567dd7cddfSDavid du Colombier // what's left is part of the address 5577dd7cddfSDavid du Colombier s_putc(s, c); 5587dd7cddfSDavid du Colombier 5597dd7cddfSDavid du Colombier // quoted characters are recognized only as characters 5607dd7cddfSDavid du Colombier if(c == '\\') 5617dd7cddfSDavid du Colombier quoted = 1; 5627dd7cddfSDavid du Colombier else 5637dd7cddfSDavid du Colombier quoted = 0; 5647dd7cddfSDavid du Colombier 5657dd7cddfSDavid du Colombier } 5667dd7cddfSDavid du Colombier 5677dd7cddfSDavid du Colombier if(*s_to_c(s) != 0){ 5687dd7cddfSDavid du Colombier s_terminate(s); 5697dd7cddfSDavid du Colombier if(n++ != 0) 5707dd7cddfSDavid du Colombier s_append(list, " "); 5717dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5727dd7cddfSDavid du Colombier } 5737dd7cddfSDavid du Colombier s_free(s); 5747dd7cddfSDavid du Colombier 575*34e11723SDavid du Colombier if(n == 0){ /* no addressees given, just the keyword */ 5767dd7cddfSDavid du Colombier s_free(list); 5777dd7cddfSDavid du Colombier return nil; 5787dd7cddfSDavid du Colombier } 5797dd7cddfSDavid du Colombier return list; 5807dd7cddfSDavid du Colombier } 5817dd7cddfSDavid du Colombier 5823e748dfcSDavid du Colombier /* 5833e748dfcSDavid du Colombier * per rfc2822 §4.5.3, permit multiple to, cc and bcc headers by 5843e748dfcSDavid du Colombier * concatenating their values. 5853e748dfcSDavid du Colombier */ 5863e748dfcSDavid du Colombier 5877dd7cddfSDavid du Colombier static void 5887dd7cddfSDavid du Colombier to822(Message *m, Header *h, char *p) 5897dd7cddfSDavid du Colombier { 5903e748dfcSDavid du Colombier String *s; 5913e748dfcSDavid du Colombier 5927dd7cddfSDavid du Colombier p += strlen(h->type); 5933e748dfcSDavid du Colombier s = addr822(p); 5943e748dfcSDavid du Colombier if (m->to822 == nil) 5953e748dfcSDavid du Colombier m->to822 = s; 596*34e11723SDavid du Colombier else if (s != nil) { 5973e748dfcSDavid du Colombier s_append(m->to822, " "); 5983e748dfcSDavid du Colombier s_append(m->to822, s_to_c(s)); 5993e748dfcSDavid du Colombier s_free(s); 6003e748dfcSDavid du Colombier } 6017dd7cddfSDavid du Colombier } 6027dd7cddfSDavid du Colombier 6037dd7cddfSDavid du Colombier static void 6047dd7cddfSDavid du Colombier cc822(Message *m, Header *h, char *p) 6057dd7cddfSDavid du Colombier { 6063e748dfcSDavid du Colombier String *s; 6073e748dfcSDavid du Colombier 6087dd7cddfSDavid du Colombier p += strlen(h->type); 6093e748dfcSDavid du Colombier s = addr822(p); 6103e748dfcSDavid du Colombier if (m->cc822 == nil) 6113e748dfcSDavid du Colombier m->cc822 = s; 612*34e11723SDavid du Colombier else if (s != nil) { 6133e748dfcSDavid du Colombier s_append(m->cc822, " "); 6143e748dfcSDavid du Colombier s_append(m->cc822, s_to_c(s)); 6153e748dfcSDavid du Colombier s_free(s); 6163e748dfcSDavid du Colombier } 6177dd7cddfSDavid du Colombier } 6187dd7cddfSDavid du Colombier 6197dd7cddfSDavid du Colombier static void 6207dd7cddfSDavid du Colombier bcc822(Message *m, Header *h, char *p) 6217dd7cddfSDavid du Colombier { 6223e748dfcSDavid du Colombier String *s; 6233e748dfcSDavid du Colombier 6247dd7cddfSDavid du Colombier p += strlen(h->type); 6253e748dfcSDavid du Colombier s = addr822(p); 6263e748dfcSDavid du Colombier if (m->bcc822 == nil) 6273e748dfcSDavid du Colombier m->bcc822 = s; 628*34e11723SDavid du Colombier else if (s != nil) { 6293e748dfcSDavid du Colombier s_append(m->bcc822, " "); 6303e748dfcSDavid du Colombier s_append(m->bcc822, s_to_c(s)); 6313e748dfcSDavid du Colombier s_free(s); 6323e748dfcSDavid du Colombier } 6337dd7cddfSDavid du Colombier } 6347dd7cddfSDavid du Colombier 6357dd7cddfSDavid du Colombier static void 6367dd7cddfSDavid du Colombier from822(Message *m, Header *h, char *p) 6377dd7cddfSDavid du Colombier { 6387dd7cddfSDavid du Colombier p += strlen(h->type); 6397dd7cddfSDavid du Colombier s_free(m->from822); 6407dd7cddfSDavid du Colombier m->from822 = addr822(p); 6417dd7cddfSDavid du Colombier } 6427dd7cddfSDavid du Colombier 6437dd7cddfSDavid du Colombier static void 6447dd7cddfSDavid du Colombier sender822(Message *m, Header *h, char *p) 6457dd7cddfSDavid du Colombier { 6467dd7cddfSDavid du Colombier p += strlen(h->type); 6477dd7cddfSDavid du Colombier s_free(m->sender822); 6487dd7cddfSDavid du Colombier m->sender822 = addr822(p); 6497dd7cddfSDavid du Colombier } 6507dd7cddfSDavid du Colombier 6517dd7cddfSDavid du Colombier static void 6527dd7cddfSDavid du Colombier replyto822(Message *m, Header *h, char *p) 6537dd7cddfSDavid du Colombier { 6547dd7cddfSDavid du Colombier p += strlen(h->type); 6557dd7cddfSDavid du Colombier s_free(m->replyto822); 6567dd7cddfSDavid du Colombier m->replyto822 = addr822(p); 6577dd7cddfSDavid du Colombier } 6587dd7cddfSDavid du Colombier 6597dd7cddfSDavid du Colombier static void 6607dd7cddfSDavid du Colombier mimeversion(Message *m, Header *h, char *p) 6617dd7cddfSDavid du Colombier { 6627dd7cddfSDavid du Colombier p += strlen(h->type); 6637dd7cddfSDavid du Colombier s_free(m->mimeversion); 6647dd7cddfSDavid du Colombier m->mimeversion = addr822(p); 6657dd7cddfSDavid du Colombier } 6667dd7cddfSDavid du Colombier 6677dd7cddfSDavid du Colombier static void 6687dd7cddfSDavid du Colombier killtrailingwhite(char *p) 6697dd7cddfSDavid du Colombier { 6707dd7cddfSDavid du Colombier char *e; 6717dd7cddfSDavid du Colombier 6727dd7cddfSDavid du Colombier e = p + strlen(p) - 1; 6737dd7cddfSDavid du Colombier while(e > p && isspace(*e)) 6747dd7cddfSDavid du Colombier *e-- = 0; 6757dd7cddfSDavid du Colombier } 6767dd7cddfSDavid du Colombier 6777dd7cddfSDavid du Colombier static void 6787dd7cddfSDavid du Colombier date822(Message *m, Header *h, char *p) 6797dd7cddfSDavid du Colombier { 6807dd7cddfSDavid du Colombier p += strlen(h->type); 6817dd7cddfSDavid du Colombier p = skipwhite(p); 6827dd7cddfSDavid du Colombier s_free(m->date822); 6837dd7cddfSDavid du Colombier m->date822 = s_copy(p); 6847dd7cddfSDavid du Colombier p = s_to_c(m->date822); 6857dd7cddfSDavid du Colombier killtrailingwhite(p); 6867dd7cddfSDavid du Colombier } 6877dd7cddfSDavid du Colombier 6887dd7cddfSDavid du Colombier static void 6897dd7cddfSDavid du Colombier subject822(Message *m, Header *h, char *p) 6907dd7cddfSDavid du Colombier { 6917dd7cddfSDavid du Colombier p += strlen(h->type); 6927dd7cddfSDavid du Colombier p = skipwhite(p); 6937dd7cddfSDavid du Colombier s_free(m->subject822); 6947dd7cddfSDavid du Colombier m->subject822 = s_copy(p); 6957dd7cddfSDavid du Colombier p = s_to_c(m->subject822); 6967dd7cddfSDavid du Colombier killtrailingwhite(p); 6977dd7cddfSDavid du Colombier } 6987dd7cddfSDavid du Colombier 6997dd7cddfSDavid du Colombier static void 7007dd7cddfSDavid du Colombier inreplyto822(Message *m, Header *h, char *p) 7017dd7cddfSDavid du Colombier { 7027dd7cddfSDavid du Colombier p += strlen(h->type); 7037dd7cddfSDavid du Colombier p = skipwhite(p); 7047dd7cddfSDavid du Colombier s_free(m->inreplyto822); 7057dd7cddfSDavid du Colombier m->inreplyto822 = s_copy(p); 7067dd7cddfSDavid du Colombier p = s_to_c(m->inreplyto822); 7077dd7cddfSDavid du Colombier killtrailingwhite(p); 7087dd7cddfSDavid du Colombier } 7097dd7cddfSDavid du Colombier 7107dd7cddfSDavid du Colombier static void 7117dd7cddfSDavid du Colombier messageid822(Message *m, Header *h, char *p) 7127dd7cddfSDavid du Colombier { 7137dd7cddfSDavid du Colombier p += strlen(h->type); 7147dd7cddfSDavid du Colombier p = skipwhite(p); 7157dd7cddfSDavid du Colombier s_free(m->messageid822); 7167dd7cddfSDavid du Colombier m->messageid822 = s_copy(p); 7177dd7cddfSDavid du Colombier p = s_to_c(m->messageid822); 7187dd7cddfSDavid du Colombier killtrailingwhite(p); 7197dd7cddfSDavid du Colombier } 7207dd7cddfSDavid du Colombier 7217dd7cddfSDavid du Colombier static int 7227dd7cddfSDavid du Colombier isattribute(char **pp, char *attr) 7237dd7cddfSDavid du Colombier { 7247dd7cddfSDavid du Colombier char *p; 7257dd7cddfSDavid du Colombier int n; 7267dd7cddfSDavid du Colombier 7277dd7cddfSDavid du Colombier n = strlen(attr); 7287dd7cddfSDavid du Colombier p = *pp; 7297dd7cddfSDavid du Colombier if(cistrncmp(p, attr, n) != 0) 7307dd7cddfSDavid du Colombier return 0; 7317dd7cddfSDavid du Colombier p += n; 7327dd7cddfSDavid du Colombier while(*p == ' ') 7337dd7cddfSDavid du Colombier p++; 7347dd7cddfSDavid du Colombier if(*p++ != '=') 7357dd7cddfSDavid du Colombier return 0; 7367dd7cddfSDavid du Colombier while(*p == ' ') 7377dd7cddfSDavid du Colombier p++; 7387dd7cddfSDavid du Colombier *pp = p; 7397dd7cddfSDavid du Colombier return 1; 7407dd7cddfSDavid du Colombier } 7417dd7cddfSDavid du Colombier 7427dd7cddfSDavid du Colombier static void 7437dd7cddfSDavid du Colombier ctype(Message *m, Header *h, char *p) 7447dd7cddfSDavid du Colombier { 7457dd7cddfSDavid du Colombier String *s; 7467dd7cddfSDavid du Colombier 7477dd7cddfSDavid du Colombier p += h->len; 7487dd7cddfSDavid du Colombier p = skipwhite(p); 7497dd7cddfSDavid du Colombier 7507dd7cddfSDavid du Colombier p = getstring(p, m->type, 1); 7517dd7cddfSDavid du Colombier 7527dd7cddfSDavid du Colombier while(*p){ 7537dd7cddfSDavid du Colombier if(isattribute(&p, "boundary")){ 7547dd7cddfSDavid du Colombier s = s_new(); 7557dd7cddfSDavid du Colombier p = getstring(p, s, 0); 7567dd7cddfSDavid du Colombier m->boundary = s_reset(m->boundary); 7577dd7cddfSDavid du Colombier s_append(m->boundary, "--"); 7587dd7cddfSDavid du Colombier s_append(m->boundary, s_to_c(s)); 7597dd7cddfSDavid du Colombier s_free(s); 7607dd7cddfSDavid du Colombier } else if(cistrncmp(p, "multipart", 9) == 0){ 7617dd7cddfSDavid du Colombier /* 7627dd7cddfSDavid du Colombier * the first unbounded part of a multipart message, 7637dd7cddfSDavid du Colombier * the preamble, is not displayed or saved 7647dd7cddfSDavid du Colombier */ 7657dd7cddfSDavid du Colombier } else if(isattribute(&p, "name")){ 7667dd7cddfSDavid du Colombier if(m->filename == nil) 7677dd7cddfSDavid du Colombier setfilename(m, p); 7687dd7cddfSDavid du Colombier } else if(isattribute(&p, "charset")){ 7697dd7cddfSDavid du Colombier p = getstring(p, s_reset(m->charset), 0); 7707dd7cddfSDavid du Colombier } 7717dd7cddfSDavid du Colombier 7727dd7cddfSDavid du Colombier p = skiptosemi(p); 7737dd7cddfSDavid du Colombier } 7747dd7cddfSDavid du Colombier } 7757dd7cddfSDavid du Colombier 7767dd7cddfSDavid du Colombier static void 7777dd7cddfSDavid du Colombier cencoding(Message *m, Header *h, char *p) 7787dd7cddfSDavid du Colombier { 7797dd7cddfSDavid du Colombier p += h->len; 7807dd7cddfSDavid du Colombier p = skipwhite(p); 7817dd7cddfSDavid du Colombier if(cistrncmp(p, "base64", 6) == 0) 7827dd7cddfSDavid du Colombier m->encoding = Ebase64; 7837dd7cddfSDavid du Colombier else if(cistrncmp(p, "quoted-printable", 16) == 0) 7847dd7cddfSDavid du Colombier m->encoding = Equoted; 7857dd7cddfSDavid du Colombier } 7867dd7cddfSDavid du Colombier 7877dd7cddfSDavid du Colombier static void 7887dd7cddfSDavid du Colombier cdisposition(Message *m, Header *h, char *p) 7897dd7cddfSDavid du Colombier { 7907dd7cddfSDavid du Colombier p += h->len; 7917dd7cddfSDavid du Colombier p = skipwhite(p); 7927dd7cddfSDavid du Colombier while(*p){ 7937dd7cddfSDavid du Colombier if(cistrncmp(p, "inline", 6) == 0){ 7947dd7cddfSDavid du Colombier m->disposition = Dinline; 7957dd7cddfSDavid du Colombier } else if(cistrncmp(p, "attachment", 10) == 0){ 7967dd7cddfSDavid du Colombier m->disposition = Dfile; 7977dd7cddfSDavid du Colombier } else if(cistrncmp(p, "filename=", 9) == 0){ 7987dd7cddfSDavid du Colombier p += 9; 7997dd7cddfSDavid du Colombier setfilename(m, p); 8007dd7cddfSDavid du Colombier } 8017dd7cddfSDavid du Colombier p = skiptosemi(p); 8027dd7cddfSDavid du Colombier } 8037dd7cddfSDavid du Colombier 8047dd7cddfSDavid du Colombier } 8057dd7cddfSDavid du Colombier 8067dd7cddfSDavid du Colombier ulong msgallocd, msgfreed; 8077dd7cddfSDavid du Colombier 8087dd7cddfSDavid du Colombier Message* 8097dd7cddfSDavid du Colombier newmessage(Message *parent) 8107dd7cddfSDavid du Colombier { 8117dd7cddfSDavid du Colombier static int id; 8127dd7cddfSDavid du Colombier Message *m; 8137dd7cddfSDavid du Colombier 8147dd7cddfSDavid du Colombier msgallocd++; 8157dd7cddfSDavid du Colombier 8167dd7cddfSDavid du Colombier m = emalloc(sizeof(*m)); 8177dd7cddfSDavid du Colombier memset(m, 0, sizeof(*m)); 8187dd7cddfSDavid du Colombier m->disposition = Dnone; 8197dd7cddfSDavid du Colombier m->type = s_copy("text/plain"); 8207dd7cddfSDavid du Colombier m->charset = s_copy("iso-8859-1"); 8217dd7cddfSDavid du Colombier m->id = newid(); 8227dd7cddfSDavid du Colombier if(parent) 8237dd7cddfSDavid du Colombier sprint(m->name, "%d", ++(parent->subname)); 8247dd7cddfSDavid du Colombier if(parent == nil) 8257dd7cddfSDavid du Colombier parent = m; 8267dd7cddfSDavid du Colombier m->whole = parent; 8277dd7cddfSDavid du Colombier m->hlen = -1; 8287dd7cddfSDavid du Colombier return m; 8297dd7cddfSDavid du Colombier } 8307dd7cddfSDavid du Colombier 8317dd7cddfSDavid du Colombier // delete a message from a mailbox 8327dd7cddfSDavid du Colombier void 8337dd7cddfSDavid du Colombier delmessage(Mailbox *mb, Message *m) 8347dd7cddfSDavid du Colombier { 8357dd7cddfSDavid du Colombier Message **l; 8367dd7cddfSDavid du Colombier int i; 8377dd7cddfSDavid du Colombier 8387dd7cddfSDavid du Colombier mb->vers++; 8397dd7cddfSDavid du Colombier msgfreed++; 8407dd7cddfSDavid du Colombier 8417dd7cddfSDavid du Colombier if(m->whole != m){ 8427dd7cddfSDavid du Colombier // unchain from parent 8437dd7cddfSDavid du Colombier for(l = &m->whole->part; *l && *l != m; l = &(*l)->next) 8447dd7cddfSDavid du Colombier ; 8457dd7cddfSDavid du Colombier if(*l != nil) 8467dd7cddfSDavid du Colombier *l = m->next; 8477dd7cddfSDavid du Colombier 8487dd7cddfSDavid du Colombier // clear out of name lookup hash table 8497dd7cddfSDavid du Colombier if(m->whole->whole == m->whole) 8509a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), m->name); 8517dd7cddfSDavid du Colombier else 8529a747e4fSDavid du Colombier hfree(PATH(m->whole->id, Qdir), m->name); 8537dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 8549a747e4fSDavid du Colombier hfree(PATH(m->id, Qdir), dirtab[i]); 8557dd7cddfSDavid du Colombier } 8567dd7cddfSDavid du Colombier 8577dd7cddfSDavid du Colombier /* recurse through sub-parts */ 8587dd7cddfSDavid du Colombier while(m->part) 8597dd7cddfSDavid du Colombier delmessage(mb, m->part); 8607dd7cddfSDavid du Colombier 8617dd7cddfSDavid du Colombier /* free memory */ 8627dd7cddfSDavid du Colombier if(m->mallocd) 8637dd7cddfSDavid du Colombier free(m->start); 8647dd7cddfSDavid du Colombier if(m->hallocd) 8657dd7cddfSDavid du Colombier free(m->header); 8667dd7cddfSDavid du Colombier if(m->ballocd) 8677dd7cddfSDavid du Colombier free(m->body); 8687dd7cddfSDavid du Colombier s_free(m->unixfrom); 8697dd7cddfSDavid du Colombier s_free(m->unixdate); 8709a747e4fSDavid du Colombier s_free(m->unixheader); 8717dd7cddfSDavid du Colombier s_free(m->from822); 8727dd7cddfSDavid du Colombier s_free(m->sender822); 8737dd7cddfSDavid du Colombier s_free(m->to822); 8747dd7cddfSDavid du Colombier s_free(m->bcc822); 87559cc4ca5SDavid du Colombier s_free(m->cc822); 8767dd7cddfSDavid du Colombier s_free(m->replyto822); 8777dd7cddfSDavid du Colombier s_free(m->date822); 8787dd7cddfSDavid du Colombier s_free(m->inreplyto822); 87959cc4ca5SDavid du Colombier s_free(m->subject822); 8807dd7cddfSDavid du Colombier s_free(m->messageid822); 8817dd7cddfSDavid du Colombier s_free(m->addrs); 8827dd7cddfSDavid du Colombier s_free(m->mimeversion); 88359cc4ca5SDavid du Colombier s_free(m->sdigest); 8847dd7cddfSDavid du Colombier s_free(m->boundary); 8857dd7cddfSDavid du Colombier s_free(m->type); 8867dd7cddfSDavid du Colombier s_free(m->charset); 8877dd7cddfSDavid du Colombier s_free(m->filename); 8887dd7cddfSDavid du Colombier 8897dd7cddfSDavid du Colombier free(m); 8907dd7cddfSDavid du Colombier } 8917dd7cddfSDavid du Colombier 8927dd7cddfSDavid du Colombier // mark messages (identified by path) for deletion 8937dd7cddfSDavid du Colombier void 8947dd7cddfSDavid du Colombier delmessages(int ac, char **av) 8957dd7cddfSDavid du Colombier { 8967dd7cddfSDavid du Colombier Mailbox *mb; 8977dd7cddfSDavid du Colombier Message *m; 8987dd7cddfSDavid du Colombier int i, needwrite; 8997dd7cddfSDavid du Colombier 9007dd7cddfSDavid du Colombier qlock(&mbllock); 9017dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 9027dd7cddfSDavid du Colombier if(strcmp(av[0], mb->name) == 0){ 9037dd7cddfSDavid du Colombier qlock(mb); 9047dd7cddfSDavid du Colombier break; 9057dd7cddfSDavid du Colombier } 9067dd7cddfSDavid du Colombier qunlock(&mbllock); 9077dd7cddfSDavid du Colombier if(mb == nil) 9087dd7cddfSDavid du Colombier return; 9097dd7cddfSDavid du Colombier 9107dd7cddfSDavid du Colombier needwrite = 0; 9117dd7cddfSDavid du Colombier for(i = 1; i < ac; i++){ 9127dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = m->next) 9137dd7cddfSDavid du Colombier if(strcmp(m->name, av[i]) == 0){ 9147dd7cddfSDavid du Colombier if(!m->deleted){ 9157dd7cddfSDavid du Colombier mailplumb(mb, m, 1); 9167dd7cddfSDavid du Colombier needwrite = 1; 9177dd7cddfSDavid du Colombier m->deleted = 1; 91859cc4ca5SDavid du Colombier logmsg("deleting", m); 9197dd7cddfSDavid du Colombier } 9207dd7cddfSDavid du Colombier break; 9217dd7cddfSDavid du Colombier } 9227dd7cddfSDavid du Colombier } 9237dd7cddfSDavid du Colombier if(needwrite) 9247dd7cddfSDavid du Colombier syncmbox(mb, 1); 9257dd7cddfSDavid du Colombier qunlock(mb); 9267dd7cddfSDavid du Colombier } 9277dd7cddfSDavid du Colombier 9287dd7cddfSDavid du Colombier /* 9297dd7cddfSDavid du Colombier * the following are called with the mailbox qlocked 9307dd7cddfSDavid du Colombier */ 9317dd7cddfSDavid du Colombier void 9327dd7cddfSDavid du Colombier msgincref(Message *m) 9337dd7cddfSDavid du Colombier { 9347dd7cddfSDavid du Colombier m->refs++; 9357dd7cddfSDavid du Colombier } 9367dd7cddfSDavid du Colombier void 9377dd7cddfSDavid du Colombier msgdecref(Mailbox *mb, Message *m) 9387dd7cddfSDavid du Colombier { 9397dd7cddfSDavid du Colombier m->refs--; 9407dd7cddfSDavid du Colombier if(m->refs == 0 && m->deleted) 9417dd7cddfSDavid du Colombier syncmbox(mb, 1); 9427dd7cddfSDavid du Colombier } 9437dd7cddfSDavid du Colombier 9447dd7cddfSDavid du Colombier /* 9457dd7cddfSDavid du Colombier * the following are called with mbllock'd 9467dd7cddfSDavid du Colombier */ 9477dd7cddfSDavid du Colombier void 9487dd7cddfSDavid du Colombier mboxincref(Mailbox *mb) 9497dd7cddfSDavid du Colombier { 9509a747e4fSDavid du Colombier assert(mb->refs > 0); 9517dd7cddfSDavid du Colombier mb->refs++; 9527dd7cddfSDavid du Colombier } 9537dd7cddfSDavid du Colombier void 9547dd7cddfSDavid du Colombier mboxdecref(Mailbox *mb) 9557dd7cddfSDavid du Colombier { 9569a747e4fSDavid du Colombier assert(mb->refs > 0); 9577dd7cddfSDavid du Colombier qlock(mb); 9587dd7cddfSDavid du Colombier mb->refs--; 9597dd7cddfSDavid du Colombier if(mb->refs == 0){ 9607dd7cddfSDavid du Colombier delmessage(mb, mb->root); 96180ee5cbfSDavid du Colombier if(mb->ctl) 9629a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), "ctl"); 96380ee5cbfSDavid du Colombier if(mb->close) 96480ee5cbfSDavid du Colombier (*mb->close)(mb); 9657dd7cddfSDavid du Colombier free(mb); 9667dd7cddfSDavid du Colombier } else 9677dd7cddfSDavid du Colombier qunlock(mb); 9687dd7cddfSDavid du Colombier } 9697dd7cddfSDavid du Colombier 9707dd7cddfSDavid du Colombier int 9717dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 9727dd7cddfSDavid du Colombier { 9737dd7cddfSDavid du Colombier while(n-- > 0){ 9747dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 9757dd7cddfSDavid du Colombier return -1; 9767dd7cddfSDavid du Colombier } 9777dd7cddfSDavid du Colombier return 0; 9787dd7cddfSDavid du Colombier } 9797dd7cddfSDavid du Colombier 9807dd7cddfSDavid du Colombier int 9817dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 9827dd7cddfSDavid du Colombier { 9837dd7cddfSDavid du Colombier for(;;){ 9847dd7cddfSDavid du Colombier if(tolower(*a) != tolower(*b++)) 9857dd7cddfSDavid du Colombier return -1; 9867dd7cddfSDavid du Colombier if(*a++ == 0) 9877dd7cddfSDavid du Colombier break; 9887dd7cddfSDavid du Colombier } 9897dd7cddfSDavid du Colombier return 0; 9907dd7cddfSDavid du Colombier } 9917dd7cddfSDavid du Colombier 9927dd7cddfSDavid du Colombier static char* 9937dd7cddfSDavid du Colombier skipwhite(char *p) 9947dd7cddfSDavid du Colombier { 9957dd7cddfSDavid du Colombier while(isspace(*p)) 9967dd7cddfSDavid du Colombier p++; 9977dd7cddfSDavid du Colombier return p; 9987dd7cddfSDavid du Colombier } 9997dd7cddfSDavid du Colombier 10007dd7cddfSDavid du Colombier static char* 10017dd7cddfSDavid du Colombier skiptosemi(char *p) 10027dd7cddfSDavid du Colombier { 10037dd7cddfSDavid du Colombier while(*p && *p != ';') 10047dd7cddfSDavid du Colombier p++; 10057dd7cddfSDavid du Colombier while(*p == ';' || isspace(*p)) 10067dd7cddfSDavid du Colombier p++; 10077dd7cddfSDavid du Colombier return p; 10087dd7cddfSDavid du Colombier } 10097dd7cddfSDavid du Colombier 10107dd7cddfSDavid du Colombier static char* 10117dd7cddfSDavid du Colombier getstring(char *p, String *s, int dolower) 10127dd7cddfSDavid du Colombier { 10137dd7cddfSDavid du Colombier s = s_reset(s); 10147dd7cddfSDavid du Colombier p = skipwhite(p); 10157dd7cddfSDavid du Colombier if(*p == '"'){ 10167dd7cddfSDavid du Colombier p++; 10177dd7cddfSDavid du Colombier for(;*p && *p != '"'; p++) 10187dd7cddfSDavid du Colombier if(dolower) 10197dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 10207dd7cddfSDavid du Colombier else 10217dd7cddfSDavid du Colombier s_putc(s, *p); 10227dd7cddfSDavid du Colombier if(*p == '"') 10237dd7cddfSDavid du Colombier p++; 10247dd7cddfSDavid du Colombier s_terminate(s); 10257dd7cddfSDavid du Colombier 10267dd7cddfSDavid du Colombier return p; 10277dd7cddfSDavid du Colombier } 10287dd7cddfSDavid du Colombier 10299a747e4fSDavid du Colombier for(; *p && !isspace(*p) && *p != ';'; p++) 10307dd7cddfSDavid du Colombier if(dolower) 10317dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 10327dd7cddfSDavid du Colombier else 10337dd7cddfSDavid du Colombier s_putc(s, *p); 10347dd7cddfSDavid du Colombier s_terminate(s); 10357dd7cddfSDavid du Colombier 10367dd7cddfSDavid du Colombier return p; 10377dd7cddfSDavid du Colombier } 10387dd7cddfSDavid du Colombier 10397dd7cddfSDavid du Colombier static void 10407dd7cddfSDavid du Colombier setfilename(Message *m, char *p) 10417dd7cddfSDavid du Colombier { 10427dd7cddfSDavid du Colombier m->filename = s_reset(m->filename); 10437dd7cddfSDavid du Colombier getstring(p, m->filename, 0); 10447dd7cddfSDavid du Colombier for(p = s_to_c(m->filename); *p; p++) 10457dd7cddfSDavid du Colombier if(*p == ' ' || *p == '\t' || *p == ';') 10467dd7cddfSDavid du Colombier *p = '_'; 10477dd7cddfSDavid du Colombier } 10487dd7cddfSDavid du Colombier 10497dd7cddfSDavid du Colombier // 10507dd7cddfSDavid du Colombier // undecode message body 10517dd7cddfSDavid du Colombier // 10527dd7cddfSDavid du Colombier void 10537dd7cddfSDavid du Colombier decode(Message *m) 10547dd7cddfSDavid du Colombier { 10557dd7cddfSDavid du Colombier int i, len; 10567dd7cddfSDavid du Colombier char *x; 10577dd7cddfSDavid du Colombier 10587dd7cddfSDavid du Colombier if(m->decoded) 10597dd7cddfSDavid du Colombier return; 10607dd7cddfSDavid du Colombier switch(m->encoding){ 10617dd7cddfSDavid du Colombier case Ebase64: 10627dd7cddfSDavid du Colombier len = m->bend - m->body; 10637dd7cddfSDavid du Colombier i = (len*3)/4+1; // room for max chars + null 10647dd7cddfSDavid du Colombier x = emalloc(i); 10657dd7cddfSDavid du Colombier len = dec64((uchar*)x, i, m->body, len); 10667dd7cddfSDavid du Colombier if(m->ballocd) 10677dd7cddfSDavid du Colombier free(m->body); 10687dd7cddfSDavid du Colombier m->body = x; 10697dd7cddfSDavid du Colombier m->bend = x + len; 10707dd7cddfSDavid du Colombier m->ballocd = 1; 10717dd7cddfSDavid du Colombier break; 10727dd7cddfSDavid du Colombier case Equoted: 10737dd7cddfSDavid du Colombier len = m->bend - m->body; 10747dd7cddfSDavid du Colombier x = emalloc(len+2); // room for null and possible extra nl 107517dd33a2SDavid du Colombier len = decquoted(x, m->body, m->bend, 0); 10767dd7cddfSDavid du Colombier if(m->ballocd) 10777dd7cddfSDavid du Colombier free(m->body); 10787dd7cddfSDavid du Colombier m->body = x; 10797dd7cddfSDavid du Colombier m->bend = x + len; 10807dd7cddfSDavid du Colombier m->ballocd = 1; 10817dd7cddfSDavid du Colombier break; 10827dd7cddfSDavid du Colombier default: 10837dd7cddfSDavid du Colombier break; 10847dd7cddfSDavid du Colombier } 10857dd7cddfSDavid du Colombier m->decoded = 1; 10867dd7cddfSDavid du Colombier } 10877dd7cddfSDavid du Colombier 10887dd7cddfSDavid du Colombier // convert latin1 to utf 10897dd7cddfSDavid du Colombier void 10907dd7cddfSDavid du Colombier convert(Message *m) 10917dd7cddfSDavid du Colombier { 10927dd7cddfSDavid du Colombier int len; 10937dd7cddfSDavid du Colombier char *x; 10947dd7cddfSDavid du Colombier 10957dd7cddfSDavid du Colombier // don't convert if we're not a leaf, not text, or already converted 10967dd7cddfSDavid du Colombier if(m->converted) 10977dd7cddfSDavid du Colombier return; 10987dd7cddfSDavid du Colombier if(m->part != nil) 10997dd7cddfSDavid du Colombier return; 11007dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(m->type), "text", 4) != 0) 11017dd7cddfSDavid du Colombier return; 11027dd7cddfSDavid du Colombier 1103816336a7SDavid du Colombier len = xtoutf(s_to_c(m->charset), &x, m->body, m->bend); 11047dd7cddfSDavid du Colombier if(len > 0){ 11057dd7cddfSDavid du Colombier if(m->ballocd) 11067dd7cddfSDavid du Colombier free(m->body); 11077dd7cddfSDavid du Colombier m->body = x; 11087dd7cddfSDavid du Colombier m->bend = x + len; 11097dd7cddfSDavid du Colombier m->ballocd = 1; 11107dd7cddfSDavid du Colombier } 11117dd7cddfSDavid du Colombier m->converted = 1; 11127dd7cddfSDavid du Colombier } 11137dd7cddfSDavid du Colombier 11147dd7cddfSDavid du Colombier static int 11157dd7cddfSDavid du Colombier hex2int(int x) 11167dd7cddfSDavid du Colombier { 11177dd7cddfSDavid du Colombier if(x >= '0' && x <= '9') 11187dd7cddfSDavid du Colombier return x - '0'; 11197dd7cddfSDavid du Colombier if(x >= 'A' && x <= 'F') 11207dd7cddfSDavid du Colombier return (x - 'A') + 10; 11217dd7cddfSDavid du Colombier if(x >= 'a' && x <= 'f') 11227dd7cddfSDavid du Colombier return (x - 'a') + 10; 11237dd7cddfSDavid du Colombier return 0; 11247dd7cddfSDavid du Colombier } 11257dd7cddfSDavid du Colombier 1126816336a7SDavid du Colombier // underscores are translated in 2047 headers (uscores=1) 1127816336a7SDavid du Colombier // but not in the body (uscores=0) 11287dd7cddfSDavid du Colombier static char* 112917dd33a2SDavid du Colombier decquotedline(char *out, char *in, char *e, int uscores) 11307dd7cddfSDavid du Colombier { 11317dd7cddfSDavid du Colombier int c, soft; 11327dd7cddfSDavid du Colombier 11337dd7cddfSDavid du Colombier /* dump trailing white space */ 11347dd7cddfSDavid du Colombier while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) 11357dd7cddfSDavid du Colombier e--; 11367dd7cddfSDavid du Colombier 11377dd7cddfSDavid du Colombier /* trailing '=' means no newline */ 11387dd7cddfSDavid du Colombier if(*e == '='){ 11397dd7cddfSDavid du Colombier soft = 1; 11407dd7cddfSDavid du Colombier e--; 11417dd7cddfSDavid du Colombier } else 11427dd7cddfSDavid du Colombier soft = 0; 11437dd7cddfSDavid du Colombier 11447dd7cddfSDavid du Colombier while(in <= e){ 11457dd7cddfSDavid du Colombier c = (*in++) & 0xff; 1146816336a7SDavid du Colombier switch(c){ 1147816336a7SDavid du Colombier case '_': 1148816336a7SDavid du Colombier if(uscores){ 1149816336a7SDavid du Colombier *out++ = ' '; 1150816336a7SDavid du Colombier break; 1151816336a7SDavid du Colombier } 1152816336a7SDavid du Colombier default: 11537dd7cddfSDavid du Colombier *out++ = c; 11547dd7cddfSDavid du Colombier break; 1155816336a7SDavid du Colombier case '=': 11567dd7cddfSDavid du Colombier c = hex2int(*in++)<<4; 11577dd7cddfSDavid du Colombier c |= hex2int(*in++); 11587dd7cddfSDavid du Colombier *out++ = c; 11597dd7cddfSDavid du Colombier break; 11607dd7cddfSDavid du Colombier } 11617dd7cddfSDavid du Colombier } 11627dd7cddfSDavid du Colombier if(!soft) 11637dd7cddfSDavid du Colombier *out++ = '\n'; 11647dd7cddfSDavid du Colombier *out = 0; 11657dd7cddfSDavid du Colombier 11667dd7cddfSDavid du Colombier return out; 11677dd7cddfSDavid du Colombier } 11687dd7cddfSDavid du Colombier 11697dd7cddfSDavid du Colombier int 117017dd33a2SDavid du Colombier decquoted(char *out, char *in, char *e, int uscores) 11717dd7cddfSDavid du Colombier { 11727dd7cddfSDavid du Colombier char *p, *nl; 11737dd7cddfSDavid du Colombier 11747dd7cddfSDavid du Colombier p = out; 11757dd7cddfSDavid du Colombier while((nl = strchr(in, '\n')) != nil && nl < e){ 117617dd33a2SDavid du Colombier p = decquotedline(p, in, nl, uscores); 11777dd7cddfSDavid du Colombier in = nl + 1; 11787dd7cddfSDavid du Colombier } 11797dd7cddfSDavid du Colombier if(in < e) 118017dd33a2SDavid du Colombier p = decquotedline(p, in, e-1, uscores); 11817dd7cddfSDavid du Colombier 11827dd7cddfSDavid du Colombier // make sure we end with a new line 11837dd7cddfSDavid du Colombier if(*(p-1) != '\n'){ 11847dd7cddfSDavid du Colombier *p++ = '\n'; 11857dd7cddfSDavid du Colombier *p = 0; 11867dd7cddfSDavid du Colombier } 11877dd7cddfSDavid du Colombier 11887dd7cddfSDavid du Colombier return p - out; 11897dd7cddfSDavid du Colombier } 11907dd7cddfSDavid du Colombier 11917dd7cddfSDavid du Colombier static char* 11927dd7cddfSDavid du Colombier lowercase(char *p) 11937dd7cddfSDavid du Colombier { 11947dd7cddfSDavid du Colombier char *op; 11957dd7cddfSDavid du Colombier int c; 11967dd7cddfSDavid du Colombier 11977dd7cddfSDavid du Colombier for(op = p; c = *p; p++) 11987dd7cddfSDavid du Colombier if(isupper(c)) 11997dd7cddfSDavid du Colombier *p = tolower(c); 12007dd7cddfSDavid du Colombier return op; 12017dd7cddfSDavid du Colombier } 12027dd7cddfSDavid du Colombier 12037dd7cddfSDavid du Colombier // translate latin1 directly since it fits neatly in utf 1204816336a7SDavid du Colombier static int 1205816336a7SDavid du Colombier latin1toutf(char **out, char *in, char *e) 12067dd7cddfSDavid du Colombier { 1207816336a7SDavid du Colombier int n; 12087dd7cddfSDavid du Colombier char *p; 1209816336a7SDavid du Colombier Rune r; 12107dd7cddfSDavid du Colombier 1211816336a7SDavid du Colombier n = 0; 1212816336a7SDavid du Colombier for(p = in; p < e; p++) 1213816336a7SDavid du Colombier if(*p & 0x80) 1214816336a7SDavid du Colombier n++; 1215816336a7SDavid du Colombier if(n == 0) 1216816336a7SDavid du Colombier return 0; 1217816336a7SDavid du Colombier 1218816336a7SDavid du Colombier n += e-in; 1219816336a7SDavid du Colombier *out = p = malloc(n+1); 1220816336a7SDavid du Colombier if(p == nil) 1221816336a7SDavid du Colombier return 0; 1222816336a7SDavid du Colombier 12237dd7cddfSDavid du Colombier for(; in < e; in++){ 1224816336a7SDavid du Colombier r = (uchar)*in; 12257dd7cddfSDavid du Colombier p += runetochar(p, &r); 12267dd7cddfSDavid du Colombier } 12277dd7cddfSDavid du Colombier *p = 0; 1228816336a7SDavid du Colombier return p - *out; 12297dd7cddfSDavid du Colombier } 12307dd7cddfSDavid du Colombier 1231816336a7SDavid du Colombier // translate any thing using the tcs program 12327dd7cddfSDavid du Colombier int 12337dd7cddfSDavid du Colombier xtoutf(char *charset, char **out, char *in, char *e) 12347dd7cddfSDavid du Colombier { 12357dd7cddfSDavid du Colombier char *av[4]; 12367dd7cddfSDavid du Colombier int totcs[2]; 12377dd7cddfSDavid du Colombier int fromtcs[2]; 12387dd7cddfSDavid du Colombier int n, len, sofar; 12397dd7cddfSDavid du Colombier char *p; 12407dd7cddfSDavid du Colombier 1241816336a7SDavid du Colombier // might not need to convert 1242816336a7SDavid du Colombier if(cistrcmp(charset, "us-ascii") == 0 || cistrcmp(charset, "utf-8") == 0) 1243816336a7SDavid du Colombier return 0; 1244816336a7SDavid du Colombier if(cistrcmp(charset, "iso-8859-1") == 0) 1245816336a7SDavid du Colombier return latin1toutf(out, in, e); 1246816336a7SDavid du Colombier 12477dd7cddfSDavid du Colombier len = e-in+1; 12487dd7cddfSDavid du Colombier sofar = 0; 12497dd7cddfSDavid du Colombier *out = p = malloc(len+1); 12507dd7cddfSDavid du Colombier if(p == nil) 12517dd7cddfSDavid du Colombier return 0; 12527dd7cddfSDavid du Colombier 12537dd7cddfSDavid du Colombier av[0] = charset; 12547dd7cddfSDavid du Colombier av[1] = "-f"; 12557dd7cddfSDavid du Colombier av[2] = charset; 12567dd7cddfSDavid du Colombier av[3] = 0; 12577dd7cddfSDavid du Colombier if(pipe(totcs) < 0) 1258816336a7SDavid du Colombier goto error; 12597dd7cddfSDavid du Colombier if(pipe(fromtcs) < 0){ 12607dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 1261816336a7SDavid du Colombier goto error; 12627dd7cddfSDavid du Colombier } 12637dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12647dd7cddfSDavid du Colombier case -1: 12657dd7cddfSDavid du Colombier close(fromtcs[0]); close(fromtcs[1]); 12667dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 1267816336a7SDavid du Colombier goto error; 12687dd7cddfSDavid du Colombier case 0: 12697dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 12707dd7cddfSDavid du Colombier dup(fromtcs[1], 1); 12717dd7cddfSDavid du Colombier dup(totcs[0], 0); 12727dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 12739a747e4fSDavid du Colombier dup(open("/dev/null", OWRITE), 2); 12747dd7cddfSDavid du Colombier exec("/bin/tcs", av); 12757dd7cddfSDavid du Colombier _exits(0); 12767dd7cddfSDavid du Colombier default: 12777dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 12787dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12797dd7cddfSDavid du Colombier case -1: 12807dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 1281816336a7SDavid du Colombier goto error; 12827dd7cddfSDavid du Colombier case 0: 12837dd7cddfSDavid du Colombier close(fromtcs[0]); 12847dd7cddfSDavid du Colombier while(in < e){ 12857dd7cddfSDavid du Colombier n = write(totcs[1], in, e-in); 12867dd7cddfSDavid du Colombier if(n <= 0) 12877dd7cddfSDavid du Colombier break; 12887dd7cddfSDavid du Colombier in += n; 12897dd7cddfSDavid du Colombier } 12907dd7cddfSDavid du Colombier close(totcs[1]); 12917dd7cddfSDavid du Colombier _exits(0); 12927dd7cddfSDavid du Colombier default: 12937dd7cddfSDavid du Colombier close(totcs[1]); 12947dd7cddfSDavid du Colombier for(;;){ 12957dd7cddfSDavid du Colombier n = read(fromtcs[0], &p[sofar], len-sofar); 12967dd7cddfSDavid du Colombier if(n <= 0) 12977dd7cddfSDavid du Colombier break; 12987dd7cddfSDavid du Colombier sofar += n; 12997dd7cddfSDavid du Colombier p[sofar] = 0; 13007dd7cddfSDavid du Colombier if(sofar == len){ 13017dd7cddfSDavid du Colombier len += 1024; 1302816336a7SDavid du Colombier p = realloc(p, len+1); 13037dd7cddfSDavid du Colombier if(p == nil) 1304816336a7SDavid du Colombier goto error; 1305816336a7SDavid du Colombier *out = p; 13067dd7cddfSDavid du Colombier } 13077dd7cddfSDavid du Colombier } 13087dd7cddfSDavid du Colombier close(fromtcs[0]); 13097dd7cddfSDavid du Colombier break; 13107dd7cddfSDavid du Colombier } 13117dd7cddfSDavid du Colombier break; 13127dd7cddfSDavid du Colombier } 1313816336a7SDavid du Colombier if(sofar == 0) 1314816336a7SDavid du Colombier goto error; 13157dd7cddfSDavid du Colombier return sofar; 13167dd7cddfSDavid du Colombier 1317816336a7SDavid du Colombier error: 1318816336a7SDavid du Colombier free(*out); 1319816336a7SDavid du Colombier *out = nil; 1320816336a7SDavid du Colombier return 0; 13217dd7cddfSDavid du Colombier } 13227dd7cddfSDavid du Colombier 13237dd7cddfSDavid du Colombier void * 13247dd7cddfSDavid du Colombier emalloc(ulong n) 13257dd7cddfSDavid du Colombier { 13267dd7cddfSDavid du Colombier void *p; 13277dd7cddfSDavid du Colombier 13287dd7cddfSDavid du Colombier p = mallocz(n, 1); 13297dd7cddfSDavid du Colombier if(!p){ 133080ee5cbfSDavid du Colombier fprint(2, "%s: out of memory alloc %lud\n", argv0, n); 13317dd7cddfSDavid du Colombier exits("out of memory"); 13327dd7cddfSDavid du Colombier } 133380ee5cbfSDavid du Colombier setmalloctag(p, getcallerpc(&n)); 13347dd7cddfSDavid du Colombier return p; 13357dd7cddfSDavid du Colombier } 13367dd7cddfSDavid du Colombier 13377dd7cddfSDavid du Colombier void * 13387dd7cddfSDavid du Colombier erealloc(void *p, ulong n) 13397dd7cddfSDavid du Colombier { 13403ff48bf5SDavid du Colombier if(n == 0) 13413ff48bf5SDavid du Colombier n = 1; 13427dd7cddfSDavid du Colombier p = realloc(p, n); 13437dd7cddfSDavid du Colombier if(!p){ 134480ee5cbfSDavid du Colombier fprint(2, "%s: out of memory realloc %lud\n", argv0, n); 13457dd7cddfSDavid du Colombier exits("out of memory"); 13467dd7cddfSDavid du Colombier } 134780ee5cbfSDavid du Colombier setrealloctag(p, getcallerpc(&p)); 13487dd7cddfSDavid du Colombier return p; 13497dd7cddfSDavid du Colombier } 13507dd7cddfSDavid du Colombier 13517dd7cddfSDavid du Colombier void 13527dd7cddfSDavid du Colombier mailplumb(Mailbox *mb, Message *m, int delete) 13537dd7cddfSDavid du Colombier { 13547dd7cddfSDavid du Colombier Plumbmsg p; 13557dd7cddfSDavid du Colombier Plumbattr a[7]; 13567dd7cddfSDavid du Colombier char buf[256]; 13577dd7cddfSDavid du Colombier int ai; 13587dd7cddfSDavid du Colombier char lenstr[10], *from, *subject, *date; 13597dd7cddfSDavid du Colombier static int fd = -1; 13607dd7cddfSDavid du Colombier 13617dd7cddfSDavid du Colombier if(m->subject822 == nil) 13627dd7cddfSDavid du Colombier subject = ""; 13637dd7cddfSDavid du Colombier else 13647dd7cddfSDavid du Colombier subject = s_to_c(m->subject822); 13657dd7cddfSDavid du Colombier 13667dd7cddfSDavid du Colombier if(m->from822 != nil) 13677dd7cddfSDavid du Colombier from = s_to_c(m->from822); 13687dd7cddfSDavid du Colombier else if(m->unixfrom != nil) 13697dd7cddfSDavid du Colombier from = s_to_c(m->unixfrom); 13707dd7cddfSDavid du Colombier else 13717dd7cddfSDavid du Colombier from = ""; 13727dd7cddfSDavid du Colombier 13737dd7cddfSDavid du Colombier if(m->unixdate != nil) 13747dd7cddfSDavid du Colombier date = s_to_c(m->unixdate); 13757dd7cddfSDavid du Colombier else 13767dd7cddfSDavid du Colombier date = ""; 13777dd7cddfSDavid du Colombier 13787dd7cddfSDavid du Colombier sprint(lenstr, "%ld", m->end-m->start); 13797dd7cddfSDavid du Colombier 13807dd7cddfSDavid du Colombier if(biffing && !delete) 13817dd7cddfSDavid du Colombier print("[ %s / %s / %s ]\n", from, subject, lenstr); 13827dd7cddfSDavid du Colombier 13837dd7cddfSDavid du Colombier if(!plumbing) 13847dd7cddfSDavid du Colombier return; 13857dd7cddfSDavid du Colombier 13867dd7cddfSDavid du Colombier if(fd < 0) 13877dd7cddfSDavid du Colombier fd = plumbopen("send", OWRITE); 13887dd7cddfSDavid du Colombier if(fd < 0) 13897dd7cddfSDavid du Colombier return; 13907dd7cddfSDavid du Colombier 13917dd7cddfSDavid du Colombier p.src = "mailfs"; 13927dd7cddfSDavid du Colombier p.dst = "seemail"; 13937dd7cddfSDavid du Colombier p.wdir = "/mail/fs"; 13947dd7cddfSDavid du Colombier p.type = "text"; 13957dd7cddfSDavid du Colombier 13967dd7cddfSDavid du Colombier ai = 0; 13977dd7cddfSDavid du Colombier a[ai].name = "filetype"; 13987dd7cddfSDavid du Colombier a[ai].value = "mail"; 13997dd7cddfSDavid du Colombier 14007dd7cddfSDavid du Colombier a[++ai].name = "sender"; 14017dd7cddfSDavid du Colombier a[ai].value = from; 14027dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14037dd7cddfSDavid du Colombier 14047dd7cddfSDavid du Colombier a[++ai].name = "length"; 14057dd7cddfSDavid du Colombier a[ai].value = lenstr; 14067dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14077dd7cddfSDavid du Colombier 14087dd7cddfSDavid du Colombier a[++ai].name = "mailtype"; 14097dd7cddfSDavid du Colombier a[ai].value = delete?"delete":"new"; 14107dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14117dd7cddfSDavid du Colombier 14127dd7cddfSDavid du Colombier a[++ai].name = "date"; 14137dd7cddfSDavid du Colombier a[ai].value = date; 14147dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14157dd7cddfSDavid du Colombier 14169a747e4fSDavid du Colombier if(m->sdigest){ 14177dd7cddfSDavid du Colombier a[++ai].name = "digest"; 14187dd7cddfSDavid du Colombier a[ai].value = s_to_c(m->sdigest); 14197dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14209a747e4fSDavid du Colombier } 14217dd7cddfSDavid du Colombier 14227dd7cddfSDavid du Colombier a[ai].next = nil; 14237dd7cddfSDavid du Colombier 14247dd7cddfSDavid du Colombier p.attr = a; 14257dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/%s/%s", 14267dd7cddfSDavid du Colombier mntpt, mb->name, m->name); 14277dd7cddfSDavid du Colombier p.ndata = strlen(buf); 14287dd7cddfSDavid du Colombier p.data = buf; 14297dd7cddfSDavid du Colombier 14307dd7cddfSDavid du Colombier plumbsend(fd, &p); 14317dd7cddfSDavid du Colombier } 14327dd7cddfSDavid du Colombier 14337dd7cddfSDavid du Colombier // 14347dd7cddfSDavid du Colombier // count the number of lines in the body (for imap4) 14357dd7cddfSDavid du Colombier // 14367dd7cddfSDavid du Colombier void 14377dd7cddfSDavid du Colombier countlines(Message *m) 14387dd7cddfSDavid du Colombier { 14397dd7cddfSDavid du Colombier int i; 14407dd7cddfSDavid du Colombier char *p; 14417dd7cddfSDavid du Colombier 14427dd7cddfSDavid du Colombier i = 0; 14437dd7cddfSDavid du Colombier for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n')) 14447dd7cddfSDavid du Colombier i++; 14457dd7cddfSDavid du Colombier sprint(m->lines, "%d", i); 14467dd7cddfSDavid du Colombier } 144759cc4ca5SDavid du Colombier 144859cc4ca5SDavid du Colombier char *LOG = "fs"; 144959cc4ca5SDavid du Colombier 145059cc4ca5SDavid du Colombier void 145159cc4ca5SDavid du Colombier logmsg(char *s, Message *m) 145259cc4ca5SDavid du Colombier { 145359cc4ca5SDavid du Colombier int pid; 145459cc4ca5SDavid du Colombier 145559cc4ca5SDavid du Colombier if(!logging) 145659cc4ca5SDavid du Colombier return; 145759cc4ca5SDavid du Colombier pid = getpid(); 145859cc4ca5SDavid du Colombier if(m == nil) 145959cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s", user, pid, s); 146059cc4ca5SDavid du Colombier else 146159cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s msg from %s digest %s", 146259cc4ca5SDavid du Colombier user, pid, s, 146359cc4ca5SDavid du Colombier m->from822 ? s_to_c(m->from822) : "?", 146459cc4ca5SDavid du Colombier s_to_c(m->sdigest)); 146559cc4ca5SDavid du Colombier } 146680ee5cbfSDavid du Colombier 14673ff48bf5SDavid du Colombier /* 14683ff48bf5SDavid du Colombier * squeeze nulls out of the body 14693ff48bf5SDavid du Colombier */ 14703ff48bf5SDavid du Colombier static void 14713ff48bf5SDavid du Colombier nullsqueeze(Message *m) 14723ff48bf5SDavid du Colombier { 14733ff48bf5SDavid du Colombier char *p, *q; 14743ff48bf5SDavid du Colombier 14757a02f3c0SDavid du Colombier q = memchr(m->body, 0, m->end-m->body); 14763ff48bf5SDavid du Colombier if(q == nil) 14777a02f3c0SDavid du Colombier return; 14787a02f3c0SDavid du Colombier 14797a02f3c0SDavid du Colombier for(p = m->body; q < m->end; q++){ 14807a02f3c0SDavid du Colombier if(*q == 0) 14817a02f3c0SDavid du Colombier continue; 14827a02f3c0SDavid du Colombier *p++ = *q; 14833ff48bf5SDavid du Colombier } 14847a02f3c0SDavid du Colombier m->bend = m->rbend = m->end = p; 14853ff48bf5SDavid du Colombier } 14863ff48bf5SDavid du Colombier 14873ff48bf5SDavid du Colombier 148880ee5cbfSDavid du Colombier // 148980ee5cbfSDavid du Colombier // convert an RFC822 date into a Unix style date 149080ee5cbfSDavid du Colombier // for when the Unix From line isn't there (e.g. POP3). 149180ee5cbfSDavid du Colombier // enough client programs depend on having a Unix date 149280ee5cbfSDavid du Colombier // that it's easiest to write this conversion code once, right here. 149380ee5cbfSDavid du Colombier // 149480ee5cbfSDavid du Colombier // people don't follow RFC822 particularly closely, 149580ee5cbfSDavid du Colombier // so we use strtotm, which is a bunch of heuristics. 149680ee5cbfSDavid du Colombier // 149780ee5cbfSDavid du Colombier 149880ee5cbfSDavid du Colombier extern int strtotm(char*, Tm*); 149980ee5cbfSDavid du Colombier String* 150080ee5cbfSDavid du Colombier date822tounix(char *s) 150180ee5cbfSDavid du Colombier { 150280ee5cbfSDavid du Colombier char *p, *q; 150380ee5cbfSDavid du Colombier Tm tm; 150480ee5cbfSDavid du Colombier 150580ee5cbfSDavid du Colombier if(strtotm(s, &tm) < 0) 150680ee5cbfSDavid du Colombier return nil; 150780ee5cbfSDavid du Colombier 150880ee5cbfSDavid du Colombier p = asctime(&tm); 150980ee5cbfSDavid du Colombier if(q = strchr(p, '\n')) 151080ee5cbfSDavid du Colombier *q = '\0'; 151180ee5cbfSDavid du Colombier return s_copy(p); 151280ee5cbfSDavid du Colombier } 151380ee5cbfSDavid du Colombier 1514