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; 71*9a747e4fSDavid 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 13380ee5cbfSDavid du Colombier if(rv) 13480ee5cbfSDavid du Colombier return rv; 13580ee5cbfSDavid du Colombier 1367dd7cddfSDavid du Colombier // make sure name isn't taken 1377dd7cddfSDavid du Colombier qlock(&mbllock); 13859cc4ca5SDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next){ 1397dd7cddfSDavid du Colombier if(strcmp((*l)->name, mb->name) == 0){ 14059cc4ca5SDavid du Colombier if(strcmp(path, (*l)->path) == 0) 1417dd7cddfSDavid du Colombier rv = nil; 1427dd7cddfSDavid du Colombier else 1437dd7cddfSDavid du Colombier rv = "mbox name in use"; 14480ee5cbfSDavid du Colombier if(mb->close) 14580ee5cbfSDavid du Colombier (*mb->close)(mb); 1467dd7cddfSDavid du Colombier free(mb); 1477dd7cddfSDavid du Colombier qunlock(&mbllock); 1487dd7cddfSDavid du Colombier return rv; 1497dd7cddfSDavid du Colombier } 15059cc4ca5SDavid du Colombier } 15159cc4ca5SDavid du Colombier 15259cc4ca5SDavid du Colombier // all mailboxes in /mail/box/$user are locked using /mail/box/$user/mbox 15359cc4ca5SDavid du Colombier p = strrchr(stdmbox, '/'); 15459cc4ca5SDavid du Colombier mb->dolock = strncmp(mb->path, stdmbox, p - stdmbox) == 0; 15559cc4ca5SDavid du Colombier 1567dd7cddfSDavid du Colombier mb->refs = 1; 1577dd7cddfSDavid du Colombier mb->next = nil; 1587dd7cddfSDavid du Colombier mb->id = newid(); 1597dd7cddfSDavid du Colombier mb->root = newmessage(nil); 1607dd7cddfSDavid du Colombier mb->std = std; 1617dd7cddfSDavid du Colombier *l = mb; 1627dd7cddfSDavid du Colombier qunlock(&mbllock); 1637dd7cddfSDavid du Colombier 1647dd7cddfSDavid du Colombier qlock(mb); 16580ee5cbfSDavid du Colombier if(mb->ctl){ 166*9a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), "ctl", 167*9a747e4fSDavid du Colombier (Qid){PATH(mb->id, Qmboxctl), 0, QTFILE}, nil, mb); 16880ee5cbfSDavid du Colombier } 1697dd7cddfSDavid du Colombier rv = syncmbox(mb, 0); 1707dd7cddfSDavid du Colombier qunlock(mb); 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier return rv; 1737dd7cddfSDavid du Colombier } 1747dd7cddfSDavid du Colombier 1757dd7cddfSDavid du Colombier // close the named mailbox 1767dd7cddfSDavid du Colombier void 1777dd7cddfSDavid du Colombier freembox(char *name) 1787dd7cddfSDavid du Colombier { 1797dd7cddfSDavid du Colombier Mailbox *mb; 1807dd7cddfSDavid du Colombier 1817dd7cddfSDavid du Colombier qlock(&mbllock); 1827dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 1837dd7cddfSDavid du Colombier if(strcmp(name, mb->name) == 0){ 1847dd7cddfSDavid du Colombier mboxdecref(mb); 1857dd7cddfSDavid du Colombier break; 1867dd7cddfSDavid du Colombier } 187*9a747e4fSDavid 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 23080ee5cbfSDavid du Colombier parseheaders(Message *m, int justmime, Mailbox *mb) 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){ 238*9a747e4fSDavid du Colombier henter(PATH(mb->id, Qmbox), m->name, 239*9a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2407dd7cddfSDavid du Colombier } else { 241*9a747e4fSDavid du Colombier henter(PATH(m->whole->id, Qdir), m->name, 242*9a747e4fSDavid du Colombier (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb); 2437dd7cddfSDavid du Colombier } 2447dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 245*9a747e4fSDavid du Colombier henter(PATH(m->id, Qdir), dirtab[i], 246*9a747e4fSDavid 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 27780ee5cbfSDavid du Colombier // 27880ee5cbfSDavid du Colombier // cobble together Unix-style from line 27980ee5cbfSDavid du Colombier // for local mailbox messages, we end up recreating the 28080ee5cbfSDavid du Colombier // original header. 28180ee5cbfSDavid du Colombier // for pop3 messages, the best we can do is 28280ee5cbfSDavid du Colombier // use the From: information and the RFC822 date. 28380ee5cbfSDavid du Colombier // 28480ee5cbfSDavid du Colombier if(m->unixdate == nil){ 28580ee5cbfSDavid du Colombier // look for the date in the first Received: line. 28680ee5cbfSDavid du Colombier // it's likely to be the right time zone (it's 28780ee5cbfSDavid du Colombier // the local system) and in a convenient format. 28880ee5cbfSDavid du Colombier if(cistrncmp(m->header, "received:", 9)==0){ 28980ee5cbfSDavid du Colombier if((q = strchr(m->header, ';')) 29080ee5cbfSDavid du Colombier && (p = strchr(q, '\n'))){ 29180ee5cbfSDavid du Colombier *p = '\0'; 29280ee5cbfSDavid du Colombier m->unixdate = date822tounix(q+1); 29380ee5cbfSDavid du Colombier *p = '\n'; 29480ee5cbfSDavid du Colombier } 29580ee5cbfSDavid du Colombier } 29680ee5cbfSDavid du Colombier 29780ee5cbfSDavid du Colombier // fall back on the rfc822 date 29880ee5cbfSDavid du Colombier if(m->unixdate==nil && m->date822) 29980ee5cbfSDavid du Colombier m->unixdate = date822tounix(s_to_c(m->date822)); 30080ee5cbfSDavid du Colombier } 30180ee5cbfSDavid du Colombier 302*9a747e4fSDavid du Colombier if(m->unixheader != nil) 303*9a747e4fSDavid du Colombier s_free(m->unixheader); 30480ee5cbfSDavid du Colombier m->unixheader = s_copy("From "); 30580ee5cbfSDavid du Colombier if(m->unixfrom) 30680ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixfrom)); 30780ee5cbfSDavid du Colombier else if(m->from822) 30880ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->from822)); 30980ee5cbfSDavid du Colombier else 31080ee5cbfSDavid du Colombier s_append(m->unixheader, "???"); 31180ee5cbfSDavid du Colombier 31280ee5cbfSDavid du Colombier s_append(m->unixheader, " "); 31380ee5cbfSDavid du Colombier if(m->unixdate) 31480ee5cbfSDavid du Colombier s_append(m->unixheader, s_to_c(m->unixdate)); 31580ee5cbfSDavid du Colombier else 31680ee5cbfSDavid du Colombier s_append(m->unixheader, "Thu Jan 1 00:00:00 EST 1970"); 31780ee5cbfSDavid du Colombier 31880ee5cbfSDavid du Colombier s_append(m->unixheader, "\n"); 31980ee5cbfSDavid du Colombier } 32080ee5cbfSDavid du Colombier 321*9a747e4fSDavid du Colombier String* 322*9a747e4fSDavid du Colombier promote(String **sp) 323*9a747e4fSDavid du Colombier { 324*9a747e4fSDavid du Colombier String *s; 325*9a747e4fSDavid du Colombier 326*9a747e4fSDavid du Colombier if(*sp != nil) 327*9a747e4fSDavid du Colombier s = s_clone(*sp); 328*9a747e4fSDavid du Colombier else 329*9a747e4fSDavid du Colombier s = nil; 330*9a747e4fSDavid du Colombier return s; 331*9a747e4fSDavid du Colombier } 332*9a747e4fSDavid du Colombier 33380ee5cbfSDavid du Colombier void 33480ee5cbfSDavid du Colombier parsebody(Message *m, Mailbox *mb) 33580ee5cbfSDavid du Colombier { 336*9a747e4fSDavid du Colombier Message *nm; 337*9a747e4fSDavid du Colombier 3387dd7cddfSDavid du Colombier // recurse 3397dd7cddfSDavid du Colombier if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){ 3407dd7cddfSDavid du Colombier parseattachments(m, mb); 3417dd7cddfSDavid du Colombier } else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 3427dd7cddfSDavid du Colombier decode(m); 3437dd7cddfSDavid du Colombier parseattachments(m, mb); 344*9a747e4fSDavid du Colombier nm = m->part; 345*9a747e4fSDavid du Colombier 346*9a747e4fSDavid du Colombier // promote headers 347*9a747e4fSDavid du Colombier m->from822 = promote(&nm->from822); 348*9a747e4fSDavid du Colombier m->to822 = promote(&nm->to822); 349*9a747e4fSDavid du Colombier m->date822 = promote(&nm->date822); 350*9a747e4fSDavid du Colombier m->sender822 = promote(&nm->sender822); 351*9a747e4fSDavid du Colombier m->replyto822 = promote(&nm->replyto822); 352*9a747e4fSDavid du Colombier m->subject822 = promote(&nm->subject822); 353*9a747e4fSDavid du Colombier m->unixdate = promote(&nm->unixdate); 3547dd7cddfSDavid du Colombier } 3557dd7cddfSDavid du Colombier } 3567dd7cddfSDavid du Colombier 35780ee5cbfSDavid du Colombier void 35880ee5cbfSDavid du Colombier parse(Message *m, int justmime, Mailbox *mb) 35980ee5cbfSDavid du Colombier { 36080ee5cbfSDavid du Colombier parseheaders(m, justmime, mb); 36180ee5cbfSDavid du Colombier parsebody(m, mb); 36280ee5cbfSDavid du Colombier } 36380ee5cbfSDavid du Colombier 3647dd7cddfSDavid du Colombier static void 3657dd7cddfSDavid du Colombier parseattachments(Message *m, Mailbox *mb) 3667dd7cddfSDavid du Colombier { 3677dd7cddfSDavid du Colombier Message *nm, **l; 3687dd7cddfSDavid du Colombier char *p, *x; 3697dd7cddfSDavid du Colombier 3707dd7cddfSDavid du Colombier // if there's a boundary, recurse... 3717dd7cddfSDavid du Colombier if(m->boundary != nil){ 3727dd7cddfSDavid du Colombier p = m->body; 3737dd7cddfSDavid du Colombier nm = nil; 3747dd7cddfSDavid du Colombier l = &m->part; 3757dd7cddfSDavid du Colombier for(;;){ 3767dd7cddfSDavid du Colombier x = strstr(p, s_to_c(m->boundary)); 3777dd7cddfSDavid du Colombier if(x == nil || (x != m->body && *(x-1) != '\n')){ 3787dd7cddfSDavid du Colombier if(nm != nil) 3797dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = m->bend; 3807dd7cddfSDavid du Colombier break; 3817dd7cddfSDavid du Colombier } 3827dd7cddfSDavid du Colombier if(nm != nil) 3837dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = x; 3847dd7cddfSDavid du Colombier x += strlen(s_to_c(m->boundary)); 3857dd7cddfSDavid du Colombier 3867dd7cddfSDavid du Colombier /* is this the last part? ignore anything after it */ 3877dd7cddfSDavid du Colombier if(strncmp(x, "--", 2) == 0) 3887dd7cddfSDavid du Colombier break; 3897dd7cddfSDavid du Colombier 3907dd7cddfSDavid du Colombier p = strchr(x, '\n'); 3917dd7cddfSDavid du Colombier if(p == nil) 3927dd7cddfSDavid du Colombier break; 3937dd7cddfSDavid du Colombier nm = newmessage(m); 3947dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = ++p; 3957dd7cddfSDavid du Colombier nm->mheader = nm->header; 3967dd7cddfSDavid du Colombier *l = nm; 3977dd7cddfSDavid du Colombier l = &nm->next; 3987dd7cddfSDavid du Colombier } 3997dd7cddfSDavid du Colombier for(nm = m->part; nm != nil; nm = nm->next) 4007dd7cddfSDavid du Colombier parse(nm, 1, mb); 401*9a747e4fSDavid du Colombier return; 4027dd7cddfSDavid du Colombier } 403*9a747e4fSDavid du Colombier 404*9a747e4fSDavid du Colombier // if we've got an rfc822 message, recurse... 405*9a747e4fSDavid du Colombier if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 4067dd7cddfSDavid du Colombier nm = newmessage(m); 4077dd7cddfSDavid du Colombier m->part = nm; 4087dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = m->body; 4097dd7cddfSDavid du Colombier nm->end = nm->bend = nm->rbend = m->bend; 4107dd7cddfSDavid du Colombier parse(nm, 0, mb); 4117dd7cddfSDavid du Colombier } 4127dd7cddfSDavid du Colombier } 4137dd7cddfSDavid du Colombier 4147dd7cddfSDavid du Colombier /* 4157dd7cddfSDavid du Colombier * pick up a header line 4167dd7cddfSDavid du Colombier */ 4177dd7cddfSDavid du Colombier static int 4187dd7cddfSDavid du Colombier headerline(char **pp, String *hl) 4197dd7cddfSDavid du Colombier { 4207dd7cddfSDavid du Colombier char *p, *x; 4217dd7cddfSDavid du Colombier 4227dd7cddfSDavid du Colombier s_reset(hl); 4237dd7cddfSDavid du Colombier p = *pp; 4247dd7cddfSDavid du Colombier x = strpbrk(p, ":\n"); 4257dd7cddfSDavid du Colombier if(x == nil || *x == '\n') 4267dd7cddfSDavid du Colombier return 0; 4277dd7cddfSDavid du Colombier for(;;){ 4287dd7cddfSDavid du Colombier x = strchr(p, '\n'); 4297dd7cddfSDavid du Colombier if(x == nil) 4307dd7cddfSDavid du Colombier x = p + strlen(p); 4317dd7cddfSDavid du Colombier s_nappend(hl, p, x-p); 4327dd7cddfSDavid du Colombier p = x; 433223a736eSDavid du Colombier if(*p != '\n' || *++p != ' ' && *p != '\t') 4347dd7cddfSDavid du Colombier break; 435223a736eSDavid du Colombier while(*p == ' ' || *p == '\t') 436223a736eSDavid du Colombier p++; 437223a736eSDavid du Colombier s_putc(hl, ' '); 4387dd7cddfSDavid du Colombier } 4397dd7cddfSDavid du Colombier *pp = p; 4407dd7cddfSDavid du Colombier return 1; 4417dd7cddfSDavid du Colombier } 4427dd7cddfSDavid du Colombier 4437dd7cddfSDavid du Colombier static String* 4447dd7cddfSDavid du Colombier addr822(char *p) 4457dd7cddfSDavid du Colombier { 4467dd7cddfSDavid du Colombier String *s, *list; 4477dd7cddfSDavid du Colombier int incomment, addrdone, inanticomment, quoted; 4487dd7cddfSDavid du Colombier int n; 4497dd7cddfSDavid du Colombier int c; 4507dd7cddfSDavid du Colombier 4517dd7cddfSDavid du Colombier list = s_new(); 4527dd7cddfSDavid du Colombier s = s_new(); 4537dd7cddfSDavid du Colombier quoted = incomment = addrdone = inanticomment = 0; 4547dd7cddfSDavid du Colombier n = 0; 4557dd7cddfSDavid du Colombier for(; *p; p++){ 4567dd7cddfSDavid du Colombier c = *p; 4577dd7cddfSDavid du Colombier 4587dd7cddfSDavid du Colombier // whitespace is ignored 4597dd7cddfSDavid du Colombier if(!quoted && isspace(c) || c == '\r') 4607dd7cddfSDavid du Colombier continue; 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier // strings are always treated as atoms 4637dd7cddfSDavid du Colombier if(!quoted && c == '"'){ 4647dd7cddfSDavid du Colombier if(!addrdone && !incomment) 4657dd7cddfSDavid du Colombier s_putc(s, c); 4667dd7cddfSDavid du Colombier for(p++; *p; p++){ 4677dd7cddfSDavid du Colombier if(!addrdone && !incomment) 4687dd7cddfSDavid du Colombier s_putc(s, *p); 4697dd7cddfSDavid du Colombier if(!quoted && *p == '"') 4707dd7cddfSDavid du Colombier break; 4717dd7cddfSDavid du Colombier if(*p == '\\') 4727dd7cddfSDavid du Colombier quoted = 1; 4737dd7cddfSDavid du Colombier else 4747dd7cddfSDavid du Colombier quoted = 0; 4757dd7cddfSDavid du Colombier } 4767dd7cddfSDavid du Colombier if(*p == 0) 4777dd7cddfSDavid du Colombier break; 4787dd7cddfSDavid du Colombier quoted = 0; 4797dd7cddfSDavid du Colombier continue; 4807dd7cddfSDavid du Colombier } 4817dd7cddfSDavid du Colombier 4827dd7cddfSDavid du Colombier // ignore everything in an expicit comment 4837dd7cddfSDavid du Colombier if(!quoted && c == '('){ 4847dd7cddfSDavid du Colombier incomment = 1; 4857dd7cddfSDavid du Colombier continue; 4867dd7cddfSDavid du Colombier } 4877dd7cddfSDavid du Colombier if(incomment){ 4887dd7cddfSDavid du Colombier if(!quoted && c == ')') 4897dd7cddfSDavid du Colombier incomment = 0; 4907dd7cddfSDavid du Colombier quoted = 0; 4917dd7cddfSDavid du Colombier continue; 4927dd7cddfSDavid du Colombier } 4937dd7cddfSDavid du Colombier 4947dd7cddfSDavid du Colombier // anticomments makes everything outside of them comments 4957dd7cddfSDavid du Colombier if(!quoted && c == '<' && !inanticomment){ 4967dd7cddfSDavid du Colombier inanticomment = 1; 4977dd7cddfSDavid du Colombier s = s_reset(s); 4987dd7cddfSDavid du Colombier continue; 4997dd7cddfSDavid du Colombier } 5007dd7cddfSDavid du Colombier if(!quoted && c == '>' && inanticomment){ 5017dd7cddfSDavid du Colombier addrdone = 1; 5027dd7cddfSDavid du Colombier inanticomment = 0; 5037dd7cddfSDavid du Colombier continue; 5047dd7cddfSDavid du Colombier } 5057dd7cddfSDavid du Colombier 5067dd7cddfSDavid du Colombier // commas separate addresses 5077dd7cddfSDavid du Colombier if(!quoted && c == ',' && !inanticomment){ 5087dd7cddfSDavid du Colombier s_terminate(s); 5097dd7cddfSDavid du Colombier addrdone = 0; 5107dd7cddfSDavid du Colombier if(n++ != 0) 5117dd7cddfSDavid du Colombier s_append(list, " "); 5127dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5137dd7cddfSDavid du Colombier s = s_reset(s); 5147dd7cddfSDavid du Colombier continue; 5157dd7cddfSDavid du Colombier } 5167dd7cddfSDavid du Colombier 5177dd7cddfSDavid du Colombier // what's left is part of the address 5187dd7cddfSDavid du Colombier s_putc(s, c); 5197dd7cddfSDavid du Colombier 5207dd7cddfSDavid du Colombier // quoted characters are recognized only as characters 5217dd7cddfSDavid du Colombier if(c == '\\') 5227dd7cddfSDavid du Colombier quoted = 1; 5237dd7cddfSDavid du Colombier else 5247dd7cddfSDavid du Colombier quoted = 0; 5257dd7cddfSDavid du Colombier 5267dd7cddfSDavid du Colombier } 5277dd7cddfSDavid du Colombier 5287dd7cddfSDavid du Colombier if(*s_to_c(s) != 0){ 5297dd7cddfSDavid du Colombier s_terminate(s); 5307dd7cddfSDavid du Colombier if(n++ != 0) 5317dd7cddfSDavid du Colombier s_append(list, " "); 5327dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 5337dd7cddfSDavid du Colombier } 5347dd7cddfSDavid du Colombier s_free(s); 5357dd7cddfSDavid du Colombier 5367dd7cddfSDavid du Colombier if(n == 0){ 5377dd7cddfSDavid du Colombier s_free(list); 5387dd7cddfSDavid du Colombier return nil; 5397dd7cddfSDavid du Colombier } 5407dd7cddfSDavid du Colombier return list; 5417dd7cddfSDavid du Colombier } 5427dd7cddfSDavid du Colombier 5437dd7cddfSDavid du Colombier static void 5447dd7cddfSDavid du Colombier to822(Message *m, Header *h, char *p) 5457dd7cddfSDavid du Colombier { 5467dd7cddfSDavid du Colombier p += strlen(h->type); 5477dd7cddfSDavid du Colombier s_free(m->to822); 5487dd7cddfSDavid du Colombier m->to822 = addr822(p); 5497dd7cddfSDavid du Colombier } 5507dd7cddfSDavid du Colombier 5517dd7cddfSDavid du Colombier static void 5527dd7cddfSDavid du Colombier cc822(Message *m, Header *h, char *p) 5537dd7cddfSDavid du Colombier { 5547dd7cddfSDavid du Colombier p += strlen(h->type); 5557dd7cddfSDavid du Colombier s_free(m->cc822); 5567dd7cddfSDavid du Colombier m->cc822 = addr822(p); 5577dd7cddfSDavid du Colombier } 5587dd7cddfSDavid du Colombier 5597dd7cddfSDavid du Colombier static void 5607dd7cddfSDavid du Colombier bcc822(Message *m, Header *h, char *p) 5617dd7cddfSDavid du Colombier { 5627dd7cddfSDavid du Colombier p += strlen(h->type); 5637dd7cddfSDavid du Colombier s_free(m->bcc822); 5647dd7cddfSDavid du Colombier m->bcc822 = addr822(p); 5657dd7cddfSDavid du Colombier } 5667dd7cddfSDavid du Colombier 5677dd7cddfSDavid du Colombier static void 5687dd7cddfSDavid du Colombier from822(Message *m, Header *h, char *p) 5697dd7cddfSDavid du Colombier { 5707dd7cddfSDavid du Colombier p += strlen(h->type); 5717dd7cddfSDavid du Colombier s_free(m->from822); 5727dd7cddfSDavid du Colombier m->from822 = addr822(p); 5737dd7cddfSDavid du Colombier } 5747dd7cddfSDavid du Colombier 5757dd7cddfSDavid du Colombier static void 5767dd7cddfSDavid du Colombier sender822(Message *m, Header *h, char *p) 5777dd7cddfSDavid du Colombier { 5787dd7cddfSDavid du Colombier p += strlen(h->type); 5797dd7cddfSDavid du Colombier s_free(m->sender822); 5807dd7cddfSDavid du Colombier m->sender822 = addr822(p); 5817dd7cddfSDavid du Colombier } 5827dd7cddfSDavid du Colombier 5837dd7cddfSDavid du Colombier static void 5847dd7cddfSDavid du Colombier replyto822(Message *m, Header *h, char *p) 5857dd7cddfSDavid du Colombier { 5867dd7cddfSDavid du Colombier p += strlen(h->type); 5877dd7cddfSDavid du Colombier s_free(m->replyto822); 5887dd7cddfSDavid du Colombier m->replyto822 = addr822(p); 5897dd7cddfSDavid du Colombier } 5907dd7cddfSDavid du Colombier 5917dd7cddfSDavid du Colombier static void 5927dd7cddfSDavid du Colombier mimeversion(Message *m, Header *h, char *p) 5937dd7cddfSDavid du Colombier { 5947dd7cddfSDavid du Colombier p += strlen(h->type); 5957dd7cddfSDavid du Colombier s_free(m->mimeversion); 5967dd7cddfSDavid du Colombier m->mimeversion = addr822(p); 5977dd7cddfSDavid du Colombier } 5987dd7cddfSDavid du Colombier 5997dd7cddfSDavid du Colombier static void 6007dd7cddfSDavid du Colombier killtrailingwhite(char *p) 6017dd7cddfSDavid du Colombier { 6027dd7cddfSDavid du Colombier char *e; 6037dd7cddfSDavid du Colombier 6047dd7cddfSDavid du Colombier e = p + strlen(p) - 1; 6057dd7cddfSDavid du Colombier while(e > p && isspace(*e)) 6067dd7cddfSDavid du Colombier *e-- = 0; 6077dd7cddfSDavid du Colombier } 6087dd7cddfSDavid du Colombier 6097dd7cddfSDavid du Colombier static void 6107dd7cddfSDavid du Colombier date822(Message *m, Header *h, char *p) 6117dd7cddfSDavid du Colombier { 6127dd7cddfSDavid du Colombier p += strlen(h->type); 6137dd7cddfSDavid du Colombier p = skipwhite(p); 6147dd7cddfSDavid du Colombier s_free(m->date822); 6157dd7cddfSDavid du Colombier m->date822 = s_copy(p); 6167dd7cddfSDavid du Colombier p = s_to_c(m->date822); 6177dd7cddfSDavid du Colombier killtrailingwhite(p); 6187dd7cddfSDavid du Colombier } 6197dd7cddfSDavid du Colombier 6207dd7cddfSDavid du Colombier static void 6217dd7cddfSDavid du Colombier subject822(Message *m, Header *h, char *p) 6227dd7cddfSDavid du Colombier { 6237dd7cddfSDavid du Colombier p += strlen(h->type); 6247dd7cddfSDavid du Colombier p = skipwhite(p); 6257dd7cddfSDavid du Colombier s_free(m->subject822); 6267dd7cddfSDavid du Colombier m->subject822 = s_copy(p); 6277dd7cddfSDavid du Colombier p = s_to_c(m->subject822); 6287dd7cddfSDavid du Colombier killtrailingwhite(p); 6297dd7cddfSDavid du Colombier } 6307dd7cddfSDavid du Colombier 6317dd7cddfSDavid du Colombier static void 6327dd7cddfSDavid du Colombier inreplyto822(Message *m, Header *h, char *p) 6337dd7cddfSDavid du Colombier { 6347dd7cddfSDavid du Colombier p += strlen(h->type); 6357dd7cddfSDavid du Colombier p = skipwhite(p); 6367dd7cddfSDavid du Colombier s_free(m->inreplyto822); 6377dd7cddfSDavid du Colombier m->inreplyto822 = s_copy(p); 6387dd7cddfSDavid du Colombier p = s_to_c(m->inreplyto822); 6397dd7cddfSDavid du Colombier killtrailingwhite(p); 6407dd7cddfSDavid du Colombier } 6417dd7cddfSDavid du Colombier 6427dd7cddfSDavid du Colombier static void 6437dd7cddfSDavid du Colombier messageid822(Message *m, Header *h, char *p) 6447dd7cddfSDavid du Colombier { 6457dd7cddfSDavid du Colombier p += strlen(h->type); 6467dd7cddfSDavid du Colombier p = skipwhite(p); 6477dd7cddfSDavid du Colombier s_free(m->messageid822); 6487dd7cddfSDavid du Colombier m->messageid822 = s_copy(p); 6497dd7cddfSDavid du Colombier p = s_to_c(m->messageid822); 6507dd7cddfSDavid du Colombier killtrailingwhite(p); 6517dd7cddfSDavid du Colombier } 6527dd7cddfSDavid du Colombier 6537dd7cddfSDavid du Colombier static int 6547dd7cddfSDavid du Colombier isattribute(char **pp, char *attr) 6557dd7cddfSDavid du Colombier { 6567dd7cddfSDavid du Colombier char *p; 6577dd7cddfSDavid du Colombier int n; 6587dd7cddfSDavid du Colombier 6597dd7cddfSDavid du Colombier n = strlen(attr); 6607dd7cddfSDavid du Colombier p = *pp; 6617dd7cddfSDavid du Colombier if(cistrncmp(p, attr, n) != 0) 6627dd7cddfSDavid du Colombier return 0; 6637dd7cddfSDavid du Colombier p += n; 6647dd7cddfSDavid du Colombier while(*p == ' ') 6657dd7cddfSDavid du Colombier p++; 6667dd7cddfSDavid du Colombier if(*p++ != '=') 6677dd7cddfSDavid du Colombier return 0; 6687dd7cddfSDavid du Colombier while(*p == ' ') 6697dd7cddfSDavid du Colombier p++; 6707dd7cddfSDavid du Colombier *pp = p; 6717dd7cddfSDavid du Colombier return 1; 6727dd7cddfSDavid du Colombier } 6737dd7cddfSDavid du Colombier 6747dd7cddfSDavid du Colombier static void 6757dd7cddfSDavid du Colombier ctype(Message *m, Header *h, char *p) 6767dd7cddfSDavid du Colombier { 6777dd7cddfSDavid du Colombier String *s; 6787dd7cddfSDavid du Colombier 6797dd7cddfSDavid du Colombier p += h->len; 6807dd7cddfSDavid du Colombier p = skipwhite(p); 6817dd7cddfSDavid du Colombier 6827dd7cddfSDavid du Colombier p = getstring(p, m->type, 1); 6837dd7cddfSDavid du Colombier 6847dd7cddfSDavid du Colombier while(*p){ 6857dd7cddfSDavid du Colombier if(isattribute(&p, "boundary")){ 6867dd7cddfSDavid du Colombier s = s_new(); 6877dd7cddfSDavid du Colombier p = getstring(p, s, 0); 6887dd7cddfSDavid du Colombier m->boundary = s_reset(m->boundary); 6897dd7cddfSDavid du Colombier s_append(m->boundary, "--"); 6907dd7cddfSDavid du Colombier s_append(m->boundary, s_to_c(s)); 6917dd7cddfSDavid du Colombier s_free(s); 6927dd7cddfSDavid du Colombier } else if(cistrncmp(p, "multipart", 9) == 0){ 6937dd7cddfSDavid du Colombier /* 6947dd7cddfSDavid du Colombier * the first unbounded part of a multipart message, 6957dd7cddfSDavid du Colombier * the preamble, is not displayed or saved 6967dd7cddfSDavid du Colombier */ 6977dd7cddfSDavid du Colombier } else if(isattribute(&p, "name")){ 6987dd7cddfSDavid du Colombier if(m->filename == nil) 6997dd7cddfSDavid du Colombier setfilename(m, p); 7007dd7cddfSDavid du Colombier } else if(isattribute(&p, "charset")){ 7017dd7cddfSDavid du Colombier p = getstring(p, s_reset(m->charset), 0); 7027dd7cddfSDavid du Colombier } 7037dd7cddfSDavid du Colombier 7047dd7cddfSDavid du Colombier p = skiptosemi(p); 7057dd7cddfSDavid du Colombier } 7067dd7cddfSDavid du Colombier } 7077dd7cddfSDavid du Colombier 7087dd7cddfSDavid du Colombier static void 7097dd7cddfSDavid du Colombier cencoding(Message *m, Header *h, char *p) 7107dd7cddfSDavid du Colombier { 7117dd7cddfSDavid du Colombier p += h->len; 7127dd7cddfSDavid du Colombier p = skipwhite(p); 7137dd7cddfSDavid du Colombier if(cistrncmp(p, "base64", 6) == 0) 7147dd7cddfSDavid du Colombier m->encoding = Ebase64; 7157dd7cddfSDavid du Colombier else if(cistrncmp(p, "quoted-printable", 16) == 0) 7167dd7cddfSDavid du Colombier m->encoding = Equoted; 7177dd7cddfSDavid du Colombier } 7187dd7cddfSDavid du Colombier 7197dd7cddfSDavid du Colombier static void 7207dd7cddfSDavid du Colombier cdisposition(Message *m, Header *h, char *p) 7217dd7cddfSDavid du Colombier { 7227dd7cddfSDavid du Colombier p += h->len; 7237dd7cddfSDavid du Colombier p = skipwhite(p); 7247dd7cddfSDavid du Colombier while(*p){ 7257dd7cddfSDavid du Colombier if(cistrncmp(p, "inline", 6) == 0){ 7267dd7cddfSDavid du Colombier m->disposition = Dinline; 7277dd7cddfSDavid du Colombier } else if(cistrncmp(p, "attachment", 10) == 0){ 7287dd7cddfSDavid du Colombier m->disposition = Dfile; 7297dd7cddfSDavid du Colombier } else if(cistrncmp(p, "filename=", 9) == 0){ 7307dd7cddfSDavid du Colombier p += 9; 7317dd7cddfSDavid du Colombier setfilename(m, p); 7327dd7cddfSDavid du Colombier } 7337dd7cddfSDavid du Colombier p = skiptosemi(p); 7347dd7cddfSDavid du Colombier } 7357dd7cddfSDavid du Colombier 7367dd7cddfSDavid du Colombier } 7377dd7cddfSDavid du Colombier 7387dd7cddfSDavid du Colombier ulong msgallocd, msgfreed; 7397dd7cddfSDavid du Colombier 7407dd7cddfSDavid du Colombier Message* 7417dd7cddfSDavid du Colombier newmessage(Message *parent) 7427dd7cddfSDavid du Colombier { 7437dd7cddfSDavid du Colombier static int id; 7447dd7cddfSDavid du Colombier Message *m; 7457dd7cddfSDavid du Colombier 7467dd7cddfSDavid du Colombier msgallocd++; 7477dd7cddfSDavid du Colombier 7487dd7cddfSDavid du Colombier m = emalloc(sizeof(*m)); 7497dd7cddfSDavid du Colombier memset(m, 0, sizeof(*m)); 7507dd7cddfSDavid du Colombier m->disposition = Dnone; 7517dd7cddfSDavid du Colombier m->type = s_copy("text/plain"); 7527dd7cddfSDavid du Colombier m->charset = s_copy("iso-8859-1"); 7537dd7cddfSDavid du Colombier m->id = newid(); 7547dd7cddfSDavid du Colombier if(parent) 7557dd7cddfSDavid du Colombier sprint(m->name, "%d", ++(parent->subname)); 7567dd7cddfSDavid du Colombier if(parent == nil) 7577dd7cddfSDavid du Colombier parent = m; 7587dd7cddfSDavid du Colombier m->whole = parent; 7597dd7cddfSDavid du Colombier m->hlen = -1; 7607dd7cddfSDavid du Colombier return m; 7617dd7cddfSDavid du Colombier } 7627dd7cddfSDavid du Colombier 7637dd7cddfSDavid du Colombier // delete a message from a mailbox 7647dd7cddfSDavid du Colombier void 7657dd7cddfSDavid du Colombier delmessage(Mailbox *mb, Message *m) 7667dd7cddfSDavid du Colombier { 7677dd7cddfSDavid du Colombier Message **l; 7687dd7cddfSDavid du Colombier int i; 7697dd7cddfSDavid du Colombier 7707dd7cddfSDavid du Colombier mb->vers++; 7717dd7cddfSDavid du Colombier msgfreed++; 7727dd7cddfSDavid du Colombier 7737dd7cddfSDavid du Colombier if(m->whole != m){ 7747dd7cddfSDavid du Colombier // unchain from parent 7757dd7cddfSDavid du Colombier for(l = &m->whole->part; *l && *l != m; l = &(*l)->next) 7767dd7cddfSDavid du Colombier ; 7777dd7cddfSDavid du Colombier if(*l != nil) 7787dd7cddfSDavid du Colombier *l = m->next; 7797dd7cddfSDavid du Colombier 7807dd7cddfSDavid du Colombier // clear out of name lookup hash table 7817dd7cddfSDavid du Colombier if(m->whole->whole == m->whole) 782*9a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), m->name); 7837dd7cddfSDavid du Colombier else 784*9a747e4fSDavid du Colombier hfree(PATH(m->whole->id, Qdir), m->name); 7857dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 786*9a747e4fSDavid du Colombier hfree(PATH(m->id, Qdir), dirtab[i]); 7877dd7cddfSDavid du Colombier } 7887dd7cddfSDavid du Colombier 7897dd7cddfSDavid du Colombier /* recurse through sub-parts */ 7907dd7cddfSDavid du Colombier while(m->part) 7917dd7cddfSDavid du Colombier delmessage(mb, m->part); 7927dd7cddfSDavid du Colombier 7937dd7cddfSDavid du Colombier /* free memory */ 7947dd7cddfSDavid du Colombier if(m->mallocd) 7957dd7cddfSDavid du Colombier free(m->start); 7967dd7cddfSDavid du Colombier if(m->hallocd) 7977dd7cddfSDavid du Colombier free(m->header); 7987dd7cddfSDavid du Colombier if(m->ballocd) 7997dd7cddfSDavid du Colombier free(m->body); 8007dd7cddfSDavid du Colombier s_free(m->unixfrom); 8017dd7cddfSDavid du Colombier s_free(m->unixdate); 802*9a747e4fSDavid du Colombier s_free(m->unixheader); 8037dd7cddfSDavid du Colombier s_free(m->from822); 8047dd7cddfSDavid du Colombier s_free(m->sender822); 8057dd7cddfSDavid du Colombier s_free(m->to822); 8067dd7cddfSDavid du Colombier s_free(m->bcc822); 80759cc4ca5SDavid du Colombier s_free(m->cc822); 8087dd7cddfSDavid du Colombier s_free(m->replyto822); 8097dd7cddfSDavid du Colombier s_free(m->date822); 8107dd7cddfSDavid du Colombier s_free(m->inreplyto822); 81159cc4ca5SDavid du Colombier s_free(m->subject822); 8127dd7cddfSDavid du Colombier s_free(m->messageid822); 8137dd7cddfSDavid du Colombier s_free(m->addrs); 8147dd7cddfSDavid du Colombier s_free(m->mimeversion); 81559cc4ca5SDavid du Colombier s_free(m->sdigest); 8167dd7cddfSDavid du Colombier s_free(m->boundary); 8177dd7cddfSDavid du Colombier s_free(m->type); 8187dd7cddfSDavid du Colombier s_free(m->charset); 8197dd7cddfSDavid du Colombier s_free(m->filename); 8207dd7cddfSDavid du Colombier 8217dd7cddfSDavid du Colombier free(m); 8227dd7cddfSDavid du Colombier } 8237dd7cddfSDavid du Colombier 8247dd7cddfSDavid du Colombier // mark messages (identified by path) for deletion 8257dd7cddfSDavid du Colombier void 8267dd7cddfSDavid du Colombier delmessages(int ac, char **av) 8277dd7cddfSDavid du Colombier { 8287dd7cddfSDavid du Colombier Mailbox *mb; 8297dd7cddfSDavid du Colombier Message *m; 8307dd7cddfSDavid du Colombier int i, needwrite; 8317dd7cddfSDavid du Colombier 8327dd7cddfSDavid du Colombier qlock(&mbllock); 8337dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 8347dd7cddfSDavid du Colombier if(strcmp(av[0], mb->name) == 0){ 8357dd7cddfSDavid du Colombier qlock(mb); 8367dd7cddfSDavid du Colombier break; 8377dd7cddfSDavid du Colombier } 8387dd7cddfSDavid du Colombier qunlock(&mbllock); 8397dd7cddfSDavid du Colombier if(mb == nil) 8407dd7cddfSDavid du Colombier return; 8417dd7cddfSDavid du Colombier 8427dd7cddfSDavid du Colombier needwrite = 0; 8437dd7cddfSDavid du Colombier for(i = 1; i < ac; i++){ 8447dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = m->next) 8457dd7cddfSDavid du Colombier if(strcmp(m->name, av[i]) == 0){ 8467dd7cddfSDavid du Colombier if(!m->deleted){ 8477dd7cddfSDavid du Colombier mailplumb(mb, m, 1); 8487dd7cddfSDavid du Colombier needwrite = 1; 8497dd7cddfSDavid du Colombier m->deleted = 1; 85059cc4ca5SDavid du Colombier logmsg("deleting", m); 8517dd7cddfSDavid du Colombier } 8527dd7cddfSDavid du Colombier break; 8537dd7cddfSDavid du Colombier } 8547dd7cddfSDavid du Colombier } 8557dd7cddfSDavid du Colombier if(needwrite) 8567dd7cddfSDavid du Colombier syncmbox(mb, 1); 8577dd7cddfSDavid du Colombier qunlock(mb); 8587dd7cddfSDavid du Colombier } 8597dd7cddfSDavid du Colombier 8607dd7cddfSDavid du Colombier /* 8617dd7cddfSDavid du Colombier * the following are called with the mailbox qlocked 8627dd7cddfSDavid du Colombier */ 8637dd7cddfSDavid du Colombier void 8647dd7cddfSDavid du Colombier msgincref(Message *m) 8657dd7cddfSDavid du Colombier { 8667dd7cddfSDavid du Colombier m->refs++; 8677dd7cddfSDavid du Colombier } 8687dd7cddfSDavid du Colombier void 8697dd7cddfSDavid du Colombier msgdecref(Mailbox *mb, Message *m) 8707dd7cddfSDavid du Colombier { 8717dd7cddfSDavid du Colombier m->refs--; 8727dd7cddfSDavid du Colombier if(m->refs == 0 && m->deleted) 8737dd7cddfSDavid du Colombier syncmbox(mb, 1); 8747dd7cddfSDavid du Colombier } 8757dd7cddfSDavid du Colombier 8767dd7cddfSDavid du Colombier /* 8777dd7cddfSDavid du Colombier * the following are called with mbllock'd 8787dd7cddfSDavid du Colombier */ 8797dd7cddfSDavid du Colombier void 8807dd7cddfSDavid du Colombier mboxincref(Mailbox *mb) 8817dd7cddfSDavid du Colombier { 882*9a747e4fSDavid du Colombier assert(mb->refs > 0); 8837dd7cddfSDavid du Colombier mb->refs++; 8847dd7cddfSDavid du Colombier } 8857dd7cddfSDavid du Colombier void 8867dd7cddfSDavid du Colombier mboxdecref(Mailbox *mb) 8877dd7cddfSDavid du Colombier { 8887dd7cddfSDavid du Colombier Mailbox **l; 8897dd7cddfSDavid du Colombier 890*9a747e4fSDavid du Colombier assert(mb->refs > 0); 8917dd7cddfSDavid du Colombier qlock(mb); 8927dd7cddfSDavid du Colombier mb->refs--; 8937dd7cddfSDavid du Colombier if(mb->refs == 0){ 8947dd7cddfSDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next){ 8957dd7cddfSDavid du Colombier if(*l == mb){ 8967dd7cddfSDavid du Colombier *l = mb->next; 8977dd7cddfSDavid du Colombier break; 8987dd7cddfSDavid du Colombier } 8997dd7cddfSDavid du Colombier } 9007dd7cddfSDavid du Colombier delmessage(mb, mb->root); 9017dd7cddfSDavid du Colombier qunlock(mb); 90280ee5cbfSDavid du Colombier if(mb->ctl) 903*9a747e4fSDavid du Colombier hfree(PATH(mb->id, Qmbox), "ctl"); 90480ee5cbfSDavid du Colombier if(mb->close) 90580ee5cbfSDavid du Colombier (*mb->close)(mb); 9067dd7cddfSDavid du Colombier free(mb); 9077dd7cddfSDavid du Colombier } else 9087dd7cddfSDavid du Colombier qunlock(mb); 9097dd7cddfSDavid du Colombier } 9107dd7cddfSDavid du Colombier 9117dd7cddfSDavid du Colombier int 9127dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 9137dd7cddfSDavid du Colombier { 9147dd7cddfSDavid du Colombier while(n-- > 0){ 9157dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 9167dd7cddfSDavid du Colombier return -1; 9177dd7cddfSDavid du Colombier } 9187dd7cddfSDavid du Colombier return 0; 9197dd7cddfSDavid du Colombier } 9207dd7cddfSDavid du Colombier 9217dd7cddfSDavid du Colombier int 9227dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 9237dd7cddfSDavid du Colombier { 9247dd7cddfSDavid du Colombier for(;;){ 9257dd7cddfSDavid du Colombier if(tolower(*a) != tolower(*b++)) 9267dd7cddfSDavid du Colombier return -1; 9277dd7cddfSDavid du Colombier if(*a++ == 0) 9287dd7cddfSDavid du Colombier break; 9297dd7cddfSDavid du Colombier } 9307dd7cddfSDavid du Colombier return 0; 9317dd7cddfSDavid du Colombier } 9327dd7cddfSDavid du Colombier 9337dd7cddfSDavid du Colombier static char* 9347dd7cddfSDavid du Colombier skipwhite(char *p) 9357dd7cddfSDavid du Colombier { 9367dd7cddfSDavid du Colombier while(isspace(*p)) 9377dd7cddfSDavid du Colombier p++; 9387dd7cddfSDavid du Colombier return p; 9397dd7cddfSDavid du Colombier } 9407dd7cddfSDavid du Colombier 9417dd7cddfSDavid du Colombier static char* 9427dd7cddfSDavid du Colombier skiptosemi(char *p) 9437dd7cddfSDavid du Colombier { 9447dd7cddfSDavid du Colombier while(*p && *p != ';') 9457dd7cddfSDavid du Colombier p++; 9467dd7cddfSDavid du Colombier while(*p == ';' || isspace(*p)) 9477dd7cddfSDavid du Colombier p++; 9487dd7cddfSDavid du Colombier return p; 9497dd7cddfSDavid du Colombier } 9507dd7cddfSDavid du Colombier 9517dd7cddfSDavid du Colombier static char* 9527dd7cddfSDavid du Colombier getstring(char *p, String *s, int dolower) 9537dd7cddfSDavid du Colombier { 9547dd7cddfSDavid du Colombier s = s_reset(s); 9557dd7cddfSDavid du Colombier p = skipwhite(p); 9567dd7cddfSDavid du Colombier if(*p == '"'){ 9577dd7cddfSDavid du Colombier p++; 9587dd7cddfSDavid du Colombier for(;*p && *p != '"'; p++) 9597dd7cddfSDavid du Colombier if(dolower) 9607dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 9617dd7cddfSDavid du Colombier else 9627dd7cddfSDavid du Colombier s_putc(s, *p); 9637dd7cddfSDavid du Colombier if(*p == '"') 9647dd7cddfSDavid du Colombier p++; 9657dd7cddfSDavid du Colombier s_terminate(s); 9667dd7cddfSDavid du Colombier 9677dd7cddfSDavid du Colombier return p; 9687dd7cddfSDavid du Colombier } 9697dd7cddfSDavid du Colombier 970*9a747e4fSDavid du Colombier for(; *p && !isspace(*p) && *p != ';'; p++) 9717dd7cddfSDavid du Colombier if(dolower) 9727dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 9737dd7cddfSDavid du Colombier else 9747dd7cddfSDavid du Colombier s_putc(s, *p); 9757dd7cddfSDavid du Colombier s_terminate(s); 9767dd7cddfSDavid du Colombier 9777dd7cddfSDavid du Colombier return p; 9787dd7cddfSDavid du Colombier } 9797dd7cddfSDavid du Colombier 9807dd7cddfSDavid du Colombier static void 9817dd7cddfSDavid du Colombier setfilename(Message *m, char *p) 9827dd7cddfSDavid du Colombier { 9837dd7cddfSDavid du Colombier m->filename = s_reset(m->filename); 9847dd7cddfSDavid du Colombier getstring(p, m->filename, 0); 9857dd7cddfSDavid du Colombier for(p = s_to_c(m->filename); *p; p++) 9867dd7cddfSDavid du Colombier if(*p == ' ' || *p == '\t' || *p == ';') 9877dd7cddfSDavid du Colombier *p = '_'; 9887dd7cddfSDavid du Colombier } 9897dd7cddfSDavid du Colombier 9907dd7cddfSDavid du Colombier // 9917dd7cddfSDavid du Colombier // undecode message body 9927dd7cddfSDavid du Colombier // 9937dd7cddfSDavid du Colombier void 9947dd7cddfSDavid du Colombier decode(Message *m) 9957dd7cddfSDavid du Colombier { 9967dd7cddfSDavid du Colombier int i, len; 9977dd7cddfSDavid du Colombier char *x; 9987dd7cddfSDavid du Colombier 9997dd7cddfSDavid du Colombier if(m->decoded) 10007dd7cddfSDavid du Colombier return; 10017dd7cddfSDavid du Colombier switch(m->encoding){ 10027dd7cddfSDavid du Colombier case Ebase64: 10037dd7cddfSDavid du Colombier len = m->bend - m->body; 10047dd7cddfSDavid du Colombier i = (len*3)/4+1; // room for max chars + null 10057dd7cddfSDavid du Colombier x = emalloc(i); 10067dd7cddfSDavid du Colombier len = dec64((uchar*)x, i, m->body, len); 10077dd7cddfSDavid du Colombier if(m->ballocd) 10087dd7cddfSDavid du Colombier free(m->body); 10097dd7cddfSDavid du Colombier m->body = x; 10107dd7cddfSDavid du Colombier m->bend = x + len; 10117dd7cddfSDavid du Colombier m->ballocd = 1; 10127dd7cddfSDavid du Colombier break; 10137dd7cddfSDavid du Colombier case Equoted: 10147dd7cddfSDavid du Colombier len = m->bend - m->body; 10157dd7cddfSDavid du Colombier x = emalloc(len+2); // room for null and possible extra nl 10167dd7cddfSDavid du Colombier len = decquoted(x, m->body, m->bend); 10177dd7cddfSDavid du Colombier if(m->ballocd) 10187dd7cddfSDavid du Colombier free(m->body); 10197dd7cddfSDavid du Colombier m->body = x; 10207dd7cddfSDavid du Colombier m->bend = x + len; 10217dd7cddfSDavid du Colombier m->ballocd = 1; 10227dd7cddfSDavid du Colombier break; 10237dd7cddfSDavid du Colombier default: 10247dd7cddfSDavid du Colombier break; 10257dd7cddfSDavid du Colombier } 10267dd7cddfSDavid du Colombier m->decoded = 1; 10277dd7cddfSDavid du Colombier } 10287dd7cddfSDavid du Colombier 10297dd7cddfSDavid du Colombier // convert latin1 to utf 10307dd7cddfSDavid du Colombier void 10317dd7cddfSDavid du Colombier convert(Message *m) 10327dd7cddfSDavid du Colombier { 10337dd7cddfSDavid du Colombier int len; 10347dd7cddfSDavid du Colombier char *x; 10357dd7cddfSDavid du Colombier 10367dd7cddfSDavid du Colombier // don't convert if we're not a leaf, not text, or already converted 10377dd7cddfSDavid du Colombier if(m->converted) 10387dd7cddfSDavid du Colombier return; 10397dd7cddfSDavid du Colombier if(m->part != nil) 10407dd7cddfSDavid du Colombier return; 10417dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(m->type), "text", 4) != 0) 10427dd7cddfSDavid du Colombier return; 10437dd7cddfSDavid du Colombier 10447dd7cddfSDavid du Colombier if(cistrcmp(s_to_c(m->charset), "us-ascii") == 0 || 10457dd7cddfSDavid du Colombier cistrcmp(s_to_c(m->charset), "iso-8859-1") == 0){ 10467dd7cddfSDavid du Colombier len = is8bit(m); 10477dd7cddfSDavid du Colombier if(len > 0){ 10487dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 10497dd7cddfSDavid du Colombier x = emalloc(len); 10507dd7cddfSDavid du Colombier len = latin1toutf(x, m->body, m->bend); 10517dd7cddfSDavid du Colombier if(m->ballocd) 10527dd7cddfSDavid du Colombier free(m->body); 10537dd7cddfSDavid du Colombier m->body = x; 10547dd7cddfSDavid du Colombier m->bend = x + len; 10557dd7cddfSDavid du Colombier m->ballocd = 1; 10567dd7cddfSDavid du Colombier } 10577dd7cddfSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "big5") == 0){ 10587dd7cddfSDavid du Colombier len = xtoutf("big5", &x, m->body, m->bend); 10597dd7cddfSDavid du Colombier if(len != 0){ 10607dd7cddfSDavid du Colombier if(m->ballocd) 10617dd7cddfSDavid du Colombier free(m->body); 10627dd7cddfSDavid du Colombier m->body = x; 10637dd7cddfSDavid du Colombier m->bend = x + len; 10647dd7cddfSDavid du Colombier m->ballocd = 1; 10657dd7cddfSDavid du Colombier } 10667dd7cddfSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "windows-1257") == 0){ 10677dd7cddfSDavid du Colombier len = is8bit(m); 10687dd7cddfSDavid du Colombier if(len > 0){ 10697dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 10707dd7cddfSDavid du Colombier x = emalloc(len); 10717dd7cddfSDavid du Colombier len = windows1257toutf(x, m->body, m->bend); 10727dd7cddfSDavid du Colombier if(m->ballocd) 10737dd7cddfSDavid du Colombier free(m->body); 10747dd7cddfSDavid du Colombier m->body = x; 10757dd7cddfSDavid du Colombier m->bend = x + len; 10767dd7cddfSDavid du Colombier m->ballocd = 1; 10777dd7cddfSDavid du Colombier } 10787dd7cddfSDavid du Colombier } 10797dd7cddfSDavid du Colombier 10807dd7cddfSDavid du Colombier m->converted = 1; 10817dd7cddfSDavid du Colombier } 10827dd7cddfSDavid du Colombier 10837dd7cddfSDavid du Colombier enum 10847dd7cddfSDavid du Colombier { 10857dd7cddfSDavid du Colombier Self= 1, 10867dd7cddfSDavid du Colombier Hex= 2, 10877dd7cddfSDavid du Colombier }; 10887dd7cddfSDavid du Colombier uchar tableqp[256]; 10897dd7cddfSDavid du Colombier 10907dd7cddfSDavid du Colombier static void 10917dd7cddfSDavid du Colombier initquoted(void) 10927dd7cddfSDavid du Colombier { 10937dd7cddfSDavid du Colombier int c; 10947dd7cddfSDavid du Colombier 10957dd7cddfSDavid du Colombier memset(tableqp, 0, 256); 10967dd7cddfSDavid du Colombier for(c = ' '; c <= '<'; c++) 10977dd7cddfSDavid du Colombier tableqp[c] = Self; 10987dd7cddfSDavid du Colombier for(c = '>'; c <= '~'; c++) 10997dd7cddfSDavid du Colombier tableqp[c] = Self; 11007dd7cddfSDavid du Colombier tableqp['\t'] = Self; 11017dd7cddfSDavid du Colombier tableqp['='] = Hex; 11027dd7cddfSDavid du Colombier } 11037dd7cddfSDavid du Colombier 11047dd7cddfSDavid du Colombier static int 11057dd7cddfSDavid du Colombier hex2int(int x) 11067dd7cddfSDavid du Colombier { 11077dd7cddfSDavid du Colombier if(x >= '0' && x <= '9') 11087dd7cddfSDavid du Colombier return x - '0'; 11097dd7cddfSDavid du Colombier if(x >= 'A' && x <= 'F') 11107dd7cddfSDavid du Colombier return (x - 'A') + 10; 11117dd7cddfSDavid du Colombier if(x >= 'a' && x <= 'f') 11127dd7cddfSDavid du Colombier return (x - 'a') + 10; 11137dd7cddfSDavid du Colombier return 0; 11147dd7cddfSDavid du Colombier } 11157dd7cddfSDavid du Colombier 11167dd7cddfSDavid du Colombier static char* 11177dd7cddfSDavid du Colombier decquotedline(char *out, char *in, char *e) 11187dd7cddfSDavid du Colombier { 11197dd7cddfSDavid du Colombier int c, soft; 11207dd7cddfSDavid du Colombier 11217dd7cddfSDavid du Colombier /* dump trailing white space */ 11227dd7cddfSDavid du Colombier while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) 11237dd7cddfSDavid du Colombier e--; 11247dd7cddfSDavid du Colombier 11257dd7cddfSDavid du Colombier /* trailing '=' means no newline */ 11267dd7cddfSDavid du Colombier if(*e == '='){ 11277dd7cddfSDavid du Colombier soft = 1; 11287dd7cddfSDavid du Colombier e--; 11297dd7cddfSDavid du Colombier } else 11307dd7cddfSDavid du Colombier soft = 0; 11317dd7cddfSDavid du Colombier 11327dd7cddfSDavid du Colombier while(in <= e){ 11337dd7cddfSDavid du Colombier c = (*in++) & 0xff; 11347dd7cddfSDavid du Colombier switch(tableqp[c]){ 11357dd7cddfSDavid du Colombier case Self: 11367dd7cddfSDavid du Colombier *out++ = c; 11377dd7cddfSDavid du Colombier break; 11387dd7cddfSDavid du Colombier case Hex: 11397dd7cddfSDavid du Colombier c = hex2int(*in++)<<4; 11407dd7cddfSDavid du Colombier c |= hex2int(*in++); 11417dd7cddfSDavid du Colombier *out++ = c; 11427dd7cddfSDavid du Colombier break; 11437dd7cddfSDavid du Colombier } 11447dd7cddfSDavid du Colombier } 11457dd7cddfSDavid du Colombier if(!soft) 11467dd7cddfSDavid du Colombier *out++ = '\n'; 11477dd7cddfSDavid du Colombier *out = 0; 11487dd7cddfSDavid du Colombier 11497dd7cddfSDavid du Colombier return out; 11507dd7cddfSDavid du Colombier } 11517dd7cddfSDavid du Colombier 11527dd7cddfSDavid du Colombier int 11537dd7cddfSDavid du Colombier decquoted(char *out, char *in, char *e) 11547dd7cddfSDavid du Colombier { 11557dd7cddfSDavid du Colombier char *p, *nl; 11567dd7cddfSDavid du Colombier 11577dd7cddfSDavid du Colombier if(tableqp[' '] == 0) 11587dd7cddfSDavid du Colombier initquoted(); 11597dd7cddfSDavid du Colombier 11607dd7cddfSDavid du Colombier p = out; 11617dd7cddfSDavid du Colombier while((nl = strchr(in, '\n')) != nil && nl < e){ 11627dd7cddfSDavid du Colombier p = decquotedline(p, in, nl); 11637dd7cddfSDavid du Colombier in = nl + 1; 11647dd7cddfSDavid du Colombier } 11657dd7cddfSDavid du Colombier if(in < e) 11667dd7cddfSDavid du Colombier p = decquotedline(p, in, e-1); 11677dd7cddfSDavid du Colombier 11687dd7cddfSDavid du Colombier // make sure we end with a new line 11697dd7cddfSDavid du Colombier if(*(p-1) != '\n'){ 11707dd7cddfSDavid du Colombier *p++ = '\n'; 11717dd7cddfSDavid du Colombier *p = 0; 11727dd7cddfSDavid du Colombier } 11737dd7cddfSDavid du Colombier 11747dd7cddfSDavid du Colombier return p - out; 11757dd7cddfSDavid du Colombier } 11767dd7cddfSDavid du Colombier 11777dd7cddfSDavid du Colombier static char* 11787dd7cddfSDavid du Colombier lowercase(char *p) 11797dd7cddfSDavid du Colombier { 11807dd7cddfSDavid du Colombier char *op; 11817dd7cddfSDavid du Colombier int c; 11827dd7cddfSDavid du Colombier 11837dd7cddfSDavid du Colombier for(op = p; c = *p; p++) 11847dd7cddfSDavid du Colombier if(isupper(c)) 11857dd7cddfSDavid du Colombier *p = tolower(c); 11867dd7cddfSDavid du Colombier return op; 11877dd7cddfSDavid du Colombier } 11887dd7cddfSDavid du Colombier 11897dd7cddfSDavid du Colombier /* 11907dd7cddfSDavid du Colombier * return number of 8 bit characters 11917dd7cddfSDavid du Colombier */ 11927dd7cddfSDavid du Colombier static int 11937dd7cddfSDavid du Colombier is8bit(Message *m) 11947dd7cddfSDavid du Colombier { 11957dd7cddfSDavid du Colombier int count = 0; 11967dd7cddfSDavid du Colombier char *p; 11977dd7cddfSDavid du Colombier 11987dd7cddfSDavid du Colombier for(p = m->body; p < m->bend; p++) 11997dd7cddfSDavid du Colombier if(*p & 0x80) 12007dd7cddfSDavid du Colombier count++; 12017dd7cddfSDavid du Colombier return count; 12027dd7cddfSDavid du Colombier } 12037dd7cddfSDavid du Colombier 12047dd7cddfSDavid du Colombier // translate latin1 directly since it fits neatly in utf 12057dd7cddfSDavid du Colombier int 12067dd7cddfSDavid du Colombier latin1toutf(char *out, char *in, char *e) 12077dd7cddfSDavid du Colombier { 12087dd7cddfSDavid du Colombier Rune r; 12097dd7cddfSDavid du Colombier char *p; 12107dd7cddfSDavid du Colombier 12117dd7cddfSDavid du Colombier p = out; 12127dd7cddfSDavid du Colombier for(; in < e; in++){ 12137dd7cddfSDavid du Colombier r = (*in) & 0xff; 12147dd7cddfSDavid du Colombier p += runetochar(p, &r); 12157dd7cddfSDavid du Colombier } 12167dd7cddfSDavid du Colombier *p = 0; 12177dd7cddfSDavid du Colombier return p - out; 12187dd7cddfSDavid du Colombier } 12197dd7cddfSDavid du Colombier 12207dd7cddfSDavid du Colombier // translate any thing else using the tcs program 12217dd7cddfSDavid du Colombier int 12227dd7cddfSDavid du Colombier xtoutf(char *charset, char **out, char *in, char *e) 12237dd7cddfSDavid du Colombier { 12247dd7cddfSDavid du Colombier char *av[4]; 12257dd7cddfSDavid du Colombier int totcs[2]; 12267dd7cddfSDavid du Colombier int fromtcs[2]; 12277dd7cddfSDavid du Colombier int n, len, sofar; 12287dd7cddfSDavid du Colombier char *p; 12297dd7cddfSDavid du Colombier 12307dd7cddfSDavid du Colombier len = e-in+1; 12317dd7cddfSDavid du Colombier sofar = 0; 12327dd7cddfSDavid du Colombier *out = p = malloc(len+1); 12337dd7cddfSDavid du Colombier if(p == nil) 12347dd7cddfSDavid du Colombier return 0; 12357dd7cddfSDavid du Colombier 12367dd7cddfSDavid du Colombier av[0] = charset; 12377dd7cddfSDavid du Colombier av[1] = "-f"; 12387dd7cddfSDavid du Colombier av[2] = charset; 12397dd7cddfSDavid du Colombier av[3] = 0; 12407dd7cddfSDavid du Colombier if(pipe(totcs) < 0) 12417dd7cddfSDavid du Colombier return 0; 12427dd7cddfSDavid du Colombier if(pipe(fromtcs) < 0){ 12437dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 12447dd7cddfSDavid du Colombier return 0; 12457dd7cddfSDavid du Colombier } 12467dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12477dd7cddfSDavid du Colombier case -1: 12487dd7cddfSDavid du Colombier close(fromtcs[0]); close(fromtcs[1]); 12497dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 12507dd7cddfSDavid du Colombier return 0; 12517dd7cddfSDavid du Colombier case 0: 12527dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 12537dd7cddfSDavid du Colombier dup(fromtcs[1], 1); 12547dd7cddfSDavid du Colombier dup(totcs[0], 0); 12557dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 1256*9a747e4fSDavid du Colombier dup(open("/dev/null", OWRITE), 2); 12577dd7cddfSDavid du Colombier exec("/bin/tcs", av); 12587dd7cddfSDavid du Colombier _exits(0); 12597dd7cddfSDavid du Colombier default: 12607dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 12617dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 12627dd7cddfSDavid du Colombier case -1: 12637dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 12647dd7cddfSDavid du Colombier return 0; 12657dd7cddfSDavid du Colombier case 0: 12667dd7cddfSDavid du Colombier close(fromtcs[0]); 12677dd7cddfSDavid du Colombier while(in < e){ 12687dd7cddfSDavid du Colombier n = write(totcs[1], in, e-in); 12697dd7cddfSDavid du Colombier if(n <= 0) 12707dd7cddfSDavid du Colombier break; 12717dd7cddfSDavid du Colombier in += n; 12727dd7cddfSDavid du Colombier } 12737dd7cddfSDavid du Colombier close(totcs[1]); 12747dd7cddfSDavid du Colombier _exits(0); 12757dd7cddfSDavid du Colombier default: 12767dd7cddfSDavid du Colombier close(totcs[1]); 12777dd7cddfSDavid du Colombier for(;;){ 12787dd7cddfSDavid du Colombier n = read(fromtcs[0], &p[sofar], len-sofar); 12797dd7cddfSDavid du Colombier if(n <= 0) 12807dd7cddfSDavid du Colombier break; 12817dd7cddfSDavid du Colombier sofar += n; 12827dd7cddfSDavid du Colombier p[sofar] = 0; 12837dd7cddfSDavid du Colombier if(sofar == len){ 12847dd7cddfSDavid du Colombier len += 1024; 12857dd7cddfSDavid du Colombier *out = p = realloc(p, len+1); 12867dd7cddfSDavid du Colombier if(p == nil) 12877dd7cddfSDavid du Colombier return 0; 12887dd7cddfSDavid du Colombier } 12897dd7cddfSDavid du Colombier } 12907dd7cddfSDavid du Colombier close(fromtcs[0]); 12917dd7cddfSDavid du Colombier break; 12927dd7cddfSDavid du Colombier } 12937dd7cddfSDavid du Colombier break; 12947dd7cddfSDavid du Colombier } 12957dd7cddfSDavid du Colombier return sofar; 12967dd7cddfSDavid du Colombier } 12977dd7cddfSDavid du Colombier 12987dd7cddfSDavid du Colombier enum { 12997dd7cddfSDavid du Colombier Winstart= 0x7f, 13007dd7cddfSDavid du Colombier Winend= 0x9f, 13017dd7cddfSDavid du Colombier }; 13027dd7cddfSDavid du Colombier 13037dd7cddfSDavid du Colombier Rune winchars[] = { 13047dd7cddfSDavid du Colombier 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 L'˜', L'™', L'š', L'›', L'œ', L'•', L'•', L'Ÿ', 13097dd7cddfSDavid du Colombier }; 13107dd7cddfSDavid du Colombier 13117dd7cddfSDavid du Colombier int 13127dd7cddfSDavid du Colombier windows1257toutf(char *out, char *in, char *e) 13137dd7cddfSDavid du Colombier { 13147dd7cddfSDavid du Colombier Rune r; 13157dd7cddfSDavid du Colombier char *p; 13167dd7cddfSDavid du Colombier 13177dd7cddfSDavid du Colombier p = out; 13187dd7cddfSDavid du Colombier for(; in < e; in++){ 13197dd7cddfSDavid du Colombier r = (*in) & 0xff; 13207dd7cddfSDavid du Colombier if(r >= 0x7f && r <= 0x9f) 13217dd7cddfSDavid du Colombier r = winchars[r-0x7f]; 13227dd7cddfSDavid du Colombier p += runetochar(p, &r); 13237dd7cddfSDavid du Colombier } 13247dd7cddfSDavid du Colombier *p = 0; 13257dd7cddfSDavid du Colombier return p - out; 13267dd7cddfSDavid du Colombier } 13277dd7cddfSDavid du Colombier 13287dd7cddfSDavid du Colombier void * 13297dd7cddfSDavid du Colombier emalloc(ulong n) 13307dd7cddfSDavid du Colombier { 13317dd7cddfSDavid du Colombier void *p; 13327dd7cddfSDavid du Colombier 13337dd7cddfSDavid du Colombier p = mallocz(n, 1); 13347dd7cddfSDavid du Colombier if(!p){ 133580ee5cbfSDavid du Colombier fprint(2, "%s: out of memory alloc %lud\n", argv0, n); 13367dd7cddfSDavid du Colombier exits("out of memory"); 13377dd7cddfSDavid du Colombier } 133880ee5cbfSDavid du Colombier setmalloctag(p, getcallerpc(&n)); 13397dd7cddfSDavid du Colombier return p; 13407dd7cddfSDavid du Colombier } 13417dd7cddfSDavid du Colombier 13427dd7cddfSDavid du Colombier void * 13437dd7cddfSDavid du Colombier erealloc(void *p, ulong n) 13447dd7cddfSDavid du Colombier { 13457dd7cddfSDavid du Colombier p = realloc(p, n); 13467dd7cddfSDavid du Colombier if(!p){ 134780ee5cbfSDavid du Colombier fprint(2, "%s: out of memory realloc %lud\n", argv0, n); 13487dd7cddfSDavid du Colombier exits("out of memory"); 13497dd7cddfSDavid du Colombier } 135080ee5cbfSDavid du Colombier setrealloctag(p, getcallerpc(&p)); 13517dd7cddfSDavid du Colombier return p; 13527dd7cddfSDavid du Colombier } 13537dd7cddfSDavid du Colombier 13547dd7cddfSDavid du Colombier void 13557dd7cddfSDavid du Colombier mailplumb(Mailbox *mb, Message *m, int delete) 13567dd7cddfSDavid du Colombier { 13577dd7cddfSDavid du Colombier Plumbmsg p; 13587dd7cddfSDavid du Colombier Plumbattr a[7]; 13597dd7cddfSDavid du Colombier char buf[256]; 13607dd7cddfSDavid du Colombier int ai; 13617dd7cddfSDavid du Colombier char lenstr[10], *from, *subject, *date; 13627dd7cddfSDavid du Colombier static int fd = -1; 13637dd7cddfSDavid du Colombier 13647dd7cddfSDavid du Colombier if(m->subject822 == nil) 13657dd7cddfSDavid du Colombier subject = ""; 13667dd7cddfSDavid du Colombier else 13677dd7cddfSDavid du Colombier subject = s_to_c(m->subject822); 13687dd7cddfSDavid du Colombier 13697dd7cddfSDavid du Colombier if(m->from822 != nil) 13707dd7cddfSDavid du Colombier from = s_to_c(m->from822); 13717dd7cddfSDavid du Colombier else if(m->unixfrom != nil) 13727dd7cddfSDavid du Colombier from = s_to_c(m->unixfrom); 13737dd7cddfSDavid du Colombier else 13747dd7cddfSDavid du Colombier from = ""; 13757dd7cddfSDavid du Colombier 13767dd7cddfSDavid du Colombier if(m->unixdate != nil) 13777dd7cddfSDavid du Colombier date = s_to_c(m->unixdate); 13787dd7cddfSDavid du Colombier else 13797dd7cddfSDavid du Colombier date = ""; 13807dd7cddfSDavid du Colombier 13817dd7cddfSDavid du Colombier sprint(lenstr, "%ld", m->end-m->start); 13827dd7cddfSDavid du Colombier 13837dd7cddfSDavid du Colombier if(biffing && !delete) 13847dd7cddfSDavid du Colombier print("[ %s / %s / %s ]\n", from, subject, lenstr); 13857dd7cddfSDavid du Colombier 13867dd7cddfSDavid du Colombier if(!plumbing) 13877dd7cddfSDavid du Colombier return; 13887dd7cddfSDavid du Colombier 13897dd7cddfSDavid du Colombier if(fd < 0) 13907dd7cddfSDavid du Colombier fd = plumbopen("send", OWRITE); 13917dd7cddfSDavid du Colombier if(fd < 0) 13927dd7cddfSDavid du Colombier return; 13937dd7cddfSDavid du Colombier 13947dd7cddfSDavid du Colombier p.src = "mailfs"; 13957dd7cddfSDavid du Colombier p.dst = "seemail"; 13967dd7cddfSDavid du Colombier p.wdir = "/mail/fs"; 13977dd7cddfSDavid du Colombier p.type = "text"; 13987dd7cddfSDavid du Colombier 13997dd7cddfSDavid du Colombier ai = 0; 14007dd7cddfSDavid du Colombier a[ai].name = "filetype"; 14017dd7cddfSDavid du Colombier a[ai].value = "mail"; 14027dd7cddfSDavid du Colombier 14037dd7cddfSDavid du Colombier a[++ai].name = "sender"; 14047dd7cddfSDavid du Colombier a[ai].value = from; 14057dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14067dd7cddfSDavid du Colombier 14077dd7cddfSDavid du Colombier a[++ai].name = "length"; 14087dd7cddfSDavid du Colombier a[ai].value = lenstr; 14097dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14107dd7cddfSDavid du Colombier 14117dd7cddfSDavid du Colombier a[++ai].name = "mailtype"; 14127dd7cddfSDavid du Colombier a[ai].value = delete?"delete":"new"; 14137dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14147dd7cddfSDavid du Colombier 14157dd7cddfSDavid du Colombier a[++ai].name = "date"; 14167dd7cddfSDavid du Colombier a[ai].value = date; 14177dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 14187dd7cddfSDavid du Colombier 1419*9a747e4fSDavid du Colombier if(m->sdigest){ 14207dd7cddfSDavid du Colombier a[++ai].name = "digest"; 14217dd7cddfSDavid du Colombier a[ai].value = s_to_c(m->sdigest); 14227dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 1423*9a747e4fSDavid du Colombier } 14247dd7cddfSDavid du Colombier 14257dd7cddfSDavid du Colombier a[ai].next = nil; 14267dd7cddfSDavid du Colombier 14277dd7cddfSDavid du Colombier p.attr = a; 14287dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/%s/%s", 14297dd7cddfSDavid du Colombier mntpt, mb->name, m->name); 14307dd7cddfSDavid du Colombier p.ndata = strlen(buf); 14317dd7cddfSDavid du Colombier p.data = buf; 14327dd7cddfSDavid du Colombier 14337dd7cddfSDavid du Colombier plumbsend(fd, &p); 14347dd7cddfSDavid du Colombier } 14357dd7cddfSDavid du Colombier 14367dd7cddfSDavid du Colombier // 14377dd7cddfSDavid du Colombier // count the number of lines in the body (for imap4) 14387dd7cddfSDavid du Colombier // 14397dd7cddfSDavid du Colombier void 14407dd7cddfSDavid du Colombier countlines(Message *m) 14417dd7cddfSDavid du Colombier { 14427dd7cddfSDavid du Colombier int i; 14437dd7cddfSDavid du Colombier char *p; 14447dd7cddfSDavid du Colombier 14457dd7cddfSDavid du Colombier i = 0; 14467dd7cddfSDavid du Colombier for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n')) 14477dd7cddfSDavid du Colombier i++; 14487dd7cddfSDavid du Colombier sprint(m->lines, "%d", i); 14497dd7cddfSDavid du Colombier } 145059cc4ca5SDavid du Colombier 145159cc4ca5SDavid du Colombier char *LOG = "fs"; 145259cc4ca5SDavid du Colombier 145359cc4ca5SDavid du Colombier void 145459cc4ca5SDavid du Colombier logmsg(char *s, Message *m) 145559cc4ca5SDavid du Colombier { 145659cc4ca5SDavid du Colombier int pid; 145759cc4ca5SDavid du Colombier 145859cc4ca5SDavid du Colombier if(!logging) 145959cc4ca5SDavid du Colombier return; 146059cc4ca5SDavid du Colombier pid = getpid(); 146159cc4ca5SDavid du Colombier if(m == nil) 146259cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s", user, pid, s); 146359cc4ca5SDavid du Colombier else 146459cc4ca5SDavid du Colombier syslog(0, LOG, "%s.%d: %s msg from %s digest %s", 146559cc4ca5SDavid du Colombier user, pid, s, 146659cc4ca5SDavid du Colombier m->from822 ? s_to_c(m->from822) : "?", 146759cc4ca5SDavid du Colombier s_to_c(m->sdigest)); 146859cc4ca5SDavid du Colombier } 146980ee5cbfSDavid du Colombier 147080ee5cbfSDavid du Colombier // 147180ee5cbfSDavid du Colombier // convert an RFC822 date into a Unix style date 147280ee5cbfSDavid du Colombier // for when the Unix From line isn't there (e.g. POP3). 147380ee5cbfSDavid du Colombier // enough client programs depend on having a Unix date 147480ee5cbfSDavid du Colombier // that it's easiest to write this conversion code once, right here. 147580ee5cbfSDavid du Colombier // 147680ee5cbfSDavid du Colombier // people don't follow RFC822 particularly closely, 147780ee5cbfSDavid du Colombier // so we use strtotm, which is a bunch of heuristics. 147880ee5cbfSDavid du Colombier // 147980ee5cbfSDavid du Colombier 148080ee5cbfSDavid du Colombier extern int strtotm(char*, Tm*); 148180ee5cbfSDavid du Colombier String* 148280ee5cbfSDavid du Colombier date822tounix(char *s) 148380ee5cbfSDavid du Colombier { 148480ee5cbfSDavid du Colombier char *p, *q; 148580ee5cbfSDavid du Colombier Tm tm; 148680ee5cbfSDavid du Colombier 148780ee5cbfSDavid du Colombier if(strtotm(s, &tm) < 0) 148880ee5cbfSDavid du Colombier return nil; 148980ee5cbfSDavid du Colombier 149080ee5cbfSDavid du Colombier p = asctime(&tm); 149180ee5cbfSDavid du Colombier if(q = strchr(p, '\n')) 149280ee5cbfSDavid du Colombier *q = '\0'; 149380ee5cbfSDavid du Colombier return s_copy(p); 149480ee5cbfSDavid du Colombier } 149580ee5cbfSDavid du Colombier 1496