collect.c: fix compiler warnings..
[s-mailx.git] / maildir.c
blob4384177d06b8e1fffe5a56f9851b60bc09a0dc8b
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 */
6 /*
7 * Copyright (c) 2004
8 * Gunnar Ritter. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Gunnar Ritter
21 * and his contributors.
22 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #ifndef lint
40 #ifdef DOSCCS
41 static char sccsid[] = "@(#)maildir.c 1.20 (gritter) 12/28/06";
42 #endif
43 #endif /* not lint */
45 #include "config.h"
47 #include "rcv.h"
48 #include "extern.h"
49 #include <time.h>
50 #include <dirent.h>
51 #include <unistd.h>
52 #include <sys/stat.h>
53 #include <errno.h>
56 * Mail -- a mail program
58 * Maildir folder support.
61 static struct mditem {
62 struct message *md_data;
63 unsigned md_hash;
64 } *mdtable;
65 static long mdprime;
67 static sigjmp_buf maildirjmp;
69 static int maildir_setfile1(const char *name, int newmail, int omsgCount);
70 static int mdcmp(const void *a, const void *b);
71 static int subdir(const char *name, const char *sub, int newmail);
72 static void cleantmp(const char *name);
73 static void append(const char *name, const char *sub, const char *fn);
74 static void readin(const char *name, struct message *m);
75 static void maildir_update(void);
76 static void move(struct message *m);
77 static char *mkname(time_t t, enum mflag f, const char *pref);
78 static void maildircatch(int s);
79 static enum okay maildir_append1(const char *name, FILE *fp, off_t off1,
80 long size, enum mflag flag);
81 static enum okay trycreate(const char *name);
82 static enum okay mkmaildir(const char *name);
83 static struct message *mdlook(const char *name, struct message *data);
84 static void mktable(void);
85 static enum okay subdir_remove(const char *name, const char *sub);
87 int
88 maildir_setfile(const char *name, int newmail, int isedit)
90 sighandler_type saveint;
91 struct cw cw;
92 int i = -1, omsgCount;
94 (void)&saveint;
95 (void)&i;
96 omsgCount = msgCount;
97 if (cwget(&cw) == STOP) {
98 fprintf(stderr, "Fatal: Cannot open current directory\n");
99 return -1;
101 if (!newmail)
102 quit();
103 saveint = safe_signal(SIGINT, SIG_IGN);
104 if (chdir(name) < 0) {
105 fprintf(stderr, "Cannot change directory to \"%s\".\n", name);
106 cwrelse(&cw);
107 return -1;
109 if (!newmail) {
110 edit = isedit;
111 if (mb.mb_itf) {
112 fclose(mb.mb_itf);
113 mb.mb_itf = NULL;
115 if (mb.mb_otf) {
116 fclose(mb.mb_otf);
117 mb.mb_otf = NULL;
119 initbox(name);
120 mb.mb_type = MB_MAILDIR;
122 mdtable = NULL;
123 if (sigsetjmp(maildirjmp, 1) == 0) {
124 if (newmail)
125 mktable();
126 if (saveint != SIG_IGN)
127 safe_signal(SIGINT, maildircatch);
128 i = maildir_setfile1(name, newmail, omsgCount);
130 if (newmail)
131 free(mdtable);
132 safe_signal(SIGINT, saveint);
133 if (i < 0) {
134 mb.mb_type = MB_VOID;
135 *mailname = '\0';
136 msgCount = 0;
138 if (cwret(&cw) == STOP) {
139 fputs("Fatal: Cannot change back to current directory.\n",
140 stderr);
141 abort();
143 cwrelse(&cw);
144 setmsize(msgCount);
145 if (newmail && mb.mb_sorted && msgCount > omsgCount) {
146 mb.mb_threaded = 0;
147 sort((void *)-1);
149 if (!newmail)
150 sawcom = 0;
151 if (!newmail && !edit && msgCount == 0) {
152 if (mb.mb_type == MB_MAILDIR && value("emptystart") == NULL)
153 fprintf(stderr, "No mail at %s\n", name);
154 return 1;
156 if (newmail && msgCount > omsgCount)
157 newmailinfo(omsgCount);
158 return 0;
161 static int
162 maildir_setfile1(const char *name, int newmail, int omsgCount)
164 int i;
166 if (!newmail)
167 cleantmp(name);
168 mb.mb_perm = Rflag ? 0 : MB_DELE;
169 if ((i = subdir(name, "cur", newmail)) != 0)
170 return i;
171 if ((i = subdir(name, "new", newmail)) != 0)
172 return i;
173 append(name, NULL, NULL);
174 for (i = newmail?omsgCount:0; i < msgCount; i++)
175 readin(name, &message[i]);
176 if (newmail) {
177 if (msgCount > omsgCount)
178 qsort(&message[omsgCount],
179 msgCount - omsgCount,
180 sizeof *message, mdcmp);
181 } else {
182 if (msgCount)
183 qsort(message, msgCount, sizeof *message, mdcmp);
185 return msgCount;
189 * In combination with the names from mkname(), this comparison function
190 * ensures that the order of messages in a maildir folder created by mailx
191 * remains always the same. In effect, if a mbox folder is transferred to
192 * a maildir folder by 'copy *', the order of the messages in mailx will
193 * not change.
195 static int
196 mdcmp(const void *a, const void *b)
198 long i;
200 if ((i = ((struct message *)a)->m_time -
201 ((struct message *)b)->m_time) == 0)
202 i = strcmp(&((struct message *)a)->m_maildir_file[4],
203 &((struct message *)b)->m_maildir_file[4]);
204 return i;
207 static int
208 subdir(const char *name, const char *sub, int newmail)
210 DIR *dirfd;
211 struct dirent *dp;
213 if ((dirfd = opendir(sub)) == NULL) {
214 fprintf(stderr, "Cannot open directory \"%s/%s\".\n",
215 name, sub);
216 return -1;
218 if (access(sub, W_OK) < 0)
219 mb.mb_perm = 0;
220 while ((dp = readdir(dirfd)) != NULL) {
221 if (dp->d_name[0] == '.' &&
222 (dp->d_name[1] == '\0' ||
223 (dp->d_name[1] == '.' &&
224 dp->d_name[2] == '\0')))
225 continue;
226 if (dp->d_name[0] == '.')
227 continue;
228 if (!newmail || mdlook(dp->d_name, NULL) == NULL)
229 append(name, sub, dp->d_name);
231 closedir(dirfd);
232 return 0;
235 static void
236 cleantmp(const char *name)
238 struct stat st;
239 DIR *dirfd;
240 struct dirent *dp;
241 char *fn = NULL;
242 size_t fnsz = 0, ssz;
243 time_t now;
245 if ((dirfd = opendir("tmp")) == NULL)
246 return;
247 time(&now);
248 while ((dp = readdir(dirfd)) != NULL) {
249 if (dp->d_name[0] == '.' &&
250 (dp->d_name[1] == '\0' ||
251 (dp->d_name[1] == '.' &&
252 dp->d_name[2] == '\0')))
253 continue;
254 if (dp->d_name[0] == '.')
255 continue;
256 if ((ssz = strlen(dp->d_name)) + 5 > fnsz) {
257 free(fn);
258 fn = smalloc(fnsz = ssz + 40);
260 strcpy(fn, "tmp/");
261 strcpy(&fn[4], dp->d_name);
262 if (stat(fn, &st) < 0)
263 continue;
264 if (st.st_atime + 36*3600 < now)
265 unlink(fn);
267 free(fn);
268 closedir(dirfd);
271 static void
272 append(const char *name, const char *sub, const char *fn)
274 struct message *m;
275 size_t sz;
276 time_t t = 0;
277 enum mflag f = MUSED|MNOFROM|MNEWEST;
278 const char *cp;
279 char *xp;
281 if (fn && sub) {
282 if (strcmp(sub, "new") == 0)
283 f |= MNEW;
284 t = strtol(fn, &xp, 10);
285 if ((cp = strrchr(xp, ',')) != NULL &&
286 cp > &xp[2] && cp[-1] == '2' && cp[-2] == ':') {
287 while (*++cp) {
288 switch (*cp) {
289 case 'F':
290 f |= MFLAGGED;
291 break;
292 case 'R':
293 f |= MANSWERED;
294 break;
295 case 'S':
296 f |= MREAD;
297 break;
298 case 'T':
299 f |= MDELETED;
300 break;
301 case 'D':
302 f |= MDRAFT;
303 break;
308 if (msgCount + 1 >= msgspace) {
309 const int chunk = 64;
310 message = srealloc(message,
311 (msgspace += chunk) * sizeof *message);
312 memset(&message[msgCount], 0, chunk * sizeof *message);
314 if (fn == NULL || sub == NULL)
315 return;
316 m = &message[msgCount++];
317 m->m_maildir_file = smalloc((sz = strlen(sub)) + strlen(fn) + 2);
318 strcpy(m->m_maildir_file, sub);
319 m->m_maildir_file[sz] = '/';
320 strcpy(&m->m_maildir_file[sz+1], fn);
321 m->m_time = t;
322 m->m_flag = f;
323 m->m_maildir_hash = ~pjw(fn);
324 return;
327 static void
328 readin(const char *name, struct message *m)
330 char *buf, *bp;
331 size_t bufsize, buflen, count;
332 long size = 0, lines = 0;
333 off_t offset;
334 FILE *fp;
335 int emptyline = 0;
337 if ((fp = Fopen(m->m_maildir_file, "r")) == NULL) {
338 fprintf(stderr, "Cannot read \"%s/%s\" for message %d\n",
339 name, m->m_maildir_file,
340 (int)(m - &message[0] + 1));
341 m->m_flag |= MHIDDEN;
342 return;
344 buf = smalloc(bufsize = LINESIZE);
345 buflen = 0;
346 count = fsize(fp);
347 fseek(mb.mb_otf, 0L, SEEK_END);
348 offset = ftell(mb.mb_otf);
349 while (fgetline(&buf, &bufsize, &count, &buflen, fp, 1) != NULL) {
350 bp = buf;
351 if (buf[0] == 'F' && buf[1] == 'r' && buf[2] == 'o' &&
352 buf[3] == 'm' && buf[4] == ' ') {
353 putc('>', mb.mb_otf);
354 size++;
356 lines++;
357 size += fwrite(bp, 1, buflen, mb.mb_otf);
358 emptyline = *bp == '\n';
360 if (!emptyline) {
361 putc('\n', mb.mb_otf);
362 lines++;
363 size++;
365 Fclose(fp);
366 fflush(mb.mb_otf);
367 m->m_size = m->m_xsize = size;
368 m->m_lines = m->m_xlines = lines;
369 m->m_block = mailx_blockof(offset);
370 m->m_offset = mailx_offsetof(offset);
371 free(buf);
372 substdate(m);
375 void
376 maildir_quit(void)
378 sighandler_type saveint;
379 struct cw cw;
381 (void)&saveint;
382 if (cwget(&cw) == STOP) {
383 fprintf(stderr, "Fatal: Cannot open current directory\n");
384 return;
386 saveint = safe_signal(SIGINT, SIG_IGN);
387 if (chdir(mailname) < 0) {
388 fprintf(stderr, "Cannot change directory to \"%s\".\n",
389 mailname);
390 cwrelse(&cw);
391 return;
393 if (sigsetjmp(maildirjmp, 1) == 0) {
394 if (saveint != SIG_IGN)
395 safe_signal(SIGINT, maildircatch);
396 maildir_update();
398 safe_signal(SIGINT, saveint);
399 if (cwret(&cw) == STOP) {
400 fputs("Fatal: Cannot change back to current directory.\n",
401 stderr);
402 abort();
404 cwrelse(&cw);
407 static void
408 maildir_update(void)
410 FILE *readstat = NULL;
411 struct message *m;
412 int dodel, c, gotcha = 0, held = 0, modflags = 0;
414 if (mb.mb_perm == 0)
415 goto free;
416 if (Tflag != NULL) {
417 if ((readstat = Zopen(Tflag, "w", NULL)) == NULL)
418 Tflag = NULL;
420 if (!edit) {
421 holdbits();
422 for (m = &message[0], c = 0; m < &message[msgCount]; m++) {
423 if (m->m_flag & MBOX)
424 c++;
426 if (c > 0)
427 if (makembox() == STOP)
428 goto bypass;
430 for (m = &message[0], gotcha=0, held=0; m < &message[msgCount]; m++) {
431 if (readstat != NULL && (m->m_flag & (MREAD|MDELETED)) != 0) {
432 char *id;
433 if ((id = hfield("message-id", m)) != NULL ||
434 (id = hfield("article-id", m)) != NULL)
435 fprintf(readstat, "%s\n", id);
437 if (edit)
438 dodel = m->m_flag & MDELETED;
439 else
440 dodel = !((m->m_flag&MPRESERVE) ||
441 (m->m_flag&MTOUCH) == 0);
442 if (dodel) {
443 if (unlink(m->m_maildir_file) < 0)
444 fprintf(stderr, "Cannot delete file \"%s/%s\" "
445 "for message %d.\n",
446 mailname, m->m_maildir_file,
447 (int)(m - &message[0] + 1));
448 else
449 gotcha++;
450 } else {
451 if ((m->m_flag&(MREAD|MSTATUS)) == (MREAD|MSTATUS) ||
452 m->m_flag & (MNEW|MBOXED|MSAVED|MSTATUS|
453 MFLAG|MUNFLAG|
454 MANSWER|MUNANSWER|
455 MDRAFT|MUNDRAFT)) {
456 move(m);
457 modflags++;
459 held++;
462 bypass: if (readstat != NULL)
463 Fclose(readstat);
464 if ((gotcha || modflags) && edit) {
465 printf(catgets(catd, CATSET, 168, "\"%s\" "), mailname);
466 printf(value("bsdcompat") || value("bsdmsgs") ?
467 catgets(catd, CATSET, 170, "complete\n") :
468 catgets(catd, CATSET, 212, "updated.\n"));
469 } else if (held && !edit && mb.mb_perm != 0) {
470 if (held == 1)
471 printf(catgets(catd, CATSET, 155,
472 "Held 1 message in %s\n"), mailname);
473 else if (held > 1)
474 printf(catgets(catd, CATSET, 156,
475 "Held %d messages in %s\n"), held, mailname);
477 fflush(stdout);
478 free: for (m = &message[0]; m < &message[msgCount]; m++)
479 free(m->m_maildir_file);
482 static void
483 move(struct message *m)
485 char *fn, *new;
487 fn = mkname(0, m->m_flag, &m->m_maildir_file[4]);
488 new = savecat("cur/", fn);
489 if (strcmp(m->m_maildir_file, new) == 0)
490 return;
491 if (link(m->m_maildir_file, new) < 0) {
492 fprintf(stderr, "Cannot link \"%s/%s\" to \"%s/%s\": "
493 "message %d not touched.\n",
494 mailname, m->m_maildir_file,
495 mailname, new,
496 (int)(m - &message[0] + 1));
497 return;
499 if (unlink(m->m_maildir_file) < 0)
500 fprintf(stderr, "Cannot unlink \"%s/%s\".\n",
501 mailname, m->m_maildir_file);
504 static char *
505 mkname(time_t t, enum mflag f, const char *pref)
507 static unsigned long count;
508 static pid_t mypid;
509 char *cp;
510 static char *node;
511 int size, n, i;
513 if (pref == NULL) {
514 if (mypid == 0)
515 mypid = getpid();
516 if (node == NULL) {
517 cp = nodename(0);
518 n = size = 0;
519 do {
520 if (n < size + 8)
521 node = srealloc(node, size += 20);
522 switch (*cp) {
523 case '/':
524 node[n++] = '\\', node[n++] = '0',
525 node[n++] = '5', node[n++] = '7';
526 break;
527 case ':':
528 node[n++] = '\\', node[n++] = '0',
529 node[n++] = '7', node[n++] = '2';
530 break;
531 default:
532 node[n++] = *cp;
534 } while (*cp++);
536 size = 60 + strlen(node);
537 cp = salloc(size);
538 n = snprintf(cp, size, "%lu.%06lu_%06lu.%s:2,",
539 (unsigned long)t,
540 (unsigned long)mypid, ++count, node);
541 } else {
542 size = (n = strlen(pref)) + 13;
543 cp = salloc(size);
544 strcpy(cp, pref);
545 for (i = n; i > 3; i--)
546 if (cp[i-1] == ',' && cp[i-2] == '2' &&
547 cp[i-3] == ':') {
548 n = i;
549 break;
551 if (i <= 3) {
552 strcpy(&cp[n], ":2,");
553 n += 3;
556 if (n < size - 7) {
557 if (f & MDRAFTED)
558 cp[n++] = 'D';
559 if (f & MFLAGGED)
560 cp[n++] = 'F';
561 if (f & MANSWERED)
562 cp[n++] = 'R';
563 if (f & MREAD)
564 cp[n++] = 'S';
565 if (f & MDELETED)
566 cp[n++] = 'T';
567 cp[n] = '\0';
569 return cp;
572 static void
573 maildircatch(int s)
575 siglongjmp(maildirjmp, s);
578 enum okay
579 maildir_append(const char *name, FILE *fp)
581 char *buf, *bp, *lp;
582 size_t bufsize, buflen, count;
583 off_t off1 = -1, offs;
584 int inhead = 1;
585 int flag = MNEW|MNEWEST;
586 long size = 0;
587 enum okay ok;
589 if (mkmaildir(name) != OKAY)
590 return STOP;
591 buf = smalloc(bufsize = LINESIZE);
592 buflen = 0;
593 count = fsize(fp);
594 offs = ftell(fp);
595 do {
596 bp = fgetline(&buf, &bufsize, &count, &buflen, fp, 1);
597 if (bp == NULL || strncmp(buf, "From ", 5) == 0) {
598 if (off1 != (off_t)-1) {
599 ok = maildir_append1(name, fp, off1,
600 size, flag);
601 if (ok == STOP)
602 return STOP;
603 fseek(fp, offs+buflen, SEEK_SET);
605 off1 = offs + buflen;
606 size = 0;
607 inhead = 1;
608 flag = MNEW;
609 } else
610 size += buflen;
611 offs += buflen;
612 if (bp && buf[0] == '\n')
613 inhead = 0;
614 else if (bp && inhead && ascncasecmp(buf, "status", 6) == 0) {
615 lp = &buf[6];
616 while (whitechar(*lp&0377))
617 lp++;
618 if (*lp == ':')
619 while (*++lp != '\0')
620 switch (*lp) {
621 case 'R':
622 flag |= MREAD;
623 break;
624 case 'O':
625 flag &= ~MNEW;
626 break;
628 } else if (bp && inhead &&
629 ascncasecmp(buf, "x-status", 8) == 0) {
630 lp = &buf[8];
631 while (whitechar(*lp&0377))
632 lp++;
633 if (*lp == ':')
634 while (*++lp != '\0')
635 switch (*lp) {
636 case 'F':
637 flag |= MFLAGGED;
638 break;
639 case 'A':
640 flag |= MANSWERED;
641 break;
642 case 'T':
643 flag |= MDRAFTED;
644 break;
647 } while (bp != NULL);
648 free(buf);
649 return OKAY;
652 static enum okay
653 maildir_append1(const char *name, FILE *fp, off_t off1, long size,
654 enum mflag flag)
656 const int attempts = 43200;
657 struct stat st;
658 char buf[4096];
659 char *fn, *tmp, *new;
660 FILE *op;
661 long n, z;
662 int i;
663 time_t now;
665 for (i = 0; i < attempts; i++) {
666 time(&now);
667 fn = mkname(now, flag, NULL);
668 tmp = salloc(n = strlen(name) + strlen(fn) + 6);
669 snprintf(tmp, n, "%s/tmp/%s", name, fn);
670 if (stat(tmp, &st) < 0 && errno == ENOENT)
671 break;
672 sleep(2);
674 if (i >= attempts) {
675 fprintf(stderr,
676 "Cannot create unique file name in \"%s/tmp\".\n",
677 name);
678 return STOP;
680 if ((op = Fopen(tmp, "w")) == NULL) {
681 fprintf(stderr, "Cannot write to \"%s\".\n", tmp);
682 return STOP;
684 fseek(fp, off1, SEEK_SET);
685 while (size > 0) {
686 z = size > sizeof buf ? sizeof buf : size;
687 if ((n = fread(buf, 1, z, fp)) != z ||
688 fwrite(buf, 1, n, op) != n) {
689 fprintf(stderr, "Error writing to \"%s\".\n", tmp);
690 Fclose(op);
691 unlink(tmp);
692 return STOP;
694 size -= n;
696 Fclose(op);
697 new = salloc(n = strlen(name) + strlen(fn) + 6);
698 snprintf(new, n, "%s/new/%s", name, fn);
699 if (link(tmp, new) < 0) {
700 fprintf(stderr, "Cannot link \"%s\" to \"%s\".\n", tmp, new);
701 return STOP;
703 if (unlink(tmp) < 0)
704 fprintf(stderr, "Cannot unlink \"%s\".\n", tmp);
705 return OKAY;
708 static enum okay
709 trycreate(const char *name)
711 struct stat st;
713 if (stat(name, &st) == 0) {
714 if (!S_ISDIR(st.st_mode)) {
715 fprintf(stderr, "\"%s\" is not a directory.\n", name);
716 return STOP;
718 } else if (makedir(name) != OKAY) {
719 fprintf(stderr, "Cannot create directory \"%s\".\n", name);
720 return STOP;
721 } else
722 imap_created_mailbox++;
723 return OKAY;
726 static enum okay
727 mkmaildir(const char *name)
729 char *np;
730 size_t sz;
731 enum okay ok = STOP;
733 if (trycreate(name) == OKAY) {
734 np = ac_alloc((sz = strlen(name)) + 5);
735 strcpy(np, name);
736 strcpy(&np[sz], "/tmp");
737 if (trycreate(np) == OKAY) {
738 strcpy(&np[sz], "/new");
739 if (trycreate(np) == OKAY) {
740 strcpy(&np[sz], "/cur");
741 if (trycreate(np) == OKAY)
742 ok = OKAY;
745 ac_free(np);
747 return ok;
750 static struct message *
751 mdlook(const char *name, struct message *data)
753 struct mditem *md;
754 unsigned c, h, n = 0;
756 if (data && data->m_maildir_hash)
757 h = ~data->m_maildir_hash;
758 else
759 h = pjw(name);
760 h %= mdprime;
761 md = &mdtable[c = h];
762 while (md->md_data != NULL) {
763 if (strcmp(&md->md_data->m_maildir_file[4], name) == 0)
764 break;
765 c += n&1 ? -((n+1)/2) * ((n+1)/2) : ((n+1)/2) * ((n+1)/2);
766 n++;
767 while (c >= mdprime)
768 c -= mdprime;
769 md = &mdtable[c];
771 if (data != NULL && md->md_data == NULL)
772 md->md_data = data;
773 return md->md_data ? md->md_data : NULL;
776 static void
777 mktable(void)
779 int i;
781 mdprime = nextprime(msgCount);
782 mdtable = scalloc(mdprime, sizeof *mdtable);
783 for (i = 0; i < msgCount; i++)
784 mdlook(&message[i].m_maildir_file[4], &message[i]);
787 static enum okay
788 subdir_remove(const char *name, const char *sub)
790 char *path;
791 int pathsize, pathend, namelen, sublen, n;
792 DIR *dirfd;
793 struct dirent *dp;
795 namelen = strlen(name);
796 sublen = strlen(sub);
797 path = smalloc(pathsize = namelen + sublen + 30);
798 strcpy(path, name);
799 path[namelen] = '/';
800 strcpy(&path[namelen+1], sub);
801 path[namelen+sublen+1] = '/';
802 path[pathend = namelen + sublen + 2] = '\0';
803 if ((dirfd = opendir(path)) == NULL) {
804 perror(path);
805 free(path);
806 return STOP;
808 while ((dp = readdir(dirfd)) != NULL) {
809 if (dp->d_name[0] == '.' &&
810 (dp->d_name[1] == '\0' ||
811 (dp->d_name[1] == '.' &&
812 dp->d_name[2] == '\0')))
813 continue;
814 if (dp->d_name[0] == '.')
815 continue;
816 n = strlen(dp->d_name);
817 if (pathend + n + 1 > pathsize)
818 path = srealloc(path, pathsize = pathend + n + 30);
819 strcpy(&path[pathend], dp->d_name);
820 if (unlink(path) < 0) {
821 perror(path);
822 closedir(dirfd);
823 free(path);
824 return STOP;
827 closedir(dirfd);
828 path[pathend] = '\0';
829 if (rmdir(path) < 0) {
830 perror(path);
831 free(path);
832 return STOP;
834 free(path);
835 return OKAY;
838 enum okay
839 maildir_remove(const char *name)
841 if (subdir_remove(name, "tmp") == STOP ||
842 subdir_remove(name, "new") == STOP ||
843 subdir_remove(name, "cur") == STOP)
844 return STOP;
845 if (rmdir(name) < 0) {
846 perror(name);
847 return STOP;
849 return OKAY;