11 typedef struct Inbuf Inbuf;
18 uchar data[Buffersize+7];
22 addtomessage(Message *m, uchar *p, int n, int done)
26 /* add to message (+ 1 in malloc is for a trailing null) */
27 if(m->lim - m->end < n){
34 m->start = erealloc(m->start, len + 1);
35 m->end = m->start + i;
41 m->start = emalloc(len + 1);
44 m->lim = m->start + len;
47 memmove(m->end, p, n);
52 /* read in a single message */
55 readmessage(Message *m, Inbuf *inb)
59 char sdigest[SHA1dlen*2+1];
62 for(done = 0; !done;){
63 n = inb->wptr - inb->rptr;
66 memmove(inb->data, inb->rptr, n);
67 inb->rptr = inb->data;
68 inb->wptr = inb->rptr + n;
69 i = read(inb->fd, inb->wptr, Buffersize);
71 /* if(fd2path(inb->fd, tmp, sizeof tmp) < 0)
72 strcpy(tmp, "unknown mailbox"); jpc */
73 fprint(2, "error reading '%s': %r\n", tmp);
78 addtomessage(m, inb->rptr, n, 1);
79 if(m->end == m->start)
86 /* look for end of message */
87 for(p = inb->rptr; p < inb->wptr; p = np+1){
88 /* first part of search for '\nFrom ' */
89 np = memchr(p, '\n', inb->wptr - p);
96 * if we've found a \n but there's
97 * not enough room for '\nFrom ', don't do
98 * the comparison till we've read in more.
100 if(inb->wptr - np < 6){
105 if(strncmp((char*)np, "\nFrom ", 6) == 0){
112 /* add to message (+ 1 in malloc is for a trailing null) */
114 addtomessage(m, inb->rptr, n, done);
118 /* if it doesn't start with a 'From ', this ain't a mailbox */
119 if(strncmp(m->start, "From ", 5) != 0)
122 /* dump trailing newline, make sure there's a trailing null */
123 /* (helps in body searches) */
124 if(*(m->end-1) == '\n')
127 m->bend = m->rbend = m->end;
130 sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
131 for(i = 0; i < SHA1dlen; i++)
132 sprint(sdigest+2*i, "%2.2ux", m->digest[i]);
133 m->sdigest = s_copy(sdigest);
139 /* throw out deleted messages. return number of freshly deleted messages */
141 purgedeleted(Mailbox *mb)
146 /* forget about what's no longer in the mailbox */
148 for(m = mb->root->part; m != nil; m = next){
150 if(m->deleted && m->refs == 0){
160 /* read in the mailbox and parse into messages. */
163 _readmbox(Mailbox *mb, int doplumb, Mlock *lk)
168 static char err[128];
176 * open the mailbox. If it doesn't exist, try the temporary one.
179 fd = open(mb->path, OREAD);
181 errstr(err, sizeof(err));
182 if(strstr(err, "exist") != 0){
183 tmp = s_copy(mb->path);
184 s_append(tmp, ".tmp");
185 if(sysrename(s_to_c(tmp), mb->path) == 0){
195 * a new qid.path means reread the mailbox, while
196 * a new qid.vers means read any new messages
201 errstr(err, sizeof(err));
205 if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){
210 if(d->qid.path == mb->d->qid.path){
213 seek(fd, mb->d->length, 0);
219 henter(PATH(0, Qtop), mb->name,
220 (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
222 inb = emalloc(sizeof(Inbuf));
223 inb->rptr = inb->wptr = inb->data;
226 /* read new messages */
227 snprint(err, sizeof err, "reading '%s'", mb->path);
232 m = newmessage(mb->root);
235 if(readmessage(m, inb) < 0){
241 /* merge mailbox versions */
243 if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){
244 /* matches mail we already read, discard */
245 logmsg("duplicate", *l);
252 /* old mail no longer in box, mark deleted */
253 logmsg("disappeared", *l);
255 mailplumb(mb, *l, 1);
264 x = strchr(m->start, '\n');
269 m->mheader = m->mhend = m->header;
281 logmsg("mbox read", nil);
283 /* whatever is left has been removed from the mbox, mark deleted */
286 mailplumb(mb, *l, 1);
298 _writembox(Mailbox *mb, Mlock *lk)
306 tmp = s_copy(mb->path);
307 s_append(tmp, ".tmp");
310 * preserve old files permissions, if possible
312 d = dirstat(mb->path);
319 sysremove(s_to_c(tmp));
320 b = sysopen(s_to_c(tmp), "alc", mode);
322 fprint(2, "can't write temporary mailbox %s: %r\n", s_to_c(tmp));
326 logmsg("writing new mbox", nil);
328 for(m = mb->root->part; m != nil; m = m->next){
333 logmsg("writing", m);
334 if(Bwrite(b, m->start, m->end - m->start) < 0)
336 if(Bwrite(b, "\n", 1) < 0)
339 logmsg("wrote new mbox", nil);
345 fprint(2, "error writing temporary mail file\n");
351 if(sysrename(s_to_c(tmp), mb->path) < 0)
352 fprint(2, "%s: can't rename %s to %s: %r\n", argv0,
353 s_to_c(tmp), mb->path);
357 mb->d = dirstat(mb->path);
361 plan9syncmbox(Mailbox *mb, int doplumb)
368 lk = syslock(mb->path);
370 return "can't lock mailbox";
373 rv = _readmbox(mb, doplumb, lk); /* interpolate */
374 if(purgedeleted(mb) > 0)
384 /* look to see if we can open this mail box */
387 plan9mbox(Mailbox *mb, char *path)
392 if(access(path, AEXIST) < 0){
393 errstr(err, sizeof(err));
395 s_append(tmp, ".tmp");
396 if(access(s_to_c(tmp), AEXIST) < 0){
403 mb->sync = plan9syncmbox;