maildir2mbox.c (4606B)
1 #include <sys/stat.h> 2 #include "readwrite.h" 3 #include "prioq.h" 4 #include "env.h" 5 #include "stralloc.h" 6 #include "subfd.h" 7 #include "substdio.h" 8 #include "getln.h" 9 #include "error.h" 10 #include "open.h" 11 #include "lock.h" 12 #include "gfrom.h" 13 #include "str.h" 14 #include "myctime.h" 15 #include "maildir.h" 16 17 extern int rename(const char *, const char *); 18 19 char *mbox; 20 char *mboxtmp; 21 22 stralloc filenames = {0}; 23 prioq pq = {0}; 24 prioq pq2 = {0}; 25 26 stralloc line = {0}; 27 28 stralloc ufline = {0}; 29 30 char inbuf[SUBSTDIO_INSIZE]; 31 char outbuf[SUBSTDIO_OUTSIZE]; 32 33 #define FATAL "maildir2mbox: fatal: " 34 #define WARNING "maildir2mbox: warning: " 35 36 void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); } 37 38 int main(void) 39 { 40 substdio ssin; 41 substdio ssout; 42 struct prioq_elt pe; 43 int fdoldmbox; 44 int fdnewmbox; 45 int fd; 46 int match; 47 int fdlock; 48 49 umask(077); 50 51 mbox = env_get("MAIL"); 52 if (!mbox) strerr_die2x(111,FATAL,"MAIL not set"); 53 mboxtmp = env_get("MAILTMP"); 54 if (!mboxtmp) strerr_die2x(111,FATAL,"MAILTMP not set"); 55 56 if (maildir_chdir() == -1) 57 strerr_die1(111,FATAL,&maildir_chdir_err); 58 maildir_clean(&filenames); 59 if (maildir_scan(&pq,&filenames,1,1) == -1) 60 strerr_die1(111,FATAL,&maildir_scan_err); 61 62 if (!prioq_min(&pq,&pe)) return 0; /* nothing new */ 63 64 fdlock = open_append(mbox); 65 if (fdlock == -1) 66 strerr_die4sys(111,FATAL,"unable to lock ",mbox,": "); 67 if (lock_ex(fdlock) == -1) 68 strerr_die4sys(111,FATAL,"unable to lock ",mbox,": "); 69 70 fdoldmbox = open_read(mbox); 71 if (fdoldmbox == -1) 72 strerr_die4sys(111,FATAL,"unable to read ",mbox,": "); 73 74 fdnewmbox = open_trunc(mboxtmp); 75 if (fdnewmbox == -1) 76 strerr_die4sys(111,FATAL,"unable to create ",mboxtmp,": "); 77 78 substdio_fdbuf(&ssin,read,fdoldmbox,inbuf,sizeof(inbuf)); 79 substdio_fdbuf(&ssout,write,fdnewmbox,outbuf,sizeof(outbuf)); 80 81 switch(substdio_copy(&ssout,&ssin)) 82 { 83 case -2: strerr_die4sys(111,FATAL,"unable to read ",mbox,": "); 84 case -3: strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 85 } 86 87 while (prioq_min(&pq,&pe)) 88 { 89 prioq_delmin(&pq); 90 if (!prioq_insert(&pq2,&pe)) die_nomem(); 91 92 fd = open_read(filenames.s + pe.id); 93 if (fd == -1) 94 strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); 95 substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf)); 96 97 if (getln(&ssin,&line,&match,'\n') != 0) 98 strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); 99 100 if (!stralloc_copys(&ufline,"From XXX ")) die_nomem(); 101 if (match) 102 if (stralloc_starts(&line,"Return-Path: <")) 103 { 104 if (line.s[14] == '>') 105 { 106 if (!stralloc_copys(&ufline,"From MAILER-DAEMON ")) die_nomem(); 107 } 108 else 109 { 110 int i; 111 if (!stralloc_ready(&ufline,line.len)) die_nomem(); 112 if (!stralloc_copys(&ufline,"From ")) die_nomem(); 113 for (i = 14;i < line.len - 2;++i) 114 if ((line.s[i] == ' ') || (line.s[i] == '\t')) 115 ufline.s[ufline.len++] = '-'; 116 else 117 ufline.s[ufline.len++] = line.s[i]; 118 if (!stralloc_cats(&ufline," ")) die_nomem(); 119 } 120 } 121 if (!stralloc_cats(&ufline,myctime(pe.dt))) die_nomem(); 122 if (substdio_put(&ssout,ufline.s,ufline.len) == -1) 123 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 124 125 while (match && line.len) 126 { 127 if (gfrom(line.s,line.len)) 128 if (substdio_puts(&ssout,">") == -1) 129 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 130 if (substdio_put(&ssout,line.s,line.len) == -1) 131 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 132 if (!match) 133 { 134 if (substdio_puts(&ssout,"\n") == -1) 135 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 136 break; 137 } 138 if (getln(&ssin,&line,&match,'\n') != 0) 139 strerr_die4sys(111,FATAL,"unable to read $MAILDIR/",filenames.s + pe.id,": "); 140 } 141 if (substdio_puts(&ssout,"\n")) 142 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 143 144 close(fd); 145 } 146 147 if (substdio_flush(&ssout) == -1) 148 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 149 if (fsync(fdnewmbox) == -1) 150 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 151 if (close(fdnewmbox) == -1) /* NFS dorks */ 152 strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": "); 153 if (rename(mboxtmp,mbox) == -1) 154 strerr_die6(111,FATAL,"unable to move ",mboxtmp," to ",mbox,": ",&strerr_sys); 155 156 while (prioq_min(&pq2,&pe)) 157 { 158 prioq_delmin(&pq2); 159 if (unlink(filenames.s + pe.id) == -1) 160 strerr_warn4(WARNING,"$MAILDIR/",filenames.s + pe.id," will be delivered twice; unable to unlink: ",&strerr_sys); 161 } 162 163 return 0; 164 }