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 void parse(Message*, int, Mailbox*); 677dd7cddfSDavid du Colombier static void parseunix(Message*); 687dd7cddfSDavid du Colombier static int headerline(char**, String*); 697dd7cddfSDavid du Colombier static void initheaders(void); 707dd7cddfSDavid du Colombier static void parseattachments(Message*, Mailbox*); 717dd7cddfSDavid du Colombier 727dd7cddfSDavid du Colombier int debug; 737dd7cddfSDavid du Colombier 747dd7cddfSDavid du Colombier enum 757dd7cddfSDavid du Colombier { 767dd7cddfSDavid du Colombier Chunksize = 1024, 777dd7cddfSDavid du Colombier }; 787dd7cddfSDavid du Colombier 797dd7cddfSDavid du Colombier /* create a new mailbox */ 807dd7cddfSDavid du Colombier char* 817dd7cddfSDavid du Colombier newmbox(char *path, char *name, int std) 827dd7cddfSDavid du Colombier { 837dd7cddfSDavid du Colombier Mailbox *mb, **l; 847dd7cddfSDavid du Colombier char *p, *rv; 857dd7cddfSDavid du Colombier 867dd7cddfSDavid du Colombier mb = emalloc(sizeof(*mb)); 877dd7cddfSDavid du Colombier strncpy(mb->path, path, sizeof(mb->path)-1); 887dd7cddfSDavid du Colombier if(name == nil){ 897dd7cddfSDavid du Colombier p = strrchr(path, '/'); 907dd7cddfSDavid du Colombier if(p == nil) 917dd7cddfSDavid du Colombier p = path; 927dd7cddfSDavid du Colombier else 937dd7cddfSDavid du Colombier p++; 947dd7cddfSDavid du Colombier if(*p == 0){ 957dd7cddfSDavid du Colombier free(mb); 967dd7cddfSDavid du Colombier return "bad mbox name"; 977dd7cddfSDavid du Colombier } 987dd7cddfSDavid du Colombier strncpy(mb->name, p, sizeof(mb->name)-1); 997dd7cddfSDavid du Colombier } else { 1007dd7cddfSDavid du Colombier strncpy(mb->name, name, sizeof(mb->name)-1); 1017dd7cddfSDavid du Colombier } 1027dd7cddfSDavid du Colombier 1037dd7cddfSDavid du Colombier // make sure name isn't taken 1047dd7cddfSDavid du Colombier qlock(&mbllock); 1057dd7cddfSDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next) 1067dd7cddfSDavid du Colombier if(strcmp((*l)->name, mb->name) == 0){ 1077dd7cddfSDavid du Colombier if(strcmp(path, mb->path) == 0) 1087dd7cddfSDavid du Colombier rv = nil; 1097dd7cddfSDavid du Colombier else 1107dd7cddfSDavid du Colombier rv = "mbox name in use"; 1117dd7cddfSDavid du Colombier free(mb); 1127dd7cddfSDavid du Colombier qunlock(&mbllock); 1137dd7cddfSDavid du Colombier return rv; 1147dd7cddfSDavid du Colombier } 1157dd7cddfSDavid du Colombier mb->refs = 1; 1167dd7cddfSDavid du Colombier mb->next = nil; 1177dd7cddfSDavid du Colombier mb->id = newid(); 1187dd7cddfSDavid du Colombier mb->root = newmessage(nil); 1197dd7cddfSDavid du Colombier mb->std = std; 1207dd7cddfSDavid du Colombier *l = mb; 1217dd7cddfSDavid du Colombier qunlock(&mbllock); 1227dd7cddfSDavid du Colombier 1237dd7cddfSDavid du Colombier qlock(mb); 1247dd7cddfSDavid du Colombier rv = syncmbox(mb, 0); 1257dd7cddfSDavid du Colombier qunlock(mb); 1267dd7cddfSDavid du Colombier 1277dd7cddfSDavid du Colombier return rv; 1287dd7cddfSDavid du Colombier } 1297dd7cddfSDavid du Colombier 1307dd7cddfSDavid du Colombier // close the named mailbox 1317dd7cddfSDavid du Colombier void 1327dd7cddfSDavid du Colombier freembox(char *name) 1337dd7cddfSDavid du Colombier { 1347dd7cddfSDavid du Colombier Mailbox *mb; 1357dd7cddfSDavid du Colombier 1367dd7cddfSDavid du Colombier qlock(&mbllock); 1377dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 1387dd7cddfSDavid du Colombier if(strcmp(name, mb->name) == 0){ 1397dd7cddfSDavid du Colombier mboxdecref(mb); 1407dd7cddfSDavid du Colombier break; 1417dd7cddfSDavid du Colombier } 1427dd7cddfSDavid du Colombier hfree(CHDIR|PATH(0, Qtop), name); 1437dd7cddfSDavid du Colombier qunlock(&mbllock); 1447dd7cddfSDavid du Colombier } 1457dd7cddfSDavid du Colombier 1467dd7cddfSDavid du Colombier enum { 1477dd7cddfSDavid du Colombier Buffersize = 64*1024, 1487dd7cddfSDavid du Colombier }; 1497dd7cddfSDavid du Colombier 1507dd7cddfSDavid du Colombier typedef struct Inbuf Inbuf; 1517dd7cddfSDavid du Colombier struct Inbuf 1527dd7cddfSDavid du Colombier { 1537dd7cddfSDavid du Colombier int fd; 1547dd7cddfSDavid du Colombier uchar *lim; 1557dd7cddfSDavid du Colombier uchar *rptr; 1567dd7cddfSDavid du Colombier uchar *wptr; 1577dd7cddfSDavid du Colombier uchar data[Buffersize+7]; 1587dd7cddfSDavid du Colombier }; 1597dd7cddfSDavid du Colombier 1607dd7cddfSDavid du Colombier static void 1617dd7cddfSDavid du Colombier addtomessage(Message *m, uchar *p, int n, int done) 1627dd7cddfSDavid du Colombier { 1637dd7cddfSDavid du Colombier int i, len; 1647dd7cddfSDavid du Colombier 1657dd7cddfSDavid du Colombier // add to message (+ 1 in malloc is for a trailing null) 1667dd7cddfSDavid du Colombier if(m->lim - m->end < n){ 1677dd7cddfSDavid du Colombier if(m->start != nil){ 1687dd7cddfSDavid du Colombier i = m->end-m->start; 1697dd7cddfSDavid du Colombier if(done) 1707dd7cddfSDavid du Colombier len = i + n; 1717dd7cddfSDavid du Colombier else 1727dd7cddfSDavid du Colombier len = (4*(i+n))/3; 1737dd7cddfSDavid du Colombier m->start = erealloc(m->start, len + 1); 1747dd7cddfSDavid du Colombier m->end = m->start + i; 1757dd7cddfSDavid du Colombier } else { 1767dd7cddfSDavid du Colombier if(done) 1777dd7cddfSDavid du Colombier len = n; 1787dd7cddfSDavid du Colombier else 1797dd7cddfSDavid du Colombier len = 2*n; 1807dd7cddfSDavid du Colombier m->start = emalloc(len + 1); 1817dd7cddfSDavid du Colombier m->end = m->start; 1827dd7cddfSDavid du Colombier } 1837dd7cddfSDavid du Colombier m->lim = m->start + len; 1847dd7cddfSDavid du Colombier } 1857dd7cddfSDavid du Colombier 1867dd7cddfSDavid du Colombier memmove(m->end, p, n); 1877dd7cddfSDavid du Colombier m->end += n; 1887dd7cddfSDavid du Colombier } 1897dd7cddfSDavid du Colombier 1907dd7cddfSDavid du Colombier // 1917dd7cddfSDavid du Colombier // read in a single message 1927dd7cddfSDavid du Colombier // 1937dd7cddfSDavid du Colombier static int 1947dd7cddfSDavid du Colombier readmessage(Message *m, Inbuf *inb) 1957dd7cddfSDavid du Colombier { 1967dd7cddfSDavid du Colombier int i, n, done; 1977dd7cddfSDavid du Colombier uchar *p, *np; 1987dd7cddfSDavid du Colombier char sdigest[SHA1dlen*2+1]; 1997dd7cddfSDavid du Colombier 2007dd7cddfSDavid du Colombier for(done = 0; !done;){ 2017dd7cddfSDavid du Colombier n = inb->wptr - inb->rptr; 2027dd7cddfSDavid du Colombier if(n < 6){ 2037dd7cddfSDavid du Colombier if(n) 2047dd7cddfSDavid du Colombier memmove(inb->data, inb->rptr, n); 2057dd7cddfSDavid du Colombier inb->rptr = inb->data; 2067dd7cddfSDavid du Colombier inb->wptr = inb->rptr + n; 2077dd7cddfSDavid du Colombier i = read(inb->fd, inb->wptr, Buffersize); 2087dd7cddfSDavid du Colombier if(i < 0) 2097dd7cddfSDavid du Colombier return -1; 2107dd7cddfSDavid du Colombier if(i == 0){ 2117dd7cddfSDavid du Colombier if(n != 0) 2127dd7cddfSDavid du Colombier addtomessage(m, inb->rptr, n, 1); 2137dd7cddfSDavid du Colombier if(m->end == m->start) 2147dd7cddfSDavid du Colombier return -1; 2157dd7cddfSDavid du Colombier break; 2167dd7cddfSDavid du Colombier } 2177dd7cddfSDavid du Colombier inb->wptr += i; 2187dd7cddfSDavid du Colombier } 2197dd7cddfSDavid du Colombier 2207dd7cddfSDavid du Colombier // look for end of message 2217dd7cddfSDavid du Colombier for(p = inb->rptr; p < inb->wptr; p = np+1){ 2227dd7cddfSDavid du Colombier // first part of search for '\nFrom ' 2237dd7cddfSDavid du Colombier np = memchr(p, '\n', inb->wptr - p); 2247dd7cddfSDavid du Colombier if(np == nil){ 2257dd7cddfSDavid du Colombier p = inb->wptr; 2267dd7cddfSDavid du Colombier break; 2277dd7cddfSDavid du Colombier } 2287dd7cddfSDavid du Colombier 2297dd7cddfSDavid du Colombier /* 2307dd7cddfSDavid du Colombier * if we've found a \n but there's 2317dd7cddfSDavid du Colombier * not enough room for '\nFrom ', don't do 2327dd7cddfSDavid du Colombier * the comparison till we've read in more. 2337dd7cddfSDavid du Colombier */ 2347dd7cddfSDavid du Colombier if(inb->wptr - np < 6){ 2357dd7cddfSDavid du Colombier p = np; 2367dd7cddfSDavid du Colombier break; 2377dd7cddfSDavid du Colombier } 2387dd7cddfSDavid du Colombier 2397dd7cddfSDavid du Colombier if(strncmp((char*)np, "\nFrom ", 6) == 0){ 2407dd7cddfSDavid du Colombier done = 1; 2417dd7cddfSDavid du Colombier p = np+1; 2427dd7cddfSDavid du Colombier break; 2437dd7cddfSDavid du Colombier } 2447dd7cddfSDavid du Colombier } 2457dd7cddfSDavid du Colombier 2467dd7cddfSDavid du Colombier // add to message (+ 1 in malloc is for a trailing null) 2477dd7cddfSDavid du Colombier n = p - inb->rptr; 2487dd7cddfSDavid du Colombier addtomessage(m, inb->rptr, n, done); 2497dd7cddfSDavid du Colombier inb->rptr += n; 2507dd7cddfSDavid du Colombier } 2517dd7cddfSDavid du Colombier 2527dd7cddfSDavid du Colombier // if it doesn't start with a 'From ', this ain't a mailbox 2537dd7cddfSDavid du Colombier if(strncmp(m->start, "From ", 5) != 0) 2547dd7cddfSDavid du Colombier return -1; 2557dd7cddfSDavid du Colombier 2567dd7cddfSDavid du Colombier // dump trailing newline, make sure there's a trailing null 2577dd7cddfSDavid du Colombier // (helps in body searches) 2587dd7cddfSDavid du Colombier if(*(m->end-1) == '\n') 2597dd7cddfSDavid du Colombier m->end--; 2607dd7cddfSDavid du Colombier *m->end = 0; 2617dd7cddfSDavid du Colombier m->bend = m->rbend = m->end; 2627dd7cddfSDavid du Colombier 2637dd7cddfSDavid du Colombier // digest message 2647dd7cddfSDavid du Colombier sha1((uchar*)m->start, m->end - m->start, m->digest, nil); 2657dd7cddfSDavid du Colombier for(i = 0; i < SHA1dlen; i++) 2667dd7cddfSDavid du Colombier sprint(sdigest+2*i, "%2.2ux", m->digest[i]); 2677dd7cddfSDavid du Colombier m->sdigest = s_copy(sdigest); 2687dd7cddfSDavid du Colombier 2697dd7cddfSDavid du Colombier return 0; 2707dd7cddfSDavid du Colombier } 2717dd7cddfSDavid du Colombier 2727dd7cddfSDavid du Colombier // throw out deleted messages. return number of freshly deleted messages 2737dd7cddfSDavid du Colombier int 2747dd7cddfSDavid du Colombier purgedeleted(Mailbox *mb) 2757dd7cddfSDavid du Colombier { 2767dd7cddfSDavid du Colombier Message *m, *next; 2777dd7cddfSDavid du Colombier int newdels; 2787dd7cddfSDavid du Colombier 2797dd7cddfSDavid du Colombier // forget about what's no longer in the mailbox 2807dd7cddfSDavid du Colombier newdels = 0; 2817dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = next){ 2827dd7cddfSDavid du Colombier next = m->next; 2837dd7cddfSDavid du Colombier if(m->deleted && m->refs == 0){ 2847dd7cddfSDavid du Colombier if(m->inmbox) 2857dd7cddfSDavid du Colombier newdels++; 2867dd7cddfSDavid du Colombier delmessage(mb, m); 2877dd7cddfSDavid du Colombier } 2887dd7cddfSDavid du Colombier } 2897dd7cddfSDavid du Colombier return newdels; 2907dd7cddfSDavid du Colombier } 2917dd7cddfSDavid du Colombier 2927dd7cddfSDavid du Colombier // 2937dd7cddfSDavid du Colombier // read in the mailbox and parse into messages. 2947dd7cddfSDavid du Colombier // 2957dd7cddfSDavid du Colombier static char* 2967dd7cddfSDavid du Colombier _readmbox(Mailbox *mb, int doplumb, Mlock *lk) 2977dd7cddfSDavid du Colombier { 2987dd7cddfSDavid du Colombier int fd; 2997dd7cddfSDavid du Colombier String *tmp; 3007dd7cddfSDavid du Colombier Dir d; 3017dd7cddfSDavid du Colombier static char err[ERRLEN]; 3027dd7cddfSDavid du Colombier Message *m, **l; 3037dd7cddfSDavid du Colombier Inbuf *inb; 3047dd7cddfSDavid du Colombier char *x; 3057dd7cddfSDavid du Colombier 3067dd7cddfSDavid du Colombier l = &mb->root->part; 3077dd7cddfSDavid du Colombier initheaders(); 3087dd7cddfSDavid du Colombier 3097dd7cddfSDavid du Colombier /* 3107dd7cddfSDavid du Colombier * open the mailbox. If it doesn't exist, try the temporary one. 3117dd7cddfSDavid du Colombier */ 3127dd7cddfSDavid du Colombier retry: 3137dd7cddfSDavid du Colombier fd = open(mb->path, OREAD); 3147dd7cddfSDavid du Colombier if(fd < 0){ 3157dd7cddfSDavid du Colombier errstr(err); 3167dd7cddfSDavid du Colombier if(strstr(err, "exist") != 0){ 3177dd7cddfSDavid du Colombier tmp = s_copy(mb->path); 3187dd7cddfSDavid du Colombier s_append(tmp, ".tmp"); 3197dd7cddfSDavid du Colombier if(sysrename(s_to_c(tmp), mb->path) == 0){ 3207dd7cddfSDavid du Colombier s_free(tmp); 3217dd7cddfSDavid du Colombier goto retry; 3227dd7cddfSDavid du Colombier } 3237dd7cddfSDavid du Colombier s_free(tmp); 3247dd7cddfSDavid du Colombier } 3257dd7cddfSDavid du Colombier return err; 3267dd7cddfSDavid du Colombier } 3277dd7cddfSDavid du Colombier 3287dd7cddfSDavid du Colombier /* 3297dd7cddfSDavid du Colombier * a new qid.path means reread the mailbox, while 3307dd7cddfSDavid du Colombier * a new qid.vers means read any new messages 3317dd7cddfSDavid du Colombier */ 3327dd7cddfSDavid du Colombier if(dirfstat(fd, &d) < 0){ 3337dd7cddfSDavid du Colombier close(fd); 3347dd7cddfSDavid du Colombier errstr(err); 3357dd7cddfSDavid du Colombier return err; 3367dd7cddfSDavid du Colombier } 3377dd7cddfSDavid du Colombier if(d.qid.path == mb->d.qid.path && d.qid.vers == mb->d.qid.vers){ 3387dd7cddfSDavid du Colombier close(fd); 3397dd7cddfSDavid du Colombier return nil; 3407dd7cddfSDavid du Colombier } 3417dd7cddfSDavid du Colombier if(d.qid.path == mb->d.qid.path){ 3427dd7cddfSDavid du Colombier while(*l != nil) 3437dd7cddfSDavid du Colombier l = &(*l)->next; 3447dd7cddfSDavid du Colombier seek(fd, mb->d.length, 0); 3457dd7cddfSDavid du Colombier } 3467dd7cddfSDavid du Colombier memmove(&mb->d, &d, sizeof(d)); 3477dd7cddfSDavid du Colombier mb->vers++; 3487dd7cddfSDavid du Colombier henter(CHDIR|PATH(0, Qtop), mb->name, 3497dd7cddfSDavid du Colombier (Qid){CHDIR|PATH(mb->id, Qmbox), mb->vers}, nil, mb); 3507dd7cddfSDavid du Colombier 3517dd7cddfSDavid du Colombier inb = emalloc(sizeof(Inbuf)); 3527dd7cddfSDavid du Colombier inb->rptr = inb->wptr = inb->data; 3537dd7cddfSDavid du Colombier inb->fd = fd; 3547dd7cddfSDavid du Colombier 3557dd7cddfSDavid du Colombier // read new messages 3567dd7cddfSDavid du Colombier for(;;){ 3577dd7cddfSDavid du Colombier if(lk != nil) 3587dd7cddfSDavid du Colombier syslockrefresh(lk); 3597dd7cddfSDavid du Colombier m = newmessage(mb->root); 3607dd7cddfSDavid du Colombier m->mallocd = 1; 3617dd7cddfSDavid du Colombier m->inmbox = 1; 3627dd7cddfSDavid du Colombier if(readmessage(m, inb) < 0){ 3637dd7cddfSDavid du Colombier delmessage(mb, m); 3647dd7cddfSDavid du Colombier mb->root->subname--; 3657dd7cddfSDavid du Colombier break; 3667dd7cddfSDavid du Colombier } 3677dd7cddfSDavid du Colombier 3687dd7cddfSDavid du Colombier // merge mailbox versions 3697dd7cddfSDavid du Colombier while(*l != nil){ 3707dd7cddfSDavid du Colombier if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){ 3717dd7cddfSDavid du Colombier // matches mail we already read, discard 3727dd7cddfSDavid du Colombier delmessage(mb, m); 3737dd7cddfSDavid du Colombier mb->root->subname--; 3747dd7cddfSDavid du Colombier m = nil; 3757dd7cddfSDavid du Colombier l = &(*l)->next; 3767dd7cddfSDavid du Colombier break; 3777dd7cddfSDavid du Colombier } else { 3787dd7cddfSDavid du Colombier // old mail no longer in box, mark deleted 3797dd7cddfSDavid du Colombier if(doplumb) 3807dd7cddfSDavid du Colombier mailplumb(mb, *l, 1); 3817dd7cddfSDavid du Colombier (*l)->inmbox = 0; 3827dd7cddfSDavid du Colombier (*l)->deleted = 1; 3837dd7cddfSDavid du Colombier l = &(*l)->next; 3847dd7cddfSDavid du Colombier } 3857dd7cddfSDavid du Colombier } 3867dd7cddfSDavid du Colombier if(m == nil) 3877dd7cddfSDavid du Colombier continue; 3887dd7cddfSDavid du Colombier 3897dd7cddfSDavid du Colombier x = strchr(m->start, '\n'); 3907dd7cddfSDavid du Colombier if(x == nil) 3917dd7cddfSDavid du Colombier m->header = m->end; 3927dd7cddfSDavid du Colombier else 3937dd7cddfSDavid du Colombier m->header = x + 1; 3947dd7cddfSDavid du Colombier m->mheader = m->mhend = m->header; 3957dd7cddfSDavid du Colombier parseunix(m); 3967dd7cddfSDavid du Colombier parse(m, 0, mb); 3977dd7cddfSDavid du Colombier 3987dd7cddfSDavid du Colombier /* chain in */ 3997dd7cddfSDavid du Colombier *l = m; 4007dd7cddfSDavid du Colombier l = &m->next; 4017dd7cddfSDavid du Colombier if(doplumb) 4027dd7cddfSDavid du Colombier mailplumb(mb, m, 0); 4037dd7cddfSDavid du Colombier 4047dd7cddfSDavid du Colombier } 4057dd7cddfSDavid du Colombier 4067dd7cddfSDavid du Colombier // whatever is left has been removed from the mbox, mark deleted 4077dd7cddfSDavid du Colombier while(*l != nil){ 4087dd7cddfSDavid du Colombier if(doplumb) 4097dd7cddfSDavid du Colombier mailplumb(mb, *l, 1); 4107dd7cddfSDavid du Colombier (*l)->inmbox = 0; 4117dd7cddfSDavid du Colombier (*l)->deleted = 1; 4127dd7cddfSDavid du Colombier l = &(*l)->next; 4137dd7cddfSDavid du Colombier } 4147dd7cddfSDavid du Colombier 4157dd7cddfSDavid du Colombier close(fd); 4167dd7cddfSDavid du Colombier free(inb); 4177dd7cddfSDavid du Colombier return nil; 4187dd7cddfSDavid du Colombier } 4197dd7cddfSDavid du Colombier 4207dd7cddfSDavid du Colombier static void 4217dd7cddfSDavid du Colombier _writembox(Mailbox *mb, Mlock *lk) 4227dd7cddfSDavid du Colombier { 4237dd7cddfSDavid du Colombier Dir d; 4247dd7cddfSDavid du Colombier Message *m; 4257dd7cddfSDavid du Colombier String *tmp; 4267dd7cddfSDavid du Colombier int mode, errs; 4277dd7cddfSDavid du Colombier Biobuf *b; 4287dd7cddfSDavid du Colombier 4297dd7cddfSDavid du Colombier tmp = s_copy(mb->path); 4307dd7cddfSDavid du Colombier s_append(tmp, ".tmp"); 4317dd7cddfSDavid du Colombier 4327dd7cddfSDavid du Colombier /* 4337dd7cddfSDavid du Colombier * preserve old files permissions, if possible 4347dd7cddfSDavid du Colombier */ 4357dd7cddfSDavid du Colombier if(dirstat(mb->path, &d) >= 0) 4367dd7cddfSDavid du Colombier mode = d.mode&0777; 4377dd7cddfSDavid du Colombier else 4387dd7cddfSDavid du Colombier mode = MBOXMODE; 4397dd7cddfSDavid du Colombier 4407dd7cddfSDavid du Colombier sysremove(s_to_c(tmp)); 4417dd7cddfSDavid du Colombier b = sysopen(s_to_c(tmp), "alc", mode); 4427dd7cddfSDavid du Colombier if(b == 0){ 4437dd7cddfSDavid du Colombier fprint(2, "can't write temporary mailbox\n"); 4447dd7cddfSDavid du Colombier return; 4457dd7cddfSDavid du Colombier } 4467dd7cddfSDavid du Colombier 4477dd7cddfSDavid du Colombier errs = 0; 4487dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = m->next){ 4497dd7cddfSDavid du Colombier if(lk != nil) 4507dd7cddfSDavid du Colombier syslockrefresh(lk); 4517dd7cddfSDavid du Colombier if(m->deleted) 4527dd7cddfSDavid du Colombier continue; 4537dd7cddfSDavid du Colombier if(Bwrite(b, m->start, m->end - m->start) < 0) 4547dd7cddfSDavid du Colombier errs = 1; 4557dd7cddfSDavid du Colombier if(Bwrite(b, "\n", 1) < 0) 4567dd7cddfSDavid du Colombier errs = 1; 4577dd7cddfSDavid du Colombier } 4587dd7cddfSDavid du Colombier 4597dd7cddfSDavid du Colombier if(sysclose(b) < 0) 4607dd7cddfSDavid du Colombier errs = 1; 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier if(errs){ 4637dd7cddfSDavid du Colombier fprint(2, "error writing temporary mail file\n"); 4647dd7cddfSDavid du Colombier s_free(tmp); 4657dd7cddfSDavid du Colombier return; 4667dd7cddfSDavid du Colombier } 4677dd7cddfSDavid du Colombier 4687dd7cddfSDavid du Colombier sysremove(mb->path); 4697dd7cddfSDavid du Colombier if(sysrename(s_to_c(tmp), mb->path) < 0) 4707dd7cddfSDavid du Colombier fprint(2, "%s: can't rename %s to %s: %r\n", argv0, 4717dd7cddfSDavid du Colombier s_to_c(tmp), mb->path); 4727dd7cddfSDavid du Colombier s_free(tmp); 4737dd7cddfSDavid du Colombier dirstat(mb->path, &mb->d); 4747dd7cddfSDavid du Colombier } 4757dd7cddfSDavid du Colombier 4767dd7cddfSDavid du Colombier char* 4777dd7cddfSDavid du Colombier syncmbox(Mailbox *mb, int doplumb) 4787dd7cddfSDavid du Colombier { 4797dd7cddfSDavid du Colombier Mlock *lk; 4807dd7cddfSDavid du Colombier char *rv; 4817dd7cddfSDavid du Colombier 4827dd7cddfSDavid du Colombier lk = nil; 4837dd7cddfSDavid du Colombier if(mb->std){ 4847dd7cddfSDavid du Colombier lk = syslock(mb->path); 4857dd7cddfSDavid du Colombier if(lk == nil) 4867dd7cddfSDavid du Colombier return "can't lock mailbox"; 4877dd7cddfSDavid du Colombier } 4887dd7cddfSDavid du Colombier 4897dd7cddfSDavid du Colombier rv = _readmbox(mb, doplumb, lk); /* interpolate */ 4907dd7cddfSDavid du Colombier if(purgedeleted(mb) > 0) 4917dd7cddfSDavid du Colombier _writembox(mb, lk); 4927dd7cddfSDavid du Colombier 4937dd7cddfSDavid du Colombier if(lk != nil) 4947dd7cddfSDavid du Colombier sysunlock(lk); 4957dd7cddfSDavid du Colombier 4967dd7cddfSDavid du Colombier return rv; 4977dd7cddfSDavid du Colombier } 4987dd7cddfSDavid du Colombier 4997dd7cddfSDavid du Colombier static void 5007dd7cddfSDavid du Colombier initheaders(void) 5017dd7cddfSDavid du Colombier { 5027dd7cddfSDavid du Colombier Header *h; 5037dd7cddfSDavid du Colombier static int already; 5047dd7cddfSDavid du Colombier 5057dd7cddfSDavid du Colombier if(already) 5067dd7cddfSDavid du Colombier return; 5077dd7cddfSDavid du Colombier already = 1; 5087dd7cddfSDavid du Colombier 5097dd7cddfSDavid du Colombier for(h = head; h->type != nil; h++) 5107dd7cddfSDavid du Colombier h->len = strlen(h->type); 5117dd7cddfSDavid du Colombier } 5127dd7cddfSDavid du Colombier 5137dd7cddfSDavid du Colombier /* 5147dd7cddfSDavid du Colombier * parse a Unix style header 5157dd7cddfSDavid du Colombier */ 5167dd7cddfSDavid du Colombier static void 5177dd7cddfSDavid du Colombier parseunix(Message *m) 5187dd7cddfSDavid du Colombier { 5197dd7cddfSDavid du Colombier char *p; 5207dd7cddfSDavid du Colombier String *h; 5217dd7cddfSDavid du Colombier 5227dd7cddfSDavid du Colombier h = s_new(); 5237dd7cddfSDavid du Colombier for(p = m->start + 5; *p && *p != '\r' && *p != '\n'; p++) 5247dd7cddfSDavid du Colombier s_putc(h, *p); 5257dd7cddfSDavid du Colombier s_terminate(h); 5267dd7cddfSDavid du Colombier s_restart(h); 5277dd7cddfSDavid du Colombier 5287dd7cddfSDavid du Colombier m->unixfrom = s_parse(h, s_reset(m->unixfrom)); 5297dd7cddfSDavid du Colombier m->unixdate = s_append(s_reset(m->unixdate), h->ptr); 5307dd7cddfSDavid du Colombier 5317dd7cddfSDavid du Colombier s_free(h); 5327dd7cddfSDavid du Colombier } 5337dd7cddfSDavid du Colombier 5347dd7cddfSDavid du Colombier /* 5357dd7cddfSDavid du Colombier * parse a message 5367dd7cddfSDavid du Colombier */ 5377dd7cddfSDavid du Colombier static void 5387dd7cddfSDavid du Colombier parse(Message *m, int justmime, Mailbox *mb) 5397dd7cddfSDavid du Colombier { 5407dd7cddfSDavid du Colombier String *hl; 5417dd7cddfSDavid du Colombier Header *h; 5427dd7cddfSDavid du Colombier char *p; 5437dd7cddfSDavid du Colombier int i; 5447dd7cddfSDavid du Colombier 5457dd7cddfSDavid du Colombier 5467dd7cddfSDavid du Colombier if(m->whole == m->whole->whole){ 5477dd7cddfSDavid du Colombier henter(CHDIR|PATH(mb->id, Qmbox), m->name, 5487dd7cddfSDavid du Colombier (Qid){CHDIR|PATH(m->id, Qdir), 0}, m, mb); 5497dd7cddfSDavid du Colombier } else { 5507dd7cddfSDavid du Colombier henter(CHDIR|PATH(m->whole->id, Qdir), m->name, 5517dd7cddfSDavid du Colombier (Qid){CHDIR|PATH(m->id, Qdir), 0}, m, mb); 5527dd7cddfSDavid du Colombier } 5537dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 5547dd7cddfSDavid du Colombier henter(CHDIR|PATH(m->id, Qdir), dirtab[i], 5557dd7cddfSDavid du Colombier (Qid){PATH(m->id, i), 0}, m, mb); 5567dd7cddfSDavid du Colombier 5577dd7cddfSDavid du Colombier // parse mime headers 5587dd7cddfSDavid du Colombier p = m->header; 5597dd7cddfSDavid du Colombier hl = s_new(); 5607dd7cddfSDavid du Colombier while(headerline(&p, hl)){ 5617dd7cddfSDavid du Colombier if(justmime) 5627dd7cddfSDavid du Colombier h = &head[Mhead]; 5637dd7cddfSDavid du Colombier else 5647dd7cddfSDavid du Colombier h = head; 5657dd7cddfSDavid du Colombier for(; h->type; h++){ 5667dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(hl), h->type, h->len) == 0){ 5677dd7cddfSDavid du Colombier (*h->f)(m, h, s_to_c(hl)); 5687dd7cddfSDavid du Colombier break; 5697dd7cddfSDavid du Colombier } 5707dd7cddfSDavid du Colombier } 5717dd7cddfSDavid du Colombier s_reset(hl); 5727dd7cddfSDavid du Colombier } 5737dd7cddfSDavid du Colombier s_free(hl); 5747dd7cddfSDavid du Colombier 5757dd7cddfSDavid du Colombier // the blank line isn't really part of the body or header 5767dd7cddfSDavid du Colombier if(justmime){ 5777dd7cddfSDavid du Colombier m->mhend = p; 5787dd7cddfSDavid du Colombier m->hend = m->header; 5797dd7cddfSDavid du Colombier } else { 5807dd7cddfSDavid du Colombier m->hend = p; 5817dd7cddfSDavid du Colombier } 5827dd7cddfSDavid du Colombier if(*p == '\n') 5837dd7cddfSDavid du Colombier p++; 5847dd7cddfSDavid du Colombier m->rbody = m->body = p; 5857dd7cddfSDavid du Colombier 5867dd7cddfSDavid du Colombier // if the message isn't mime, ignore the type 5877dd7cddfSDavid du Colombier if(m->whole == m->whole->whole && m->mimeversion == nil){ 5887dd7cddfSDavid du Colombier s_append(s_reset(m->type), "text/plain"); 5897dd7cddfSDavid du Colombier } else { 5907dd7cddfSDavid du Colombier // recurse 5917dd7cddfSDavid du Colombier if(strncmp(s_to_c(m->type), "multipart/", 10) == 0){ 5927dd7cddfSDavid du Colombier parseattachments(m, mb); 5937dd7cddfSDavid du Colombier } else if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 5947dd7cddfSDavid du Colombier decode(m); 5957dd7cddfSDavid du Colombier parseattachments(m, mb); 5967dd7cddfSDavid du Colombier } 5977dd7cddfSDavid du Colombier } 5987dd7cddfSDavid du Colombier } 5997dd7cddfSDavid du Colombier 6007dd7cddfSDavid du Colombier static void 6017dd7cddfSDavid du Colombier parseattachments(Message *m, Mailbox *mb) 6027dd7cddfSDavid du Colombier { 6037dd7cddfSDavid du Colombier Message *nm, **l; 6047dd7cddfSDavid du Colombier char *p, *x; 6057dd7cddfSDavid du Colombier 6067dd7cddfSDavid du Colombier // if there's a boundary, recurse... 6077dd7cddfSDavid du Colombier if(m->boundary != nil){ 6087dd7cddfSDavid du Colombier p = m->body; 6097dd7cddfSDavid du Colombier nm = nil; 6107dd7cddfSDavid du Colombier l = &m->part; 6117dd7cddfSDavid du Colombier for(;;){ 6127dd7cddfSDavid du Colombier x = strstr(p, s_to_c(m->boundary)); 6137dd7cddfSDavid du Colombier if(x == nil || (x != m->body && *(x-1) != '\n')){ 6147dd7cddfSDavid du Colombier if(nm != nil) 6157dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = m->bend; 6167dd7cddfSDavid du Colombier break; 6177dd7cddfSDavid du Colombier } 6187dd7cddfSDavid du Colombier if(nm != nil) 6197dd7cddfSDavid du Colombier nm->rbend = nm->bend = nm->end = x; 6207dd7cddfSDavid du Colombier x += strlen(s_to_c(m->boundary)); 6217dd7cddfSDavid du Colombier 6227dd7cddfSDavid du Colombier /* is this the last part? ignore anything after it */ 6237dd7cddfSDavid du Colombier if(strncmp(x, "--", 2) == 0) 6247dd7cddfSDavid du Colombier break; 6257dd7cddfSDavid du Colombier 6267dd7cddfSDavid du Colombier p = strchr(x, '\n'); 6277dd7cddfSDavid du Colombier if(p == nil) 6287dd7cddfSDavid du Colombier break; 6297dd7cddfSDavid du Colombier nm = newmessage(m); 6307dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = ++p; 6317dd7cddfSDavid du Colombier nm->mheader = nm->header; 6327dd7cddfSDavid du Colombier *l = nm; 6337dd7cddfSDavid du Colombier l = &nm->next; 6347dd7cddfSDavid du Colombier } 6357dd7cddfSDavid du Colombier for(nm = m->part; nm != nil; nm = nm->next) 6367dd7cddfSDavid du Colombier parse(nm, 1, mb); 6377dd7cddfSDavid du Colombier } else { 6387dd7cddfSDavid du Colombier // reparse rfc822 messages 6397dd7cddfSDavid du Colombier if(strcmp(s_to_c(m->type), "message/rfc822") == 0){ 6407dd7cddfSDavid du Colombier if(m->unixfrom == nil && m->from822 == nil){ 6417dd7cddfSDavid du Colombier m->header = m->body; 6427dd7cddfSDavid du Colombier if(m->ballocd){ 6437dd7cddfSDavid du Colombier m->hallocd = 1; 6447dd7cddfSDavid du Colombier m->ballocd = 0; 6457dd7cddfSDavid du Colombier } 6467dd7cddfSDavid du Colombier s_free(m->type); 6477dd7cddfSDavid du Colombier m->type = s_copy("text/plain"); 6487dd7cddfSDavid du Colombier m->decoded = 0; 6497dd7cddfSDavid du Colombier m->converted = 0; 6507dd7cddfSDavid du Colombier parse(m, 0, mb); 6517dd7cddfSDavid du Colombier } else { 6527dd7cddfSDavid du Colombier nm = newmessage(m); 6537dd7cddfSDavid du Colombier m->part = nm; 6547dd7cddfSDavid du Colombier nm->start = nm->header = nm->body = nm->rbody = m->body; 6557dd7cddfSDavid du Colombier nm->end = nm->bend = nm->rbend = m->bend; 6567dd7cddfSDavid du Colombier parse(nm, 0, mb); 6577dd7cddfSDavid du Colombier } 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier } 6607dd7cddfSDavid du Colombier } 6617dd7cddfSDavid du Colombier 6627dd7cddfSDavid du Colombier /* 6637dd7cddfSDavid du Colombier * pick up a header line 6647dd7cddfSDavid du Colombier */ 6657dd7cddfSDavid du Colombier static int 6667dd7cddfSDavid du Colombier headerline(char **pp, String *hl) 6677dd7cddfSDavid du Colombier { 6687dd7cddfSDavid du Colombier char *p, *x; 6697dd7cddfSDavid du Colombier 6707dd7cddfSDavid du Colombier s_reset(hl); 6717dd7cddfSDavid du Colombier p = *pp; 6727dd7cddfSDavid du Colombier x = strpbrk(p, ":\n"); 6737dd7cddfSDavid du Colombier if(x == nil || *x == '\n') 6747dd7cddfSDavid du Colombier return 0; 6757dd7cddfSDavid du Colombier for(;;){ 6767dd7cddfSDavid du Colombier x = strchr(p, '\n'); 6777dd7cddfSDavid du Colombier if(x == nil) 6787dd7cddfSDavid du Colombier x = p + strlen(p); 6797dd7cddfSDavid du Colombier s_nappend(hl, p, x-p); 6807dd7cddfSDavid du Colombier p = x; 681*223a736eSDavid du Colombier if(*p != '\n' || *++p != ' ' && *p != '\t') 6827dd7cddfSDavid du Colombier break; 683*223a736eSDavid du Colombier while(*p == ' ' || *p == '\t') 684*223a736eSDavid du Colombier p++; 685*223a736eSDavid du Colombier s_putc(hl, ' '); 6867dd7cddfSDavid du Colombier } 6877dd7cddfSDavid du Colombier *pp = p; 6887dd7cddfSDavid du Colombier return 1; 6897dd7cddfSDavid du Colombier } 6907dd7cddfSDavid du Colombier 6917dd7cddfSDavid du Colombier static String* 6927dd7cddfSDavid du Colombier addr822(char *p) 6937dd7cddfSDavid du Colombier { 6947dd7cddfSDavid du Colombier String *s, *list; 6957dd7cddfSDavid du Colombier int incomment, addrdone, inanticomment, quoted; 6967dd7cddfSDavid du Colombier int n; 6977dd7cddfSDavid du Colombier int c; 6987dd7cddfSDavid du Colombier 6997dd7cddfSDavid du Colombier list = s_new(); 7007dd7cddfSDavid du Colombier s = s_new(); 7017dd7cddfSDavid du Colombier quoted = incomment = addrdone = inanticomment = 0; 7027dd7cddfSDavid du Colombier n = 0; 7037dd7cddfSDavid du Colombier for(; *p; p++){ 7047dd7cddfSDavid du Colombier c = *p; 7057dd7cddfSDavid du Colombier 7067dd7cddfSDavid du Colombier // whitespace is ignored 7077dd7cddfSDavid du Colombier if(!quoted && isspace(c) || c == '\r') 7087dd7cddfSDavid du Colombier continue; 7097dd7cddfSDavid du Colombier 7107dd7cddfSDavid du Colombier // strings are always treated as atoms 7117dd7cddfSDavid du Colombier if(!quoted && c == '"'){ 7127dd7cddfSDavid du Colombier if(!addrdone && !incomment) 7137dd7cddfSDavid du Colombier s_putc(s, c); 7147dd7cddfSDavid du Colombier for(p++; *p; p++){ 7157dd7cddfSDavid du Colombier if(!addrdone && !incomment) 7167dd7cddfSDavid du Colombier s_putc(s, *p); 7177dd7cddfSDavid du Colombier if(!quoted && *p == '"') 7187dd7cddfSDavid du Colombier break; 7197dd7cddfSDavid du Colombier if(*p == '\\') 7207dd7cddfSDavid du Colombier quoted = 1; 7217dd7cddfSDavid du Colombier else 7227dd7cddfSDavid du Colombier quoted = 0; 7237dd7cddfSDavid du Colombier } 7247dd7cddfSDavid du Colombier if(*p == 0) 7257dd7cddfSDavid du Colombier break; 7267dd7cddfSDavid du Colombier quoted = 0; 7277dd7cddfSDavid du Colombier continue; 7287dd7cddfSDavid du Colombier } 7297dd7cddfSDavid du Colombier 7307dd7cddfSDavid du Colombier // ignore everything in an expicit comment 7317dd7cddfSDavid du Colombier if(!quoted && c == '('){ 7327dd7cddfSDavid du Colombier incomment = 1; 7337dd7cddfSDavid du Colombier continue; 7347dd7cddfSDavid du Colombier } 7357dd7cddfSDavid du Colombier if(incomment){ 7367dd7cddfSDavid du Colombier if(!quoted && c == ')') 7377dd7cddfSDavid du Colombier incomment = 0; 7387dd7cddfSDavid du Colombier quoted = 0; 7397dd7cddfSDavid du Colombier continue; 7407dd7cddfSDavid du Colombier } 7417dd7cddfSDavid du Colombier 7427dd7cddfSDavid du Colombier // anticomments makes everything outside of them comments 7437dd7cddfSDavid du Colombier if(!quoted && c == '<' && !inanticomment){ 7447dd7cddfSDavid du Colombier inanticomment = 1; 7457dd7cddfSDavid du Colombier s = s_reset(s); 7467dd7cddfSDavid du Colombier continue; 7477dd7cddfSDavid du Colombier } 7487dd7cddfSDavid du Colombier if(!quoted && c == '>' && inanticomment){ 7497dd7cddfSDavid du Colombier addrdone = 1; 7507dd7cddfSDavid du Colombier inanticomment = 0; 7517dd7cddfSDavid du Colombier continue; 7527dd7cddfSDavid du Colombier } 7537dd7cddfSDavid du Colombier 7547dd7cddfSDavid du Colombier // commas separate addresses 7557dd7cddfSDavid du Colombier if(!quoted && c == ',' && !inanticomment){ 7567dd7cddfSDavid du Colombier s_terminate(s); 7577dd7cddfSDavid du Colombier addrdone = 0; 7587dd7cddfSDavid du Colombier if(n++ != 0) 7597dd7cddfSDavid du Colombier s_append(list, " "); 7607dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 7617dd7cddfSDavid du Colombier s = s_reset(s); 7627dd7cddfSDavid du Colombier continue; 7637dd7cddfSDavid du Colombier } 7647dd7cddfSDavid du Colombier 7657dd7cddfSDavid du Colombier // what's left is part of the address 7667dd7cddfSDavid du Colombier s_putc(s, c); 7677dd7cddfSDavid du Colombier 7687dd7cddfSDavid du Colombier // quoted characters are recognized only as characters 7697dd7cddfSDavid du Colombier if(c == '\\') 7707dd7cddfSDavid du Colombier quoted = 1; 7717dd7cddfSDavid du Colombier else 7727dd7cddfSDavid du Colombier quoted = 0; 7737dd7cddfSDavid du Colombier 7747dd7cddfSDavid du Colombier } 7757dd7cddfSDavid du Colombier 7767dd7cddfSDavid du Colombier if(*s_to_c(s) != 0){ 7777dd7cddfSDavid du Colombier s_terminate(s); 7787dd7cddfSDavid du Colombier if(n++ != 0) 7797dd7cddfSDavid du Colombier s_append(list, " "); 7807dd7cddfSDavid du Colombier s_append(list, s_to_c(s)); 7817dd7cddfSDavid du Colombier } 7827dd7cddfSDavid du Colombier s_free(s); 7837dd7cddfSDavid du Colombier 7847dd7cddfSDavid du Colombier if(n == 0){ 7857dd7cddfSDavid du Colombier s_free(list); 7867dd7cddfSDavid du Colombier return nil; 7877dd7cddfSDavid du Colombier } 7887dd7cddfSDavid du Colombier return list; 7897dd7cddfSDavid du Colombier } 7907dd7cddfSDavid du Colombier 7917dd7cddfSDavid du Colombier static void 7927dd7cddfSDavid du Colombier to822(Message *m, Header *h, char *p) 7937dd7cddfSDavid du Colombier { 7947dd7cddfSDavid du Colombier p += strlen(h->type); 7957dd7cddfSDavid du Colombier s_free(m->to822); 7967dd7cddfSDavid du Colombier m->to822 = addr822(p); 7977dd7cddfSDavid du Colombier } 7987dd7cddfSDavid du Colombier 7997dd7cddfSDavid du Colombier static void 8007dd7cddfSDavid du Colombier cc822(Message *m, Header *h, char *p) 8017dd7cddfSDavid du Colombier { 8027dd7cddfSDavid du Colombier p += strlen(h->type); 8037dd7cddfSDavid du Colombier s_free(m->cc822); 8047dd7cddfSDavid du Colombier m->cc822 = addr822(p); 8057dd7cddfSDavid du Colombier } 8067dd7cddfSDavid du Colombier 8077dd7cddfSDavid du Colombier static void 8087dd7cddfSDavid du Colombier bcc822(Message *m, Header *h, char *p) 8097dd7cddfSDavid du Colombier { 8107dd7cddfSDavid du Colombier p += strlen(h->type); 8117dd7cddfSDavid du Colombier s_free(m->bcc822); 8127dd7cddfSDavid du Colombier m->bcc822 = addr822(p); 8137dd7cddfSDavid du Colombier } 8147dd7cddfSDavid du Colombier 8157dd7cddfSDavid du Colombier static void 8167dd7cddfSDavid du Colombier from822(Message *m, Header *h, char *p) 8177dd7cddfSDavid du Colombier { 8187dd7cddfSDavid du Colombier p += strlen(h->type); 8197dd7cddfSDavid du Colombier s_free(m->from822); 8207dd7cddfSDavid du Colombier m->from822 = addr822(p); 8217dd7cddfSDavid du Colombier } 8227dd7cddfSDavid du Colombier 8237dd7cddfSDavid du Colombier static void 8247dd7cddfSDavid du Colombier sender822(Message *m, Header *h, char *p) 8257dd7cddfSDavid du Colombier { 8267dd7cddfSDavid du Colombier p += strlen(h->type); 8277dd7cddfSDavid du Colombier s_free(m->sender822); 8287dd7cddfSDavid du Colombier m->sender822 = addr822(p); 8297dd7cddfSDavid du Colombier } 8307dd7cddfSDavid du Colombier 8317dd7cddfSDavid du Colombier static void 8327dd7cddfSDavid du Colombier replyto822(Message *m, Header *h, char *p) 8337dd7cddfSDavid du Colombier { 8347dd7cddfSDavid du Colombier p += strlen(h->type); 8357dd7cddfSDavid du Colombier s_free(m->replyto822); 8367dd7cddfSDavid du Colombier m->replyto822 = addr822(p); 8377dd7cddfSDavid du Colombier } 8387dd7cddfSDavid du Colombier 8397dd7cddfSDavid du Colombier static void 8407dd7cddfSDavid du Colombier mimeversion(Message *m, Header *h, char *p) 8417dd7cddfSDavid du Colombier { 8427dd7cddfSDavid du Colombier p += strlen(h->type); 8437dd7cddfSDavid du Colombier s_free(m->mimeversion); 8447dd7cddfSDavid du Colombier m->mimeversion = addr822(p); 8457dd7cddfSDavid du Colombier } 8467dd7cddfSDavid du Colombier 8477dd7cddfSDavid du Colombier static void 8487dd7cddfSDavid du Colombier killtrailingwhite(char *p) 8497dd7cddfSDavid du Colombier { 8507dd7cddfSDavid du Colombier char *e; 8517dd7cddfSDavid du Colombier 8527dd7cddfSDavid du Colombier e = p + strlen(p) - 1; 8537dd7cddfSDavid du Colombier while(e > p && isspace(*e)) 8547dd7cddfSDavid du Colombier *e-- = 0; 8557dd7cddfSDavid du Colombier } 8567dd7cddfSDavid du Colombier 8577dd7cddfSDavid du Colombier static void 8587dd7cddfSDavid du Colombier date822(Message *m, Header *h, char *p) 8597dd7cddfSDavid du Colombier { 8607dd7cddfSDavid du Colombier p += strlen(h->type); 8617dd7cddfSDavid du Colombier p = skipwhite(p); 8627dd7cddfSDavid du Colombier s_free(m->date822); 8637dd7cddfSDavid du Colombier m->date822 = s_copy(p); 8647dd7cddfSDavid du Colombier p = s_to_c(m->date822); 8657dd7cddfSDavid du Colombier killtrailingwhite(p); 8667dd7cddfSDavid du Colombier } 8677dd7cddfSDavid du Colombier 8687dd7cddfSDavid du Colombier static void 8697dd7cddfSDavid du Colombier subject822(Message *m, Header *h, char *p) 8707dd7cddfSDavid du Colombier { 8717dd7cddfSDavid du Colombier p += strlen(h->type); 8727dd7cddfSDavid du Colombier p = skipwhite(p); 8737dd7cddfSDavid du Colombier s_free(m->subject822); 8747dd7cddfSDavid du Colombier m->subject822 = s_copy(p); 8757dd7cddfSDavid du Colombier p = s_to_c(m->subject822); 8767dd7cddfSDavid du Colombier killtrailingwhite(p); 8777dd7cddfSDavid du Colombier } 8787dd7cddfSDavid du Colombier 8797dd7cddfSDavid du Colombier static void 8807dd7cddfSDavid du Colombier inreplyto822(Message *m, Header *h, char *p) 8817dd7cddfSDavid du Colombier { 8827dd7cddfSDavid du Colombier p += strlen(h->type); 8837dd7cddfSDavid du Colombier p = skipwhite(p); 8847dd7cddfSDavid du Colombier s_free(m->inreplyto822); 8857dd7cddfSDavid du Colombier m->inreplyto822 = s_copy(p); 8867dd7cddfSDavid du Colombier p = s_to_c(m->inreplyto822); 8877dd7cddfSDavid du Colombier killtrailingwhite(p); 8887dd7cddfSDavid du Colombier } 8897dd7cddfSDavid du Colombier 8907dd7cddfSDavid du Colombier static void 8917dd7cddfSDavid du Colombier messageid822(Message *m, Header *h, char *p) 8927dd7cddfSDavid du Colombier { 8937dd7cddfSDavid du Colombier p += strlen(h->type); 8947dd7cddfSDavid du Colombier p = skipwhite(p); 8957dd7cddfSDavid du Colombier s_free(m->messageid822); 8967dd7cddfSDavid du Colombier m->messageid822 = s_copy(p); 8977dd7cddfSDavid du Colombier p = s_to_c(m->messageid822); 8987dd7cddfSDavid du Colombier killtrailingwhite(p); 8997dd7cddfSDavid du Colombier } 9007dd7cddfSDavid du Colombier 9017dd7cddfSDavid du Colombier static int 9027dd7cddfSDavid du Colombier isattribute(char **pp, char *attr) 9037dd7cddfSDavid du Colombier { 9047dd7cddfSDavid du Colombier char *p; 9057dd7cddfSDavid du Colombier int n; 9067dd7cddfSDavid du Colombier 9077dd7cddfSDavid du Colombier n = strlen(attr); 9087dd7cddfSDavid du Colombier p = *pp; 9097dd7cddfSDavid du Colombier if(cistrncmp(p, attr, n) != 0) 9107dd7cddfSDavid du Colombier return 0; 9117dd7cddfSDavid du Colombier p += n; 9127dd7cddfSDavid du Colombier while(*p == ' ') 9137dd7cddfSDavid du Colombier p++; 9147dd7cddfSDavid du Colombier if(*p++ != '=') 9157dd7cddfSDavid du Colombier return 0; 9167dd7cddfSDavid du Colombier while(*p == ' ') 9177dd7cddfSDavid du Colombier p++; 9187dd7cddfSDavid du Colombier *pp = p; 9197dd7cddfSDavid du Colombier return 1; 9207dd7cddfSDavid du Colombier } 9217dd7cddfSDavid du Colombier 9227dd7cddfSDavid du Colombier static void 9237dd7cddfSDavid du Colombier ctype(Message *m, Header *h, char *p) 9247dd7cddfSDavid du Colombier { 9257dd7cddfSDavid du Colombier String *s; 9267dd7cddfSDavid du Colombier 9277dd7cddfSDavid du Colombier p += h->len; 9287dd7cddfSDavid du Colombier p = skipwhite(p); 9297dd7cddfSDavid du Colombier 9307dd7cddfSDavid du Colombier p = getstring(p, m->type, 1); 9317dd7cddfSDavid du Colombier 9327dd7cddfSDavid du Colombier while(*p){ 9337dd7cddfSDavid du Colombier if(isattribute(&p, "boundary")){ 9347dd7cddfSDavid du Colombier s = s_new(); 9357dd7cddfSDavid du Colombier p = getstring(p, s, 0); 9367dd7cddfSDavid du Colombier m->boundary = s_reset(m->boundary); 9377dd7cddfSDavid du Colombier s_append(m->boundary, "--"); 9387dd7cddfSDavid du Colombier s_append(m->boundary, s_to_c(s)); 9397dd7cddfSDavid du Colombier s_free(s); 9407dd7cddfSDavid du Colombier } else if(cistrncmp(p, "multipart", 9) == 0){ 9417dd7cddfSDavid du Colombier /* 9427dd7cddfSDavid du Colombier * the first unbounded part of a multipart message, 9437dd7cddfSDavid du Colombier * the preamble, is not displayed or saved 9447dd7cddfSDavid du Colombier */ 9457dd7cddfSDavid du Colombier } else if(isattribute(&p, "name")){ 9467dd7cddfSDavid du Colombier if(m->filename == nil) 9477dd7cddfSDavid du Colombier setfilename(m, p); 9487dd7cddfSDavid du Colombier } else if(isattribute(&p, "charset")){ 9497dd7cddfSDavid du Colombier p = getstring(p, s_reset(m->charset), 0); 9507dd7cddfSDavid du Colombier } 9517dd7cddfSDavid du Colombier 9527dd7cddfSDavid du Colombier p = skiptosemi(p); 9537dd7cddfSDavid du Colombier } 9547dd7cddfSDavid du Colombier } 9557dd7cddfSDavid du Colombier 9567dd7cddfSDavid du Colombier static void 9577dd7cddfSDavid du Colombier cencoding(Message *m, Header *h, char *p) 9587dd7cddfSDavid du Colombier { 9597dd7cddfSDavid du Colombier p += h->len; 9607dd7cddfSDavid du Colombier p = skipwhite(p); 9617dd7cddfSDavid du Colombier if(cistrncmp(p, "base64", 6) == 0) 9627dd7cddfSDavid du Colombier m->encoding = Ebase64; 9637dd7cddfSDavid du Colombier else if(cistrncmp(p, "quoted-printable", 16) == 0) 9647dd7cddfSDavid du Colombier m->encoding = Equoted; 9657dd7cddfSDavid du Colombier } 9667dd7cddfSDavid du Colombier 9677dd7cddfSDavid du Colombier static void 9687dd7cddfSDavid du Colombier cdisposition(Message *m, Header *h, char *p) 9697dd7cddfSDavid du Colombier { 9707dd7cddfSDavid du Colombier p += h->len; 9717dd7cddfSDavid du Colombier p = skipwhite(p); 9727dd7cddfSDavid du Colombier while(*p){ 9737dd7cddfSDavid du Colombier if(cistrncmp(p, "inline", 6) == 0){ 9747dd7cddfSDavid du Colombier m->disposition = Dinline; 9757dd7cddfSDavid du Colombier } else if(cistrncmp(p, "attachment", 10) == 0){ 9767dd7cddfSDavid du Colombier m->disposition = Dfile; 9777dd7cddfSDavid du Colombier } else if(cistrncmp(p, "filename=", 9) == 0){ 9787dd7cddfSDavid du Colombier p += 9; 9797dd7cddfSDavid du Colombier setfilename(m, p); 9807dd7cddfSDavid du Colombier } 9817dd7cddfSDavid du Colombier p = skiptosemi(p); 9827dd7cddfSDavid du Colombier } 9837dd7cddfSDavid du Colombier 9847dd7cddfSDavid du Colombier } 9857dd7cddfSDavid du Colombier 9867dd7cddfSDavid du Colombier ulong msgallocd, msgfreed; 9877dd7cddfSDavid du Colombier 9887dd7cddfSDavid du Colombier Message* 9897dd7cddfSDavid du Colombier newmessage(Message *parent) 9907dd7cddfSDavid du Colombier { 9917dd7cddfSDavid du Colombier static int id; 9927dd7cddfSDavid du Colombier Message *m; 9937dd7cddfSDavid du Colombier 9947dd7cddfSDavid du Colombier msgallocd++; 9957dd7cddfSDavid du Colombier 9967dd7cddfSDavid du Colombier m = emalloc(sizeof(*m)); 9977dd7cddfSDavid du Colombier memset(m, 0, sizeof(*m)); 9987dd7cddfSDavid du Colombier m->disposition = Dnone; 9997dd7cddfSDavid du Colombier m->type = s_copy("text/plain"); 10007dd7cddfSDavid du Colombier m->charset = s_copy("iso-8859-1"); 10017dd7cddfSDavid du Colombier m->id = newid(); 10027dd7cddfSDavid du Colombier if(parent) 10037dd7cddfSDavid du Colombier sprint(m->name, "%d", ++(parent->subname)); 10047dd7cddfSDavid du Colombier if(parent == nil) 10057dd7cddfSDavid du Colombier parent = m; 10067dd7cddfSDavid du Colombier m->whole = parent; 10077dd7cddfSDavid du Colombier m->hlen = -1; 10087dd7cddfSDavid du Colombier return m; 10097dd7cddfSDavid du Colombier } 10107dd7cddfSDavid du Colombier 10117dd7cddfSDavid du Colombier // delete a message from a mailbox 10127dd7cddfSDavid du Colombier void 10137dd7cddfSDavid du Colombier delmessage(Mailbox *mb, Message *m) 10147dd7cddfSDavid du Colombier { 10157dd7cddfSDavid du Colombier Message **l; 10167dd7cddfSDavid du Colombier int i; 10177dd7cddfSDavid du Colombier 10187dd7cddfSDavid du Colombier mb->vers++; 10197dd7cddfSDavid du Colombier msgfreed++; 10207dd7cddfSDavid du Colombier 10217dd7cddfSDavid du Colombier if(m->whole != m){ 10227dd7cddfSDavid du Colombier // unchain from parent 10237dd7cddfSDavid du Colombier for(l = &m->whole->part; *l && *l != m; l = &(*l)->next) 10247dd7cddfSDavid du Colombier ; 10257dd7cddfSDavid du Colombier if(*l != nil) 10267dd7cddfSDavid du Colombier *l = m->next; 10277dd7cddfSDavid du Colombier 10287dd7cddfSDavid du Colombier // clear out of name lookup hash table 10297dd7cddfSDavid du Colombier if(m->whole->whole == m->whole) 10307dd7cddfSDavid du Colombier hfree(CHDIR|PATH(mb->id, Qmbox), m->name); 10317dd7cddfSDavid du Colombier else 10327dd7cddfSDavid du Colombier hfree(CHDIR|PATH(m->whole->id, Qdir), m->name); 10337dd7cddfSDavid du Colombier for(i = 0; i < Qmax; i++) 10347dd7cddfSDavid du Colombier hfree(CHDIR|PATH(m->id, Qdir), dirtab[i]); 10357dd7cddfSDavid du Colombier } 10367dd7cddfSDavid du Colombier 10377dd7cddfSDavid du Colombier /* recurse through sub-parts */ 10387dd7cddfSDavid du Colombier while(m->part) 10397dd7cddfSDavid du Colombier delmessage(mb, m->part); 10407dd7cddfSDavid du Colombier 10417dd7cddfSDavid du Colombier /* free memory */ 10427dd7cddfSDavid du Colombier if(m->mallocd) 10437dd7cddfSDavid du Colombier free(m->start); 10447dd7cddfSDavid du Colombier if(m->hallocd) 10457dd7cddfSDavid du Colombier free(m->header); 10467dd7cddfSDavid du Colombier if(m->ballocd) 10477dd7cddfSDavid du Colombier free(m->body); 10487dd7cddfSDavid du Colombier s_free(m->unixfrom); 10497dd7cddfSDavid du Colombier s_free(m->unixdate); 10507dd7cddfSDavid du Colombier s_free(m->from822); 10517dd7cddfSDavid du Colombier s_free(m->sender822); 10527dd7cddfSDavid du Colombier s_free(m->to822); 10537dd7cddfSDavid du Colombier s_free(m->cc822); 10547dd7cddfSDavid du Colombier s_free(m->bcc822); 10557dd7cddfSDavid du Colombier s_free(m->replyto822); 10567dd7cddfSDavid du Colombier s_free(m->date822); 10577dd7cddfSDavid du Colombier s_free(m->subject822); 10587dd7cddfSDavid du Colombier s_free(m->inreplyto822); 10597dd7cddfSDavid du Colombier s_free(m->messageid822); 10607dd7cddfSDavid du Colombier s_free(m->addrs); 10617dd7cddfSDavid du Colombier s_free(m->mimeversion); 10627dd7cddfSDavid du Colombier s_free(m->boundary); 10637dd7cddfSDavid du Colombier s_free(m->type); 10647dd7cddfSDavid du Colombier s_free(m->charset); 10657dd7cddfSDavid du Colombier s_free(m->filename); 10667dd7cddfSDavid du Colombier 10677dd7cddfSDavid du Colombier free(m); 10687dd7cddfSDavid du Colombier } 10697dd7cddfSDavid du Colombier 10707dd7cddfSDavid du Colombier // mark messages (identified by path) for deletion 10717dd7cddfSDavid du Colombier void 10727dd7cddfSDavid du Colombier delmessages(int ac, char **av) 10737dd7cddfSDavid du Colombier { 10747dd7cddfSDavid du Colombier Mailbox *mb; 10757dd7cddfSDavid du Colombier Message *m; 10767dd7cddfSDavid du Colombier int i, needwrite; 10777dd7cddfSDavid du Colombier 10787dd7cddfSDavid du Colombier qlock(&mbllock); 10797dd7cddfSDavid du Colombier for(mb = mbl; mb != nil; mb = mb->next) 10807dd7cddfSDavid du Colombier if(strcmp(av[0], mb->name) == 0){ 10817dd7cddfSDavid du Colombier qlock(mb); 10827dd7cddfSDavid du Colombier break; 10837dd7cddfSDavid du Colombier } 10847dd7cddfSDavid du Colombier qunlock(&mbllock); 10857dd7cddfSDavid du Colombier if(mb == nil) 10867dd7cddfSDavid du Colombier return; 10877dd7cddfSDavid du Colombier 10887dd7cddfSDavid du Colombier needwrite = 0; 10897dd7cddfSDavid du Colombier for(i = 1; i < ac; i++){ 10907dd7cddfSDavid du Colombier for(m = mb->root->part; m != nil; m = m->next) 10917dd7cddfSDavid du Colombier if(strcmp(m->name, av[i]) == 0){ 10927dd7cddfSDavid du Colombier if(!m->deleted){ 10937dd7cddfSDavid du Colombier mailplumb(mb, m, 1); 10947dd7cddfSDavid du Colombier needwrite = 1; 10957dd7cddfSDavid du Colombier m->deleted = 1; 10967dd7cddfSDavid du Colombier } 10977dd7cddfSDavid du Colombier break; 10987dd7cddfSDavid du Colombier } 10997dd7cddfSDavid du Colombier } 11007dd7cddfSDavid du Colombier if(needwrite) 11017dd7cddfSDavid du Colombier syncmbox(mb, 1); 11027dd7cddfSDavid du Colombier qunlock(mb); 11037dd7cddfSDavid du Colombier } 11047dd7cddfSDavid du Colombier 11057dd7cddfSDavid du Colombier /* 11067dd7cddfSDavid du Colombier * the following are called with the mailbox qlocked 11077dd7cddfSDavid du Colombier */ 11087dd7cddfSDavid du Colombier void 11097dd7cddfSDavid du Colombier msgincref(Message *m) 11107dd7cddfSDavid du Colombier { 11117dd7cddfSDavid du Colombier m->refs++; 11127dd7cddfSDavid du Colombier } 11137dd7cddfSDavid du Colombier void 11147dd7cddfSDavid du Colombier msgdecref(Mailbox *mb, Message *m) 11157dd7cddfSDavid du Colombier { 11167dd7cddfSDavid du Colombier m->refs--; 11177dd7cddfSDavid du Colombier if(m->refs == 0 && m->deleted) 11187dd7cddfSDavid du Colombier syncmbox(mb, 1); 11197dd7cddfSDavid du Colombier } 11207dd7cddfSDavid du Colombier 11217dd7cddfSDavid du Colombier /* 11227dd7cddfSDavid du Colombier * the following are called with mbllock'd 11237dd7cddfSDavid du Colombier */ 11247dd7cddfSDavid du Colombier void 11257dd7cddfSDavid du Colombier mboxincref(Mailbox *mb) 11267dd7cddfSDavid du Colombier { 11277dd7cddfSDavid du Colombier mb->refs++; 11287dd7cddfSDavid du Colombier } 11297dd7cddfSDavid du Colombier void 11307dd7cddfSDavid du Colombier mboxdecref(Mailbox *mb) 11317dd7cddfSDavid du Colombier { 11327dd7cddfSDavid du Colombier Mailbox **l; 11337dd7cddfSDavid du Colombier 11347dd7cddfSDavid du Colombier qlock(mb); 11357dd7cddfSDavid du Colombier mb->refs--; 11367dd7cddfSDavid du Colombier if(mb->refs == 0){ 11377dd7cddfSDavid du Colombier for(l = &mbl; *l != nil; l = &(*l)->next){ 11387dd7cddfSDavid du Colombier if(*l == mb){ 11397dd7cddfSDavid du Colombier *l = mb->next; 11407dd7cddfSDavid du Colombier break; 11417dd7cddfSDavid du Colombier } 11427dd7cddfSDavid du Colombier } 11437dd7cddfSDavid du Colombier delmessage(mb, mb->root); 11447dd7cddfSDavid du Colombier qunlock(mb); 11457dd7cddfSDavid du Colombier free(mb); 11467dd7cddfSDavid du Colombier } else 11477dd7cddfSDavid du Colombier qunlock(mb); 11487dd7cddfSDavid du Colombier } 11497dd7cddfSDavid du Colombier 11507dd7cddfSDavid du Colombier int 11517dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 11527dd7cddfSDavid du Colombier { 11537dd7cddfSDavid du Colombier while(n-- > 0){ 11547dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 11557dd7cddfSDavid du Colombier return -1; 11567dd7cddfSDavid du Colombier } 11577dd7cddfSDavid du Colombier return 0; 11587dd7cddfSDavid du Colombier } 11597dd7cddfSDavid du Colombier 11607dd7cddfSDavid du Colombier int 11617dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 11627dd7cddfSDavid du Colombier { 11637dd7cddfSDavid du Colombier for(;;){ 11647dd7cddfSDavid du Colombier if(tolower(*a) != tolower(*b++)) 11657dd7cddfSDavid du Colombier return -1; 11667dd7cddfSDavid du Colombier if(*a++ == 0) 11677dd7cddfSDavid du Colombier break; 11687dd7cddfSDavid du Colombier } 11697dd7cddfSDavid du Colombier return 0; 11707dd7cddfSDavid du Colombier } 11717dd7cddfSDavid du Colombier 11727dd7cddfSDavid du Colombier static char* 11737dd7cddfSDavid du Colombier skipwhite(char *p) 11747dd7cddfSDavid du Colombier { 11757dd7cddfSDavid du Colombier while(isspace(*p)) 11767dd7cddfSDavid du Colombier p++; 11777dd7cddfSDavid du Colombier return p; 11787dd7cddfSDavid du Colombier } 11797dd7cddfSDavid du Colombier 11807dd7cddfSDavid du Colombier static char* 11817dd7cddfSDavid du Colombier skiptosemi(char *p) 11827dd7cddfSDavid du Colombier { 11837dd7cddfSDavid du Colombier while(*p && *p != ';') 11847dd7cddfSDavid du Colombier p++; 11857dd7cddfSDavid du Colombier while(*p == ';' || isspace(*p)) 11867dd7cddfSDavid du Colombier p++; 11877dd7cddfSDavid du Colombier return p; 11887dd7cddfSDavid du Colombier } 11897dd7cddfSDavid du Colombier 11907dd7cddfSDavid du Colombier static char* 11917dd7cddfSDavid du Colombier getstring(char *p, String *s, int dolower) 11927dd7cddfSDavid du Colombier { 11937dd7cddfSDavid du Colombier s = s_reset(s); 11947dd7cddfSDavid du Colombier p = skipwhite(p); 11957dd7cddfSDavid du Colombier if(*p == '"'){ 11967dd7cddfSDavid du Colombier p++; 11977dd7cddfSDavid du Colombier for(;*p && *p != '"'; p++) 11987dd7cddfSDavid du Colombier if(dolower) 11997dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 12007dd7cddfSDavid du Colombier else 12017dd7cddfSDavid du Colombier s_putc(s, *p); 12027dd7cddfSDavid du Colombier if(*p == '"') 12037dd7cddfSDavid du Colombier p++; 12047dd7cddfSDavid du Colombier s_terminate(s); 12057dd7cddfSDavid du Colombier 12067dd7cddfSDavid du Colombier return p; 12077dd7cddfSDavid du Colombier } 12087dd7cddfSDavid du Colombier 12097dd7cddfSDavid du Colombier for(;!isspace(*p) && *p != ';'; p++) 12107dd7cddfSDavid du Colombier if(dolower) 12117dd7cddfSDavid du Colombier s_putc(s, tolower(*p)); 12127dd7cddfSDavid du Colombier else 12137dd7cddfSDavid du Colombier s_putc(s, *p); 12147dd7cddfSDavid du Colombier s_terminate(s); 12157dd7cddfSDavid du Colombier 12167dd7cddfSDavid du Colombier return p; 12177dd7cddfSDavid du Colombier } 12187dd7cddfSDavid du Colombier 12197dd7cddfSDavid du Colombier static void 12207dd7cddfSDavid du Colombier setfilename(Message *m, char *p) 12217dd7cddfSDavid du Colombier { 12227dd7cddfSDavid du Colombier m->filename = s_reset(m->filename); 12237dd7cddfSDavid du Colombier getstring(p, m->filename, 0); 12247dd7cddfSDavid du Colombier for(p = s_to_c(m->filename); *p; p++) 12257dd7cddfSDavid du Colombier if(*p == ' ' || *p == '\t' || *p == ';') 12267dd7cddfSDavid du Colombier *p = '_'; 12277dd7cddfSDavid du Colombier } 12287dd7cddfSDavid du Colombier 12297dd7cddfSDavid du Colombier // 12307dd7cddfSDavid du Colombier // undecode message body 12317dd7cddfSDavid du Colombier // 12327dd7cddfSDavid du Colombier void 12337dd7cddfSDavid du Colombier decode(Message *m) 12347dd7cddfSDavid du Colombier { 12357dd7cddfSDavid du Colombier int i, len; 12367dd7cddfSDavid du Colombier char *x; 12377dd7cddfSDavid du Colombier 12387dd7cddfSDavid du Colombier if(m->decoded) 12397dd7cddfSDavid du Colombier return; 12407dd7cddfSDavid du Colombier switch(m->encoding){ 12417dd7cddfSDavid du Colombier case Ebase64: 12427dd7cddfSDavid du Colombier len = m->bend - m->body; 12437dd7cddfSDavid du Colombier i = (len*3)/4+1; // room for max chars + null 12447dd7cddfSDavid du Colombier x = emalloc(i); 12457dd7cddfSDavid du Colombier len = dec64((uchar*)x, i, m->body, len); 12467dd7cddfSDavid du Colombier if(m->ballocd) 12477dd7cddfSDavid du Colombier free(m->body); 12487dd7cddfSDavid du Colombier m->body = x; 12497dd7cddfSDavid du Colombier m->bend = x + len; 12507dd7cddfSDavid du Colombier m->ballocd = 1; 12517dd7cddfSDavid du Colombier break; 12527dd7cddfSDavid du Colombier case Equoted: 12537dd7cddfSDavid du Colombier len = m->bend - m->body; 12547dd7cddfSDavid du Colombier x = emalloc(len+2); // room for null and possible extra nl 12557dd7cddfSDavid du Colombier len = decquoted(x, m->body, m->bend); 12567dd7cddfSDavid du Colombier if(m->ballocd) 12577dd7cddfSDavid du Colombier free(m->body); 12587dd7cddfSDavid du Colombier m->body = x; 12597dd7cddfSDavid du Colombier m->bend = x + len; 12607dd7cddfSDavid du Colombier m->ballocd = 1; 12617dd7cddfSDavid du Colombier break; 12627dd7cddfSDavid du Colombier default: 12637dd7cddfSDavid du Colombier break; 12647dd7cddfSDavid du Colombier } 12657dd7cddfSDavid du Colombier m->decoded = 1; 12667dd7cddfSDavid du Colombier } 12677dd7cddfSDavid du Colombier 12687dd7cddfSDavid du Colombier // convert latin1 to utf 12697dd7cddfSDavid du Colombier void 12707dd7cddfSDavid du Colombier convert(Message *m) 12717dd7cddfSDavid du Colombier { 12727dd7cddfSDavid du Colombier int len; 12737dd7cddfSDavid du Colombier char *x; 12747dd7cddfSDavid du Colombier 12757dd7cddfSDavid du Colombier // don't convert if we're not a leaf, not text, or already converted 12767dd7cddfSDavid du Colombier if(m->converted) 12777dd7cddfSDavid du Colombier return; 12787dd7cddfSDavid du Colombier if(m->part != nil) 12797dd7cddfSDavid du Colombier return; 12807dd7cddfSDavid du Colombier if(cistrncmp(s_to_c(m->type), "text", 4) != 0) 12817dd7cddfSDavid du Colombier return; 12827dd7cddfSDavid du Colombier 12837dd7cddfSDavid du Colombier if(cistrcmp(s_to_c(m->charset), "us-ascii") == 0 || 12847dd7cddfSDavid du Colombier cistrcmp(s_to_c(m->charset), "iso-8859-1") == 0){ 12857dd7cddfSDavid du Colombier len = is8bit(m); 12867dd7cddfSDavid du Colombier if(len > 0){ 12877dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 12887dd7cddfSDavid du Colombier x = emalloc(len); 12897dd7cddfSDavid du Colombier len = latin1toutf(x, m->body, m->bend); 12907dd7cddfSDavid du Colombier if(m->ballocd) 12917dd7cddfSDavid du Colombier free(m->body); 12927dd7cddfSDavid du Colombier m->body = x; 12937dd7cddfSDavid du Colombier m->bend = x + len; 12947dd7cddfSDavid du Colombier m->ballocd = 1; 12957dd7cddfSDavid du Colombier } 12967dd7cddfSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "big5") == 0){ 12977dd7cddfSDavid du Colombier len = xtoutf("big5", &x, m->body, m->bend); 12987dd7cddfSDavid du Colombier if(len != 0){ 12997dd7cddfSDavid du Colombier if(m->ballocd) 13007dd7cddfSDavid du Colombier free(m->body); 13017dd7cddfSDavid du Colombier m->body = x; 13027dd7cddfSDavid du Colombier m->bend = x + len; 13037dd7cddfSDavid du Colombier m->ballocd = 1; 13047dd7cddfSDavid du Colombier } 13057dd7cddfSDavid du Colombier } else if(cistrcmp(s_to_c(m->charset), "windows-1257") == 0){ 13067dd7cddfSDavid du Colombier len = is8bit(m); 13077dd7cddfSDavid du Colombier if(len > 0){ 13087dd7cddfSDavid du Colombier len = 2*len + m->bend - m->body + 1; 13097dd7cddfSDavid du Colombier x = emalloc(len); 13107dd7cddfSDavid du Colombier len = windows1257toutf(x, m->body, m->bend); 13117dd7cddfSDavid du Colombier if(m->ballocd) 13127dd7cddfSDavid du Colombier free(m->body); 13137dd7cddfSDavid du Colombier m->body = x; 13147dd7cddfSDavid du Colombier m->bend = x + len; 13157dd7cddfSDavid du Colombier m->ballocd = 1; 13167dd7cddfSDavid du Colombier } 13177dd7cddfSDavid du Colombier } 13187dd7cddfSDavid du Colombier 13197dd7cddfSDavid du Colombier m->converted = 1; 13207dd7cddfSDavid du Colombier } 13217dd7cddfSDavid du Colombier 13227dd7cddfSDavid du Colombier enum 13237dd7cddfSDavid du Colombier { 13247dd7cddfSDavid du Colombier Self= 1, 13257dd7cddfSDavid du Colombier Hex= 2, 13267dd7cddfSDavid du Colombier }; 13277dd7cddfSDavid du Colombier uchar tableqp[256]; 13287dd7cddfSDavid du Colombier 13297dd7cddfSDavid du Colombier static void 13307dd7cddfSDavid du Colombier initquoted(void) 13317dd7cddfSDavid du Colombier { 13327dd7cddfSDavid du Colombier int c; 13337dd7cddfSDavid du Colombier 13347dd7cddfSDavid du Colombier memset(tableqp, 0, 256); 13357dd7cddfSDavid du Colombier for(c = ' '; c <= '<'; c++) 13367dd7cddfSDavid du Colombier tableqp[c] = Self; 13377dd7cddfSDavid du Colombier for(c = '>'; c <= '~'; c++) 13387dd7cddfSDavid du Colombier tableqp[c] = Self; 13397dd7cddfSDavid du Colombier tableqp['\t'] = Self; 13407dd7cddfSDavid du Colombier tableqp['='] = Hex; 13417dd7cddfSDavid du Colombier } 13427dd7cddfSDavid du Colombier 13437dd7cddfSDavid du Colombier static int 13447dd7cddfSDavid du Colombier hex2int(int x) 13457dd7cddfSDavid du Colombier { 13467dd7cddfSDavid du Colombier if(x >= '0' && x <= '9') 13477dd7cddfSDavid du Colombier return x - '0'; 13487dd7cddfSDavid du Colombier if(x >= 'A' && x <= 'F') 13497dd7cddfSDavid du Colombier return (x - 'A') + 10; 13507dd7cddfSDavid du Colombier if(x >= 'a' && x <= 'f') 13517dd7cddfSDavid du Colombier return (x - 'a') + 10; 13527dd7cddfSDavid du Colombier return 0; 13537dd7cddfSDavid du Colombier } 13547dd7cddfSDavid du Colombier 13557dd7cddfSDavid du Colombier static char* 13567dd7cddfSDavid du Colombier decquotedline(char *out, char *in, char *e) 13577dd7cddfSDavid du Colombier { 13587dd7cddfSDavid du Colombier int c, soft; 13597dd7cddfSDavid du Colombier 13607dd7cddfSDavid du Colombier /* dump trailing white space */ 13617dd7cddfSDavid du Colombier while(e >= in && (*e == ' ' || *e == '\t' || *e == '\r' || *e == '\n')) 13627dd7cddfSDavid du Colombier e--; 13637dd7cddfSDavid du Colombier 13647dd7cddfSDavid du Colombier /* trailing '=' means no newline */ 13657dd7cddfSDavid du Colombier if(*e == '='){ 13667dd7cddfSDavid du Colombier soft = 1; 13677dd7cddfSDavid du Colombier e--; 13687dd7cddfSDavid du Colombier } else 13697dd7cddfSDavid du Colombier soft = 0; 13707dd7cddfSDavid du Colombier 13717dd7cddfSDavid du Colombier while(in <= e){ 13727dd7cddfSDavid du Colombier c = (*in++) & 0xff; 13737dd7cddfSDavid du Colombier switch(tableqp[c]){ 13747dd7cddfSDavid du Colombier case Self: 13757dd7cddfSDavid du Colombier *out++ = c; 13767dd7cddfSDavid du Colombier break; 13777dd7cddfSDavid du Colombier case Hex: 13787dd7cddfSDavid du Colombier c = hex2int(*in++)<<4; 13797dd7cddfSDavid du Colombier c |= hex2int(*in++); 13807dd7cddfSDavid du Colombier *out++ = c; 13817dd7cddfSDavid du Colombier break; 13827dd7cddfSDavid du Colombier } 13837dd7cddfSDavid du Colombier } 13847dd7cddfSDavid du Colombier if(!soft) 13857dd7cddfSDavid du Colombier *out++ = '\n'; 13867dd7cddfSDavid du Colombier *out = 0; 13877dd7cddfSDavid du Colombier 13887dd7cddfSDavid du Colombier return out; 13897dd7cddfSDavid du Colombier } 13907dd7cddfSDavid du Colombier 13917dd7cddfSDavid du Colombier int 13927dd7cddfSDavid du Colombier decquoted(char *out, char *in, char *e) 13937dd7cddfSDavid du Colombier { 13947dd7cddfSDavid du Colombier char *p, *nl; 13957dd7cddfSDavid du Colombier 13967dd7cddfSDavid du Colombier if(tableqp[' '] == 0) 13977dd7cddfSDavid du Colombier initquoted(); 13987dd7cddfSDavid du Colombier 13997dd7cddfSDavid du Colombier p = out; 14007dd7cddfSDavid du Colombier while((nl = strchr(in, '\n')) != nil && nl < e){ 14017dd7cddfSDavid du Colombier p = decquotedline(p, in, nl); 14027dd7cddfSDavid du Colombier in = nl + 1; 14037dd7cddfSDavid du Colombier } 14047dd7cddfSDavid du Colombier if(in < e) 14057dd7cddfSDavid du Colombier p = decquotedline(p, in, e-1); 14067dd7cddfSDavid du Colombier 14077dd7cddfSDavid du Colombier // make sure we end with a new line 14087dd7cddfSDavid du Colombier if(*(p-1) != '\n'){ 14097dd7cddfSDavid du Colombier *p++ = '\n'; 14107dd7cddfSDavid du Colombier *p = 0; 14117dd7cddfSDavid du Colombier } 14127dd7cddfSDavid du Colombier 14137dd7cddfSDavid du Colombier return p - out; 14147dd7cddfSDavid du Colombier } 14157dd7cddfSDavid du Colombier 14167dd7cddfSDavid du Colombier static char* 14177dd7cddfSDavid du Colombier lowercase(char *p) 14187dd7cddfSDavid du Colombier { 14197dd7cddfSDavid du Colombier char *op; 14207dd7cddfSDavid du Colombier int c; 14217dd7cddfSDavid du Colombier 14227dd7cddfSDavid du Colombier for(op = p; c = *p; p++) 14237dd7cddfSDavid du Colombier if(isupper(c)) 14247dd7cddfSDavid du Colombier *p = tolower(c); 14257dd7cddfSDavid du Colombier return op; 14267dd7cddfSDavid du Colombier } 14277dd7cddfSDavid du Colombier 14287dd7cddfSDavid du Colombier /* 14297dd7cddfSDavid du Colombier * return number of 8 bit characters 14307dd7cddfSDavid du Colombier */ 14317dd7cddfSDavid du Colombier static int 14327dd7cddfSDavid du Colombier is8bit(Message *m) 14337dd7cddfSDavid du Colombier { 14347dd7cddfSDavid du Colombier int count = 0; 14357dd7cddfSDavid du Colombier char *p; 14367dd7cddfSDavid du Colombier 14377dd7cddfSDavid du Colombier for(p = m->body; p < m->bend; p++) 14387dd7cddfSDavid du Colombier if(*p & 0x80) 14397dd7cddfSDavid du Colombier count++; 14407dd7cddfSDavid du Colombier return count; 14417dd7cddfSDavid du Colombier } 14427dd7cddfSDavid du Colombier 14437dd7cddfSDavid du Colombier // translate latin1 directly since it fits neatly in utf 14447dd7cddfSDavid du Colombier int 14457dd7cddfSDavid du Colombier latin1toutf(char *out, char *in, char *e) 14467dd7cddfSDavid du Colombier { 14477dd7cddfSDavid du Colombier Rune r; 14487dd7cddfSDavid du Colombier char *p; 14497dd7cddfSDavid du Colombier 14507dd7cddfSDavid du Colombier p = out; 14517dd7cddfSDavid du Colombier for(; in < e; in++){ 14527dd7cddfSDavid du Colombier r = (*in) & 0xff; 14537dd7cddfSDavid du Colombier p += runetochar(p, &r); 14547dd7cddfSDavid du Colombier } 14557dd7cddfSDavid du Colombier *p = 0; 14567dd7cddfSDavid du Colombier return p - out; 14577dd7cddfSDavid du Colombier } 14587dd7cddfSDavid du Colombier 14597dd7cddfSDavid du Colombier // translate any thing else using the tcs program 14607dd7cddfSDavid du Colombier int 14617dd7cddfSDavid du Colombier xtoutf(char *charset, char **out, char *in, char *e) 14627dd7cddfSDavid du Colombier { 14637dd7cddfSDavid du Colombier char *av[4]; 14647dd7cddfSDavid du Colombier int totcs[2]; 14657dd7cddfSDavid du Colombier int fromtcs[2]; 14667dd7cddfSDavid du Colombier int n, len, sofar; 14677dd7cddfSDavid du Colombier char *p; 14687dd7cddfSDavid du Colombier 14697dd7cddfSDavid du Colombier len = e-in+1; 14707dd7cddfSDavid du Colombier sofar = 0; 14717dd7cddfSDavid du Colombier *out = p = malloc(len+1); 14727dd7cddfSDavid du Colombier if(p == nil) 14737dd7cddfSDavid du Colombier return 0; 14747dd7cddfSDavid du Colombier 14757dd7cddfSDavid du Colombier av[0] = charset; 14767dd7cddfSDavid du Colombier av[1] = "-f"; 14777dd7cddfSDavid du Colombier av[2] = charset; 14787dd7cddfSDavid du Colombier av[3] = 0; 14797dd7cddfSDavid du Colombier if(pipe(totcs) < 0) 14807dd7cddfSDavid du Colombier return 0; 14817dd7cddfSDavid du Colombier if(pipe(fromtcs) < 0){ 14827dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 14837dd7cddfSDavid du Colombier return 0; 14847dd7cddfSDavid du Colombier } 14857dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 14867dd7cddfSDavid du Colombier case -1: 14877dd7cddfSDavid du Colombier close(fromtcs[0]); close(fromtcs[1]); 14887dd7cddfSDavid du Colombier close(totcs[0]); close(totcs[1]); 14897dd7cddfSDavid du Colombier return 0; 14907dd7cddfSDavid du Colombier case 0: 14917dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 14927dd7cddfSDavid du Colombier dup(fromtcs[1], 1); 14937dd7cddfSDavid du Colombier dup(totcs[0], 0); 14947dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 14957dd7cddfSDavid du Colombier exec("/bin/tcs", av); 14967dd7cddfSDavid du Colombier _exits(0); 14977dd7cddfSDavid du Colombier default: 14987dd7cddfSDavid du Colombier close(fromtcs[1]); close(totcs[0]); 14997dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFFDG|RFNOWAIT)){ 15007dd7cddfSDavid du Colombier case -1: 15017dd7cddfSDavid du Colombier close(fromtcs[0]); close(totcs[1]); 15027dd7cddfSDavid du Colombier return 0; 15037dd7cddfSDavid du Colombier case 0: 15047dd7cddfSDavid du Colombier close(fromtcs[0]); 15057dd7cddfSDavid du Colombier while(in < e){ 15067dd7cddfSDavid du Colombier n = write(totcs[1], in, e-in); 15077dd7cddfSDavid du Colombier if(n <= 0) 15087dd7cddfSDavid du Colombier break; 15097dd7cddfSDavid du Colombier in += n; 15107dd7cddfSDavid du Colombier } 15117dd7cddfSDavid du Colombier close(totcs[1]); 15127dd7cddfSDavid du Colombier _exits(0); 15137dd7cddfSDavid du Colombier default: 15147dd7cddfSDavid du Colombier close(totcs[1]); 15157dd7cddfSDavid du Colombier for(;;){ 15167dd7cddfSDavid du Colombier n = read(fromtcs[0], &p[sofar], len-sofar); 15177dd7cddfSDavid du Colombier if(n <= 0) 15187dd7cddfSDavid du Colombier break; 15197dd7cddfSDavid du Colombier sofar += n; 15207dd7cddfSDavid du Colombier p[sofar] = 0; 15217dd7cddfSDavid du Colombier if(sofar == len){ 15227dd7cddfSDavid du Colombier len += 1024; 15237dd7cddfSDavid du Colombier *out = p = realloc(p, len+1); 15247dd7cddfSDavid du Colombier if(p == nil) 15257dd7cddfSDavid du Colombier return 0; 15267dd7cddfSDavid du Colombier } 15277dd7cddfSDavid du Colombier } 15287dd7cddfSDavid du Colombier close(fromtcs[0]); 15297dd7cddfSDavid du Colombier break; 15307dd7cddfSDavid du Colombier } 15317dd7cddfSDavid du Colombier break; 15327dd7cddfSDavid du Colombier } 15337dd7cddfSDavid du Colombier return sofar; 15347dd7cddfSDavid du Colombier } 15357dd7cddfSDavid du Colombier 15367dd7cddfSDavid du Colombier enum { 15377dd7cddfSDavid du Colombier Winstart= 0x7f, 15387dd7cddfSDavid du Colombier Winend= 0x9f, 15397dd7cddfSDavid du Colombier }; 15407dd7cddfSDavid du Colombier 15417dd7cddfSDavid du Colombier Rune winchars[] = { 15427dd7cddfSDavid du Colombier L'•', 15437dd7cddfSDavid du Colombier L'•', L'•', L'‚', L'ƒ', L'„', L'…', L'†', L'‡', 15447dd7cddfSDavid du Colombier L'ˆ', L'‰', L'Š', L'‹', L'Œ', L'•', L'•', L'•', 15457dd7cddfSDavid du Colombier L'•', L'‘', L'’', L'“', L'”', L'•', L'–', L'—', 15467dd7cddfSDavid du Colombier L'˜', L'™', L'š', L'›', L'œ', L'•', L'•', L'Ÿ', 15477dd7cddfSDavid du Colombier }; 15487dd7cddfSDavid du Colombier 15497dd7cddfSDavid du Colombier int 15507dd7cddfSDavid du Colombier windows1257toutf(char *out, char *in, char *e) 15517dd7cddfSDavid du Colombier { 15527dd7cddfSDavid du Colombier Rune r; 15537dd7cddfSDavid du Colombier char *p; 15547dd7cddfSDavid du Colombier 15557dd7cddfSDavid du Colombier p = out; 15567dd7cddfSDavid du Colombier for(; in < e; in++){ 15577dd7cddfSDavid du Colombier r = (*in) & 0xff; 15587dd7cddfSDavid du Colombier if(r >= 0x7f && r <= 0x9f) 15597dd7cddfSDavid du Colombier r = winchars[r-0x7f]; 15607dd7cddfSDavid du Colombier p += runetochar(p, &r); 15617dd7cddfSDavid du Colombier } 15627dd7cddfSDavid du Colombier *p = 0; 15637dd7cddfSDavid du Colombier return p - out; 15647dd7cddfSDavid du Colombier } 15657dd7cddfSDavid du Colombier 15667dd7cddfSDavid du Colombier void * 15677dd7cddfSDavid du Colombier emalloc(ulong n) 15687dd7cddfSDavid du Colombier { 15697dd7cddfSDavid du Colombier void *p; 15707dd7cddfSDavid du Colombier 15717dd7cddfSDavid du Colombier p = mallocz(n, 1); 15727dd7cddfSDavid du Colombier if(!p){ 15737dd7cddfSDavid du Colombier fprint(2, "%s: out of memory\n", argv0); 15747dd7cddfSDavid du Colombier exits("out of memory"); 15757dd7cddfSDavid du Colombier } 15767dd7cddfSDavid du Colombier return p; 15777dd7cddfSDavid du Colombier } 15787dd7cddfSDavid du Colombier 15797dd7cddfSDavid du Colombier void * 15807dd7cddfSDavid du Colombier erealloc(void *p, ulong n) 15817dd7cddfSDavid du Colombier { 15827dd7cddfSDavid du Colombier p = realloc(p, n); 15837dd7cddfSDavid du Colombier if(!p){ 15847dd7cddfSDavid du Colombier fprint(2, "%s: out of memory\n", argv0); 15857dd7cddfSDavid du Colombier exits("out of memory"); 15867dd7cddfSDavid du Colombier } 15877dd7cddfSDavid du Colombier return p; 15887dd7cddfSDavid du Colombier } 15897dd7cddfSDavid du Colombier 15907dd7cddfSDavid du Colombier void 15917dd7cddfSDavid du Colombier mailplumb(Mailbox *mb, Message *m, int delete) 15927dd7cddfSDavid du Colombier { 15937dd7cddfSDavid du Colombier Plumbmsg p; 15947dd7cddfSDavid du Colombier Plumbattr a[7]; 15957dd7cddfSDavid du Colombier char buf[256]; 15967dd7cddfSDavid du Colombier int ai; 15977dd7cddfSDavid du Colombier char lenstr[10], *from, *subject, *date; 15987dd7cddfSDavid du Colombier static int fd = -1; 15997dd7cddfSDavid du Colombier 16007dd7cddfSDavid du Colombier if(m->subject822 == nil) 16017dd7cddfSDavid du Colombier subject = ""; 16027dd7cddfSDavid du Colombier else 16037dd7cddfSDavid du Colombier subject = s_to_c(m->subject822); 16047dd7cddfSDavid du Colombier 16057dd7cddfSDavid du Colombier if(m->from822 != nil) 16067dd7cddfSDavid du Colombier from = s_to_c(m->from822); 16077dd7cddfSDavid du Colombier else if(m->unixfrom != nil) 16087dd7cddfSDavid du Colombier from = s_to_c(m->unixfrom); 16097dd7cddfSDavid du Colombier else 16107dd7cddfSDavid du Colombier from = ""; 16117dd7cddfSDavid du Colombier 16127dd7cddfSDavid du Colombier if(m->unixdate != nil) 16137dd7cddfSDavid du Colombier date = s_to_c(m->unixdate); 16147dd7cddfSDavid du Colombier else 16157dd7cddfSDavid du Colombier date = ""; 16167dd7cddfSDavid du Colombier 16177dd7cddfSDavid du Colombier sprint(lenstr, "%ld", m->end-m->start); 16187dd7cddfSDavid du Colombier 16197dd7cddfSDavid du Colombier if(biffing && !delete) 16207dd7cddfSDavid du Colombier print("[ %s / %s / %s ]\n", from, subject, lenstr); 16217dd7cddfSDavid du Colombier 16227dd7cddfSDavid du Colombier if(!plumbing) 16237dd7cddfSDavid du Colombier return; 16247dd7cddfSDavid du Colombier 16257dd7cddfSDavid du Colombier if(fd < 0) 16267dd7cddfSDavid du Colombier fd = plumbopen("send", OWRITE); 16277dd7cddfSDavid du Colombier if(fd < 0) 16287dd7cddfSDavid du Colombier return; 16297dd7cddfSDavid du Colombier 16307dd7cddfSDavid du Colombier p.src = "mailfs"; 16317dd7cddfSDavid du Colombier p.dst = "seemail"; 16327dd7cddfSDavid du Colombier p.wdir = "/mail/fs"; 16337dd7cddfSDavid du Colombier p.type = "text"; 16347dd7cddfSDavid du Colombier 16357dd7cddfSDavid du Colombier ai = 0; 16367dd7cddfSDavid du Colombier a[ai].name = "filetype"; 16377dd7cddfSDavid du Colombier a[ai].value = "mail"; 16387dd7cddfSDavid du Colombier 16397dd7cddfSDavid du Colombier a[++ai].name = "sender"; 16407dd7cddfSDavid du Colombier a[ai].value = from; 16417dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 16427dd7cddfSDavid du Colombier 16437dd7cddfSDavid du Colombier a[++ai].name = "length"; 16447dd7cddfSDavid du Colombier a[ai].value = lenstr; 16457dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 16467dd7cddfSDavid du Colombier 16477dd7cddfSDavid du Colombier a[++ai].name = "mailtype"; 16487dd7cddfSDavid du Colombier a[ai].value = delete?"delete":"new"; 16497dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 16507dd7cddfSDavid du Colombier 16517dd7cddfSDavid du Colombier a[++ai].name = "date"; 16527dd7cddfSDavid du Colombier a[ai].value = date; 16537dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 16547dd7cddfSDavid du Colombier 16557dd7cddfSDavid du Colombier a[++ai].name = "digest"; 16567dd7cddfSDavid du Colombier a[ai].value = s_to_c(m->sdigest); 16577dd7cddfSDavid du Colombier a[ai-1].next = &a[ai]; 16587dd7cddfSDavid du Colombier 16597dd7cddfSDavid du Colombier a[ai].next = nil; 16607dd7cddfSDavid du Colombier 16617dd7cddfSDavid du Colombier p.attr = a; 16627dd7cddfSDavid du Colombier snprint(buf, sizeof(buf), "%s/%s/%s", 16637dd7cddfSDavid du Colombier mntpt, mb->name, m->name); 16647dd7cddfSDavid du Colombier p.ndata = strlen(buf); 16657dd7cddfSDavid du Colombier p.data = buf; 16667dd7cddfSDavid du Colombier 16677dd7cddfSDavid du Colombier plumbsend(fd, &p); 16687dd7cddfSDavid du Colombier } 16697dd7cddfSDavid du Colombier 16707dd7cddfSDavid du Colombier // 16717dd7cddfSDavid du Colombier // count the number of lines in the body (for imap4) 16727dd7cddfSDavid du Colombier // 16737dd7cddfSDavid du Colombier void 16747dd7cddfSDavid du Colombier countlines(Message *m) 16757dd7cddfSDavid du Colombier { 16767dd7cddfSDavid du Colombier int i; 16777dd7cddfSDavid du Colombier char *p; 16787dd7cddfSDavid du Colombier 16797dd7cddfSDavid du Colombier i = 0; 16807dd7cddfSDavid du Colombier for(p = strchr(m->rbody, '\n'); p != nil && p < m->rbend; p = strchr(p+1, '\n')) 16817dd7cddfSDavid du Colombier i++; 16827dd7cddfSDavid du Colombier sprint(m->lines, "%d", i); 16837dd7cddfSDavid du Colombier } 1684