17 #include "date822fmt.h"
22 #define FATAL "ezmlm-warn: fatal: "
23 void die_usage() { strerr_die1x(100,"ezmlm-warn: usage: ezmlm-warn dir"); }
24 void die_nomem() { strerr_die2x(111,FATAL,"out of memory"); }
27 stralloc outhost = {0};
28 stralloc outlocal = {0};
29 stralloc mailinglist = {0};
36 void die_read() { strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fn.s,": "); }
44 char strnum[FMT_ULONG];
46 stralloc fnhash = {0};
47 stralloc quoted = {0};
51 int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
53 qmail_put(&qq,buf,len);
57 substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
59 char date[DATE822FMT];
69 strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
71 substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
73 if (getln(&sstext,&line,&match,'\n') == -1)
74 strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
77 qmail_put(&qq,line.s,line.len);
93 if (fd == -1) die_read();
94 substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
96 if (getln(&ssin,&addr,&match,'\0') == -1) die_read();
97 if (!match) { close(fd); return; }
99 if (!issub(addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; }
101 cookie(hash,"",0,"",addr.s,"");
102 if (!stralloc_copys(&fnhash,"bounce/h")) die_nomem();
103 if (!stralloc_catb(&fnhash,hash,COOKIE)) die_nomem();
104 if (!stralloc_0(&fnhash)) die_nomem();
106 if (qmail_open(&qq) == -1)
107 strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
110 qmail_puts(&qq,"Mailing-List: ");
111 qmail_put(&qq,mailinglist.s,mailinglist.len);
112 qmail_puts(&qq,"\nDate: ");
113 datetime_tai(&dt,msgwhen);
114 qmail_put(&qq,date,date822fmt(date,&dt));
115 qmail_puts(&qq,"Message-ID: <");
116 qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) msgwhen));
118 qmail_put(&qq,strnum,fmt_ulong(strnum,(unsigned long) getpid()));
119 qmail_puts(&qq,".ezmlm-warn@");
120 qmail_put(&qq,outhost.s,outhost.len);
121 qmail_puts(&qq,">\nFrom: ");
122 if (!quote("ed,&outlocal)) die_nomem();
123 qmail_put(&qq,quoted.s,quoted.len);
124 qmail_puts(&qq,"-help@");
125 qmail_put(&qq,outhost.s,outhost.len);
126 qmail_puts(&qq,"\nTo: ");
127 if (!quote2("ed,addr.s)) die_nomem();
128 qmail_put(&qq,quoted.s,quoted.len);
129 qmail_puts(&qq,flagw ? "\nSubject: ezmlm probe\n\n" : "\nSubject: ezmlm warning\n\n");
132 copy(flagw ? "text/bounce-probe" : "text/bounce-warn");
135 fdhash = open_read(fnhash.s);
137 if (errno != error_noent)
138 strerr_die6sys(111,FATAL,"unable to open ",dir,"/",fnhash.s,": ");
141 copy("text/bounce-num");
142 substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf));
143 if (substdio_copy(&ssqq,&sstext) < 0)
144 strerr_die6sys(111,FATAL,"unable to read ",dir,"/",fnhash.s,": ");
149 copy("text/bounce-bottom");
150 if (substdio_copy(&ssqq,&ssin) < 0) die_read();
153 strnum[fmt_ulong(strnum,when)] = 0;
154 cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W");
155 if (!stralloc_copy(&line,&outlocal)) die_nomem();
156 if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-")) die_nomem();
157 if (!stralloc_cats(&line,strnum)) die_nomem();
158 if (!stralloc_cats(&line,".")) die_nomem();
159 if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
160 if (!stralloc_cats(&line,"-")) die_nomem();
161 i = str_chr(addr.s,'@');
162 if (!stralloc_catb(&line,addr.s,i)) die_nomem();
164 if (!stralloc_cats(&line,"=")) die_nomem();
165 if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem();
167 if (!stralloc_cats(&line,"@")) die_nomem();
168 if (!stralloc_cat(&line,&outhost)) die_nomem();
169 if (!stralloc_0(&line)) die_nomem();
170 qmail_from(&qq,line.s);
172 qmail_to(&qq,addr.s);
173 if (qmail_close(&qq) != 0)
174 strerr_die2x(111,FATAL,"temporary qmail-queue error");
176 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
177 strerr_warn2("ezmlm-warn: info: qp ",strnum,0);
180 if (unlink(fnhash.s) == -1)
181 if (errno != error_noent)
182 strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fnhash.s,": ");
184 if (unlink(fn.s) == -1)
185 strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": ");
194 unsigned long bouncedate;
199 when = (unsigned long) now();
202 if (!dir) die_usage();
204 if (chdir(dir) == -1)
205 strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
207 switch(slurp("key",&key,32)) {
209 strerr_die4sys(111,FATAL,"unable to read ",dir,"/key: ");
211 strerr_die3x(100,FATAL,dir,"/key does not exist");
213 getconf_line(&outhost,"outhost",1,FATAL,dir);
214 getconf_line(&outlocal,"outlocal",1,FATAL,dir);
215 getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
217 fdlock = open_append("lockbounce");
219 strerr_die4sys(111,FATAL,"unable to open ",dir,"/lockbounce: ");
220 if (lock_ex(fdlock) == -1)
221 strerr_die4sys(111,FATAL,"unable to lock ",dir,"/lockbounce: ");
223 bouncedir = opendir("bounce");
225 strerr_die4sys(111,FATAL,"unable to open ",dir,"/bounce: ");
227 while (d = readdir(bouncedir)) {
228 if (str_equal(d->d_name,".")) continue;
229 if (str_equal(d->d_name,"..")) continue;
231 if (!stralloc_copys(&fn,"bounce/")) die_nomem();
232 if (!stralloc_cats(&fn,d->d_name)) die_nomem();
233 if (!stralloc_0(&fn)) die_nomem();
235 if (stat(fn.s,&st) == -1) {
236 if (errno == error_noent) continue;
237 strerr_die6sys(111,FATAL,"unable to stat ",dir,"/",fn.s,": ");
240 if (when > st.st_mtime + 3000000)
241 if (unlink(fn.s) == -1)
242 strerr_die6sys(111,FATAL,"unable to remove ",dir,"/",fn.s,": ");
244 if ((d->d_name[0] == 'd') || (d->d_name[0] == 'w')) {
245 scan_ulong(d->d_name + 1,&bouncedate);
246 if (when > bouncedate + 1000000)
247 doit(d->d_name[0] == 'w');