|  | #include "a.h" | 
|  |  | 
|  | enum | 
|  | { | 
|  | BoxSubChunk = 16, | 
|  | BoxChunk = 64, | 
|  | MsgChunk = 256, | 
|  | PartChunk = 4, | 
|  | PartSubChunk = 4 | 
|  | }; | 
|  |  | 
|  | Box **boxes; | 
|  | uint nboxes; | 
|  | Box *rootbox; | 
|  | int boxid; | 
|  |  | 
|  | Box* | 
|  | boxbyname(char *name) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* LATER: replace with hash table */ | 
|  | for(i=0; i<nboxes; i++) | 
|  | if(boxes[i] && strcmp(boxes[i]->name, name) == 0) | 
|  | return boxes[i]; | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | Box* | 
|  | subbox(Box *b, char *elem) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for(i=0; i<b->nsub; i++) | 
|  | if(b->sub[i] && strcmp(b->sub[i]->elem, elem) == 0) | 
|  | return b->sub[i]; | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | Box* | 
|  | boxbyid(uint id) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* LATER: replace with binary search */ | 
|  | for(i=0; i<nboxes; i++) | 
|  | if(boxes[i] && boxes[i]->id == id) | 
|  | return boxes[i]; | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | Box* | 
|  | boxcreate(char *name) | 
|  | { | 
|  | char *p; | 
|  | Box *b, *bb; | 
|  |  | 
|  | if((b = boxbyname(name)) != nil) | 
|  | return b; | 
|  |  | 
|  | b = emalloc(sizeof *b); | 
|  | b->id = ++boxid; | 
|  | b->time = time(0); | 
|  | b->name = estrdup(name); | 
|  | b->uidnext = 1; | 
|  | p = strrchr(b->name, '/'); | 
|  | if(p){ | 
|  | *p = 0; | 
|  | bb = boxcreate(b->name); | 
|  | *p = '/'; | 
|  | b->elem = p+1; | 
|  | }else{ | 
|  | bb = rootbox; | 
|  | b->elem = b->name; | 
|  | } | 
|  | if(nboxes%BoxChunk == 0) | 
|  | boxes = erealloc(boxes, (nboxes+BoxChunk)*sizeof boxes[0]); | 
|  | boxes[nboxes++] = b; | 
|  | if(bb->nsub%BoxSubChunk == 0) | 
|  | bb->sub = erealloc(bb->sub, (bb->nsub+BoxSubChunk)*sizeof bb->sub[0]); | 
|  | bb->sub[bb->nsub++] = b; | 
|  | b->parent = bb; | 
|  | return b; | 
|  | } | 
|  |  | 
|  | void | 
|  | boxfree(Box *b) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if(b == nil) | 
|  | return; | 
|  | for(i=0; i<b->nmsg; i++) | 
|  | msgfree(b->msg[i]); | 
|  | free(b->msg); | 
|  | free(b); | 
|  | } | 
|  |  | 
|  | Part* | 
|  | partcreate(Msg *m, Part *pp) | 
|  | { | 
|  | Part *p; | 
|  |  | 
|  | if(m->npart%PartChunk == 0) | 
|  | m->part = erealloc(m->part, (m->npart+PartChunk)*sizeof m->part[0]); | 
|  | p = emalloc(sizeof *p); | 
|  | p->msg = m; | 
|  | p->ix = m->npart; | 
|  | m->part[m->npart++] = p; | 
|  | if(pp){ | 
|  | if(pp->nsub%PartSubChunk == 0) | 
|  | pp->sub = erealloc(pp->sub, (pp->nsub+PartSubChunk)*sizeof pp->sub[0]); | 
|  | p->pix = pp->nsub; | 
|  | p->parent = pp; | 
|  | pp->sub[pp->nsub++] = p; | 
|  | } | 
|  | return p; | 
|  | } | 
|  |  | 
|  | void | 
|  | partfree(Part *p) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if(p == nil) | 
|  | return; | 
|  | for(i=0; i<p->nsub; i++) | 
|  | partfree(p->sub[i]); | 
|  | free(p->sub); | 
|  | hdrfree(p->hdr); | 
|  | free(p->type); | 
|  | free(p->idstr); | 
|  | free(p->desc); | 
|  | free(p->encoding); | 
|  | free(p->charset); | 
|  | free(p->raw); | 
|  | free(p->rawheader); | 
|  | free(p->rawbody); | 
|  | free(p->mimeheader); | 
|  | free(p->body); | 
|  | free(p); | 
|  | } | 
|  |  | 
|  | void | 
|  | msgfree(Msg *m) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if(m == nil) | 
|  | return; | 
|  | for(i=0; i<m->npart; i++) | 
|  | free(m->part[i]); | 
|  | free(m->part); | 
|  | free(m); | 
|  | } | 
|  |  | 
|  | void | 
|  | msgplumb(Msg *m, int delete) | 
|  | { | 
|  | static int fd = -1; | 
|  | Plumbmsg p; | 
|  | Plumbattr a[10]; | 
|  | char buf[256], date[40]; | 
|  | int ai; | 
|  |  | 
|  | if(m == nil || m->npart < 1 || m->part[0]->hdr == nil) | 
|  | return; | 
|  | if(m->box && strcmp(m->box->name, "mbox") != 0) | 
|  | return; | 
|  |  | 
|  | p.src = "mailfs"; | 
|  | p.dst = "seemail"; | 
|  | p.wdir = "/"; | 
|  | p.type = "text"; | 
|  |  | 
|  | ai = 0; | 
|  | a[ai].name = "filetype"; | 
|  | a[ai].value = "mail"; | 
|  |  | 
|  | a[++ai].name = "mailtype"; | 
|  | a[ai].value = delete?"delete":"new"; | 
|  | a[ai-1].next = &a[ai]; | 
|  |  | 
|  | if(m->part[0]->hdr->from){ | 
|  | a[++ai].name = "sender"; | 
|  | a[ai].value = m->part[0]->hdr->from; | 
|  | a[ai-1].next = &a[ai]; | 
|  | } | 
|  |  | 
|  | if(m->part[0]->hdr->subject){ | 
|  | a[++ai].name = "subject"; | 
|  | a[ai].value = m->part[0]->hdr->subject; | 
|  | a[ai-1].next = &a[ai]; | 
|  | } | 
|  |  | 
|  | if(m->part[0]->hdr->digest){ | 
|  | a[++ai].name = "digest"; | 
|  | a[ai].value = m->part[0]->hdr->digest; | 
|  | a[ai-1].next = &a[ai]; | 
|  | } | 
|  |  | 
|  | strcpy(date, ctime(m->date)); | 
|  | date[strlen(date)-1] = 0;	/* newline */ | 
|  | a[++ai].name = "date"; | 
|  | a[ai].value = date; | 
|  | a[ai-1].next = &a[ai]; | 
|  |  | 
|  | a[ai].next = nil; | 
|  |  | 
|  | p.attr = a; | 
|  | #ifdef PLAN9PORT | 
|  | snprint(buf, sizeof buf, "Mail/%s/%ud", m->box->name, m->id); | 
|  | #else | 
|  | snprint(buf, sizeof buf, "/mail/fs/%s/%ud", m->box->name, m->id); | 
|  | #endif | 
|  | p.ndata = strlen(buf); | 
|  | p.data = buf; | 
|  |  | 
|  | if(fd < 0) | 
|  | fd = plumbopen("send", OWRITE); | 
|  | if(fd < 0) | 
|  | return; | 
|  |  | 
|  | plumbsend(fd, &p); | 
|  | } | 
|  |  | 
|  |  | 
|  | Msg* | 
|  | msgcreate(Box *box) | 
|  | { | 
|  | Msg *m; | 
|  |  | 
|  | m = emalloc(sizeof *m); | 
|  | m->box = box; | 
|  | partcreate(m, nil); | 
|  | m->part[0]->type = estrdup("message/rfc822"); | 
|  | if(box->nmsg%MsgChunk == 0) | 
|  | box->msg = erealloc(box->msg, (box->nmsg+MsgChunk)*sizeof box->msg[0]); | 
|  | m->ix = box->nmsg++; | 
|  | box->msg[m->ix] = m; | 
|  | m->id = ++box->msgid; | 
|  | return m; | 
|  | } | 
|  |  | 
|  | Msg* | 
|  | msgbyimapuid(Box *box, uint uid, int docreate) | 
|  | { | 
|  | int i; | 
|  | Msg *msg; | 
|  |  | 
|  | if(box == nil) | 
|  | return nil; | 
|  | /* LATER: binary search or something */ | 
|  | for(i=0; i<box->nmsg; i++) | 
|  | if(box->msg[i]->imapuid == uid) | 
|  | return box->msg[i]; | 
|  | if(!docreate) | 
|  | return nil; | 
|  | msg = msgcreate(box); | 
|  | msg->imapuid = uid; | 
|  | return msg; | 
|  | } | 
|  |  | 
|  | Msg* | 
|  | msgbyid(Box *box, uint id) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if(box == nil) | 
|  | return nil; | 
|  | /* LATER: binary search or something */ | 
|  | for(i=0; i<box->nmsg; i++) | 
|  | if(box->msg[i]->id == id) | 
|  | return box->msg[i]; | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | Part* | 
|  | partbyid(Msg *m, uint id) | 
|  | { | 
|  | if(m == nil) | 
|  | return nil; | 
|  | if(id >= m->npart) | 
|  | return nil; | 
|  | return m->part[id]; | 
|  | } | 
|  |  | 
|  | Part* | 
|  | subpart(Part *p, uint a) | 
|  | { | 
|  | if(p == nil || a >= p->nsub) | 
|  | return nil; | 
|  | return p->sub[a]; | 
|  | } | 
|  |  | 
|  | void | 
|  | hdrfree(Hdr *h) | 
|  | { | 
|  | if(h == nil) | 
|  | return; | 
|  | free(h->date); | 
|  | free(h->subject); | 
|  | free(h->from); | 
|  | free(h->sender); | 
|  | free(h->replyto); | 
|  | free(h->to); | 
|  | free(h->cc); | 
|  | free(h->bcc); | 
|  | free(h->inreplyto); | 
|  | free(h->messageid); | 
|  | free(h->digest); | 
|  | free(h); | 
|  | } | 
|  |  | 
|  | void | 
|  | boxinit(void) | 
|  | { | 
|  | rootbox = emalloc(sizeof *rootbox); | 
|  | rootbox->name = estrdup(""); | 
|  | rootbox->time = time(0); | 
|  | } | 
|  |  |