Commit | Line | Data |
---|---|---|
5b62e993 MW |
1 | #include <sys/types.h> |
2 | #include <sys/time.h> | |
3 | #include "sgetopt.h" | |
4 | #include "stralloc.h" | |
5 | #include "strerr.h" | |
6 | #include "exit.h" | |
7 | #include "readwrite.h" | |
8 | #include "open.h" | |
9 | #include "substdio.h" | |
10 | #include "str.h" | |
11 | #include "auto_bin.h" | |
12 | ||
13 | #define FATAL "ezmlm-make: fatal: " | |
14 | ||
15 | void die_usage() | |
16 | { | |
17 | strerr_die1x(100,"ezmlm-make: usage: ezmlm-make [ -aApP ] dir dot local host"); | |
18 | } | |
19 | void die_relative() | |
20 | { | |
21 | strerr_die2x(100,FATAL,"dir must start with slash"); | |
22 | } | |
23 | void die_newline() | |
24 | { | |
25 | strerr_die2x(100,FATAL,"newlines not allowed"); | |
26 | } | |
27 | void die_quote() | |
28 | { | |
29 | strerr_die2x(100,FATAL,"quotes not allowed"); | |
30 | } | |
31 | void die_nomem() | |
32 | { | |
33 | strerr_die2x(111,FATAL,"out of memory"); | |
34 | } | |
35 | ||
36 | stralloc key = {0}; | |
37 | struct timeval tv; | |
38 | ||
39 | void keyadd(u) | |
40 | unsigned long u; | |
41 | { | |
42 | char ch; | |
43 | ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; | |
44 | ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; | |
45 | ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); u >>= 8; | |
46 | ch = u; if (!stralloc_append(&key,&ch)) die_nomem(); | |
47 | } | |
48 | ||
49 | void keyaddtime() | |
50 | { | |
51 | gettimeofday(&tv,(struct timezone *) 0); | |
52 | keyadd(tv.tv_usec); | |
53 | } | |
54 | ||
55 | char *dir; | |
56 | char *dot; | |
57 | char *local; | |
58 | char *host; | |
59 | ||
60 | stralloc dotplus = {0}; | |
61 | stralloc dirplus = {0}; | |
62 | ||
63 | void dirplusmake(slash) | |
64 | char *slash; | |
65 | { | |
66 | if (!stralloc_copys(&dirplus,dir)) die_nomem(); | |
67 | if (!stralloc_cats(&dirplus,slash)) die_nomem(); | |
68 | if (!stralloc_0(&dirplus)) die_nomem(); | |
69 | } | |
70 | ||
71 | void linkdotdir(dash,slash) | |
72 | char *dash; | |
73 | char *slash; | |
74 | { | |
75 | if (!stralloc_copys(&dotplus,dot)) die_nomem(); | |
76 | if (!stralloc_cats(&dotplus,dash)) die_nomem(); | |
77 | if (!stralloc_0(&dotplus)) die_nomem(); | |
78 | dirplusmake(slash); | |
79 | if (symlink(dirplus.s,dotplus.s) == -1) | |
80 | strerr_die4sys(111,FATAL,"unable to create ",dotplus.s,": "); | |
81 | keyaddtime(); | |
82 | } | |
83 | ||
84 | void dcreate(slash) | |
85 | char *slash; | |
86 | { | |
87 | dirplusmake(slash); | |
88 | if (mkdir(dirplus.s,0755) == -1) | |
89 | strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); | |
90 | keyaddtime(); | |
91 | } | |
92 | ||
93 | substdio ss; | |
94 | char ssbuf[SUBSTDIO_OUTSIZE]; | |
95 | ||
96 | void fopen(slash) | |
97 | char *slash; | |
98 | { | |
99 | int fd; | |
100 | ||
101 | dirplusmake(slash); | |
102 | fd = open_trunc(dirplus.s); | |
103 | if (fd == -1) | |
104 | strerr_die4sys(111,FATAL,"unable to create ",dirplus.s,": "); | |
105 | ||
106 | substdio_fdbuf(&ss,write,fd,ssbuf,sizeof(ssbuf)); | |
107 | } | |
108 | ||
109 | void fput(buf,len) | |
110 | char *buf; | |
111 | unsigned int len; | |
112 | { | |
113 | if (substdio_bput(&ss,buf,len) == -1) | |
114 | strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); | |
115 | } | |
116 | void fputs(buf) | |
117 | char *buf; | |
118 | { | |
119 | if (substdio_bputs(&ss,buf) == -1) | |
120 | strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); | |
121 | } | |
122 | ||
123 | void fclose() | |
124 | { | |
125 | if (substdio_flush(&ss) == -1) | |
126 | strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); | |
127 | if (fsync(ss.fd) == -1) | |
128 | strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); | |
129 | if (close(ss.fd) == -1) /* NFS stupidity */ | |
130 | strerr_die4sys(111,FATAL,"unable to write to ",dirplus.s,": "); | |
131 | keyaddtime(); | |
132 | } | |
133 | ||
134 | void main(argc,argv) | |
135 | int argc; | |
136 | char **argv; | |
137 | { | |
138 | int opt; | |
139 | int flagarchived; | |
140 | int flagpublic; | |
141 | ||
142 | keyadd(getpid()); | |
143 | keyadd(getppid()); | |
144 | keyadd(getuid()); | |
145 | keyadd(getgid()); | |
146 | gettimeofday(&tv,(struct timezone *) 0); | |
147 | keyadd(tv.tv_sec); | |
148 | ||
149 | umask(077); | |
150 | ||
151 | flagarchived = 1; | |
152 | flagpublic = 1; | |
153 | ||
154 | while ((opt = getopt(argc,argv,"aApP")) != opteof) | |
155 | switch(opt) { | |
156 | case 'a': flagarchived = 1; break; | |
157 | case 'A': flagarchived = 0; break; | |
158 | case 'p': flagpublic = 1; break; | |
159 | case 'P': flagpublic = 0; break; | |
160 | default: | |
161 | die_usage(); | |
162 | } | |
163 | argv += optind; | |
164 | ||
165 | if (!(dir = *argv++)) die_usage(); | |
166 | if (!(dot = *argv++)) die_usage(); | |
167 | if (!(local = *argv++)) die_usage(); | |
168 | if (!(host = *argv++)) die_usage(); | |
169 | ||
170 | if (dir[0] != '/') die_relative(); | |
171 | if (dir[str_chr(dir,'\'')]) die_quote(); | |
172 | if (dir[str_chr(dir,'\n')]) die_newline(); | |
173 | if (local[str_chr(local,'\n')]) die_newline(); | |
174 | if (host[str_chr(host,'\n')]) die_newline(); | |
175 | ||
176 | dcreate(""); | |
177 | dcreate("/archive"); | |
178 | dcreate("/subscribers"); | |
179 | dcreate("/bounce"); | |
180 | dcreate("/text"); | |
181 | ||
182 | ||
183 | linkdotdir("-owner","/owner"); | |
184 | linkdotdir("-default","/manager"); | |
185 | linkdotdir("-return-default","/bouncer"); | |
186 | linkdotdir("","/editor"); | |
187 | ||
188 | fopen("/lock"); fclose(); | |
189 | fopen("/lockbounce"); fclose(); | |
190 | if (flagpublic) { | |
191 | fopen("/public"); fclose(); | |
192 | } | |
193 | if (flagarchived) { | |
194 | fopen("/archived"); fclose(); | |
195 | } | |
196 | fopen("/num"); fputs("0\n"); fclose(); | |
197 | fopen("/inhost"); fputs(host); fputs("\n"); fclose(); | |
198 | fopen("/outhost"); fputs(host); fputs("\n"); fclose(); | |
199 | fopen("/inlocal"); fputs(local); fputs("\n"); fclose(); | |
200 | fopen("/outlocal"); fputs(local); fputs("\n"); fclose(); | |
201 | ||
202 | fopen("/mailinglist"); | |
203 | fputs("contact "); | |
204 | fputs(local); fputs("-help@"); fputs(host); fputs("; run by ezmlm\n"); | |
205 | fclose(); | |
206 | ||
207 | fopen("/owner"); | |
208 | fputs(dir); fputs("/Mailbox\n"); | |
209 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); | |
210 | fputs("' || exit 0\n"); | |
211 | fclose(); | |
212 | ||
213 | fopen("/manager"); | |
214 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-manage '"); fputs(dir); fputs("'\n"); | |
215 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); | |
216 | fputs("' || exit 0\n"); | |
217 | fclose(); | |
218 | ||
219 | fopen("/editor"); | |
220 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-reject\n"); | |
221 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-send '"); fputs(dir); fputs("'\n"); | |
222 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); | |
223 | fputs("' || exit 0\n"); | |
224 | fclose(); | |
225 | ||
226 | fopen("/bouncer"); | |
227 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-warn '"); fputs(dir); | |
228 | fputs("' || exit 0\n"); | |
229 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-weed\n"); | |
230 | fputs("|"); fputs(auto_bin); fputs("/ezmlm-return '"); fputs(dir); fputs("'\n"); | |
231 | fclose(); | |
232 | ||
233 | fopen("/headerremove"); | |
234 | fputs("\ | |
235 | return-path\n\ | |
236 | return-receipt-to\n\ | |
237 | content-length\n\ | |
238 | "); | |
239 | fclose(); | |
240 | ||
241 | fopen("/headeradd"); | |
242 | fclose(); | |
243 | ||
244 | ||
245 | fopen("/text/top"); | |
246 | fputs("Hi! This is the ezmlm program. I'm managing the\n"); | |
247 | fputs(local); fputs("@"); fputs(host); fputs(" mailing list.\n\n"); | |
248 | fclose(); | |
249 | ||
250 | fopen("/text/bottom"); | |
251 | fputs("\n--- Here are the ezmlm command addresses.\n\ | |
252 | \n\ | |
253 | I can handle administrative requests automatically.\n\ | |
254 | Just send an empty note to any of these addresses:\n\n <"); | |
255 | fputs(local); fputs("-subscribe@"); fputs(host); fputs(">:\n"); | |
256 | fputs(" Receive future messages sent to the mailing list.\n\n <"); | |
257 | fputs(local); fputs("-unsubscribe@"); fputs(host); fputs(">:\n"); | |
258 | fputs(" Stop receiving messages.\n\n <"); | |
259 | fputs(local); fputs("-get.12345@"); fputs(host); fputs(">:\n"); | |
260 | fputs(" Retrieve a copy of message 12345 from the archive.\n\ | |
261 | \n\ | |
262 | DO NOT SEND ADMINISTRATIVE REQUESTS TO THE MAILING LIST!\n\ | |
263 | If you do, I won't see them, and subscribers will yell at you.\n\ | |
264 | \n\ | |
265 | To specify God@heaven.af.mil as your subscription address, send mail\n\ | |
266 | to <"); | |
267 | fputs(local); fputs("-subscribe-God=heaven.af.mil@"); fputs(host); | |
268 | fputs(">.\n\ | |
269 | I'll send a confirmation message to that address; when you receive that\n\ | |
270 | message, simply reply to it to complete your subscription.\n\ | |
271 | \n"); | |
272 | fputs("\n--- Below this line is a copy of the request I received.\n\n"); | |
273 | fclose(); | |
274 | ||
275 | fopen("/text/sub-confirm"); | |
276 | fputs("To confirm that you would like\n\ | |
277 | \n\ | |
278 | !A\n\ | |
279 | \n\ | |
280 | added to this mailing list, please send an empty reply to this address:\n\ | |
281 | \n\ | |
282 | !R\n\ | |
283 | \n\ | |
284 | Your mailer should have a Reply feature that uses this address automatically.\n\ | |
285 | \n\ | |
286 | This confirmation serves two purposes. First, it verifies that I am able\n\ | |
287 | to get mail through to you. Second, it protects you in case someone\n\ | |
288 | forges a subscription request in your name.\n\ | |
289 | \n"); | |
290 | fclose(); | |
291 | ||
292 | fopen("/text/unsub-confirm"); | |
293 | fputs("To confirm that you would like\n\ | |
294 | \n\ | |
295 | !A\n\ | |
296 | \n\ | |
297 | removed from this mailing list, please send an empty reply to this address:\n\ | |
298 | \n\ | |
299 | !R\n\ | |
300 | \n\ | |
301 | Your mailer should have a Reply feature that uses this address automatically.\n\ | |
302 | \n\ | |
303 | I haven't checked whether your address is currently on the mailing list.\n\ | |
304 | To see what address you used to subscribe, look at the messages you are\n\ | |
305 | receiving from the mailing list. Each message has your address hidden\n\ | |
306 | inside its return path; for example, God@heaven.af.mil receives messages\n\ | |
307 | with return path ...-God=heaven.af.mil.\n\ | |
308 | \n"); | |
309 | fclose(); | |
310 | ||
311 | fopen("/text/sub-ok"); | |
312 | fputs("Acknowledgment: I have added the address\n\ | |
313 | \n\ | |
314 | !A\n\ | |
315 | \n\ | |
316 | to this mailing list.\n\ | |
317 | \n"); | |
318 | fclose(); | |
319 | ||
320 | fopen("/text/unsub-ok"); | |
321 | fputs("Acknowledgment: I have removed the address\n\ | |
322 | \n\ | |
323 | !A\n\ | |
324 | \n\ | |
325 | from this mailing list.\n\ | |
326 | \n"); | |
327 | fclose(); | |
328 | ||
329 | fopen("/text/sub-nop"); | |
330 | fputs("Acknowledgment: The address\n\ | |
331 | \n\ | |
332 | !A\n\ | |
333 | \n\ | |
334 | is on this mailing list.\n\ | |
335 | \n"); | |
336 | fclose(); | |
337 | ||
338 | fopen("/text/unsub-nop"); | |
339 | fputs("Acknowledgment: The address\n\ | |
340 | \n\ | |
341 | !A\n\ | |
342 | \n\ | |
343 | is not on this mailing list.\n\ | |
344 | \n"); | |
345 | fclose(); | |
346 | ||
347 | fopen("/text/sub-bad"); | |
348 | fputs("Oops, that confirmation number appears to be invalid.\n\ | |
349 | \n\ | |
350 | The most common reason for invalid numbers is expiration. I have to\n\ | |
351 | receive confirmation of each request within ten days.\n\ | |
352 | \n\ | |
353 | I've set up a new confirmation number. To confirm that you would like\n\ | |
354 | \n\ | |
355 | !A\n\ | |
356 | \n\ | |
357 | added to this mailing list, please send an empty reply to this address:\n\ | |
358 | \n\ | |
359 | !R\n\ | |
360 | \n\ | |
361 | Sorry for the trouble.\n\ | |
362 | \n"); | |
363 | fclose(); | |
364 | ||
365 | fopen("/text/unsub-bad"); | |
366 | fputs("Oops, that confirmation number appears to be invalid.\n\ | |
367 | \n\ | |
368 | The most common reason for invalid numbers is expiration. I have to\n\ | |
369 | receive confirmation of each request within ten days.\n\ | |
370 | \n\ | |
371 | I've set up a new confirmation number. To confirm that you would like\n\ | |
372 | \n\ | |
373 | !A\n\ | |
374 | \n\ | |
375 | removed from this mailing list, please send an empty reply to this address:\n\ | |
376 | \n\ | |
377 | !R\n\ | |
378 | \n\ | |
379 | Sorry for the trouble.\n\ | |
380 | \n"); | |
381 | fclose(); | |
382 | ||
383 | fopen("/text/get-bad"); | |
384 | fputs("Sorry, I don't see that message.\n\n"); | |
385 | fclose(); | |
386 | ||
387 | fopen("/text/bounce-bottom"); | |
388 | fputs("\n\ | |
389 | --- Below this line is a copy of the bounce message I received.\n\n"); | |
390 | fclose(); | |
391 | ||
392 | fopen("/text/bounce-warn"); | |
393 | fputs("\n\ | |
394 | Messages to you seem to have been bouncing. I've attached a copy of\n\ | |
395 | the first bounce message I received.\n\ | |
396 | \n\ | |
397 | If this message bounces too, I will send you a probe. If the probe bounces,\n\ | |
398 | I will remove your address from the mailing list, without further notice.\n\ | |
399 | \n"); | |
400 | fclose(); | |
401 | ||
402 | fopen("/text/bounce-probe"); | |
403 | fputs("\n\ | |
404 | Messages to you seem to have been bouncing. I sent you a warning\n\ | |
405 | message, but it bounced. I've attached a copy of the bounce message.\n\ | |
406 | \n\ | |
407 | This is a probe to check whether your address is reachable. If this\n\ | |
408 | probe bounces, I will remove your address from the mailing list, without\n\ | |
409 | further notice.\n\ | |
410 | \n"); | |
411 | fclose(); | |
412 | ||
413 | fopen("/text/bounce-num"); | |
414 | fputs("\n\ | |
415 | I've kept a list of which messages bounced from your address. Copies of\n\ | |
416 | these messages may be in the archive. To get message 12345 from the\n\ | |
417 | archive, send an empty note to "); | |
418 | fputs(local); fputs("-get.12345@"); fputs(host); fputs(".\n\ | |
419 | Here are the message numbers:\n\ | |
420 | \n"); | |
421 | fclose(); | |
422 | ||
423 | fopen("/text/help"); | |
424 | fputs("\ | |
425 | This is a generic help message. The message I received wasn't sent to\n\ | |
426 | any of my command addresses.\n\ | |
427 | \n"); | |
428 | fclose(); | |
429 | ||
430 | fopen("/key"); | |
431 | fput(key.s,key.len); | |
432 | fclose(); | |
433 | ||
434 | _exit(0); | |
435 | } |