15 #include "readwrite.h"
21 #define FATAL "ezmlm-send: fatal: "
25 strerr_die1x(100,"ezmlm-send: usage: ezmlm-send dir");
29 strerr_die2x(111,FATAL,"out of memory");
32 char strnum[FMT_ULONG];
34 stralloc fnadir = {0};
42 char archivebuf[1024];
45 stralloc sublist = {0};
46 stralloc mailinglist = {0};
47 stralloc outlocal = {0};
48 stralloc outhost = {0};
49 stralloc headerremove = {0};
50 struct constmap headerremovemap;
51 stralloc headeradd = {0};
59 int mywrite(fd,buf,len)
64 qmail_put(&qq,buf,len);
70 strerr_die4sys(111,FATAL,"unable to write to ",fnaf.s,": ");
74 strerr_die2sys(111,FATAL,"unable to create numnew: ");
77 void put(buf,len) char *buf; int len;
79 qmail_put(&qq,buf,len);
81 if (substdio_put(&ssarchive,buf,len) == -1) die_archive();
84 void puts(buf) char *buf;
88 if (substdio_puts(&ssarchive,buf) == -1) die_archive();
91 int sublistmatch(sender)
98 if (j < sublist.len) return 0;
100 i = byte_rchr(sublist.s,sublist.len,'@');
101 if (i == sublist.len) return 1;
103 if (byte_diff(sublist.s,i,sender)) return 0;
104 if (case_diffb(sublist.s + i,sublist.len - i,sender + j - (sublist.len - i)))
112 unsigned long msgnum;
116 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
122 fd = open_trunc("numnew");
123 if (fd == -1) die_numnew();
124 substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf));
125 if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1)
127 if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew();
128 if (substdio_flush(&ssnumnew) == -1) die_numnew();
129 if (fsync(fd) == -1) die_numnew();
130 if (close(fd) == -1) die_numnew(); /* NFS stupidity */
131 if (rename("numnew","num") == -1)
132 strerr_die2sys(111,FATAL,"unable to move numnew to num: ");
135 stralloc mydtline = {0};
156 if (!dir) die_usage();
158 sender = env_get("SENDER");
160 if (chdir(dir) == -1)
161 strerr_die4sys(111,FATAL,"unable to switch to ",dir,": ");
163 fdlock = open_append("lock");
165 strerr_die4sys(111,FATAL,"unable to open ",dir,"/lock: ");
166 if (lock_ex(fdlock) == -1)
167 strerr_die4sys(111,FATAL,"unable to obtain ",dir,"/lock: ");
169 if (qmail_open(&qq) == -1)
170 strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
172 flagarchived = getconf_line(&line,"archived",0,FATAL,dir);
174 getconf_line(&num,"num",1,FATAL,dir);
175 if (!stralloc_0(&num)) die_nomem();
176 scan_ulong(num.s,&msgnum);
179 getconf_line(&outhost,"outhost",1,FATAL,dir);
180 getconf_line(&outlocal,"outlocal",1,FATAL,dir);
181 getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
182 flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir);
184 getconf(&headerremove,"headerremove",1,FATAL,dir);
185 constmap_init(&headerremovemap,headerremove.s,headerremove.len,0);
187 getconf(&headeradd,"headeradd",1,FATAL,dir);
188 for (i = 0;i < headeradd.len;++i)
190 headeradd.s[i] = '\n';
192 if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem();
193 if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
194 if (!stralloc_cats(&mydtline,"@")) die_nomem();
195 if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
196 if (!stralloc_cats(&mydtline,"\n")) die_nomem();
200 strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)");
201 if (str_equal(sender,"#@[]"))
202 strerr_die2x(100,FATAL,"I don't distribute bounce messages (#5.7.2)");
204 if (!sublistmatch(sender))
205 strerr_die2x(100,FATAL,"this message is not from my parent list (#5.7.2)");
209 if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
210 if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,msgnum / 100))) die_nomem();
211 if (!stralloc_copy(&fnaf,&fnadir)) die_nomem();
212 if (!stralloc_cats(&fnaf,"/")) die_nomem();
213 if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,(unsigned int) (msgnum % 100),2))) die_nomem();
214 if (!stralloc_0(&fnadir)) die_nomem();
215 if (!stralloc_0(&fnaf)) die_nomem();
217 if (mkdir(fnadir.s,0755) == -1)
218 if (errno != error_exist)
219 strerr_die4sys(111,FATAL,"unable to create ",fnadir.s,": ");
220 fdarchive = open_trunc(fnaf.s);
222 strerr_die4sys(111,FATAL,"unable to write ",fnaf.s,": ");
224 substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf));
228 puts("Mailing-List: ");
229 put(mailinglist.s,mailinglist.len);
232 put(headeradd.s,headeradd.len);
233 put(mydtline.s,mydtline.len);
240 if (getln(&ss0,&line,&match,'\n') == -1)
241 strerr_die2sys(111,FATAL,"unable to read input: ");
243 if (flaginheader && match) {
246 if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
248 if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
250 if (case_startb(line.s,line.len,"mailing-list:"))
252 if (line.len == mydtline.len)
253 if (!byte_diff(line.s,line.len,mydtline.s))
254 strerr_die2x(100,FATAL,"this message is looping: it already has my Delivered-To line (#5.4.6)");
258 if (!(flaginheader && flagbadfield))
259 put(line.s,line.len);
267 strerr_die2x(100,FATAL,"sublist messages must have Mailing-List (#5.7.2)");
270 strerr_die2x(100,FATAL,"message already has Mailing-List (#5.7.2)");
273 if (substdio_flush(&ssarchive) == -1) die_archive();
274 if (fsync(fdarchive) == -1) die_archive();
275 if (fchmod(fdarchive,0744) == -1) die_archive();
276 if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */
281 if (!stralloc_copy(&line,&outlocal)) die_nomem();
282 if (!stralloc_cats(&line,"-return-")) die_nomem();
283 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem();
284 if (!stralloc_cats(&line,"-@")) die_nomem();
285 if (!stralloc_cat(&line,&outhost)) die_nomem();
286 if (!stralloc_cats(&line,"-@[]")) die_nomem();
287 if (!stralloc_0(&line)) die_nomem();
289 qmail_from(&qq,line.s);
291 for (i = 0;i < 53;++i) {
293 if (!stralloc_copys(&fnsub,"subscribers/")) die_nomem();
294 if (!stralloc_catb(&fnsub,&ch,1)) strerr_die2x(111,FATAL,"out of memory");
295 if (!stralloc_0(&fnsub)) strerr_die2x(111,FATAL,"out of memory");
296 fd = open_read(fnsub.s);
298 if (errno != error_noent)
299 strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": ");
302 substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));
303 substdio_fdbuf(&ssout,mywrite,-1,outbuf,sizeof(outbuf));
304 if (substdio_copy(&ssout,&ssin) != 0)
305 strerr_die4sys(111,FATAL,"unable to read ",fnsub.s,": ");
310 switch(qmail_close(&qq)) {
312 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
313 strerr_die2x(0,"ezmlm-send: info: qp ",strnum);
317 strerr_die2x(111,FATAL,"temporary qmail-queue error");