Mercurial > hg > Applications > mh
comparison uip/sendmail.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | 441a2190cfae |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:bce86c4163a3 |
---|---|
1 /* sendmail.c - */ | |
2 #ifndef lint | |
3 static char Id[] = "$Id$"; | |
4 #endif | |
5 /* | |
6 ** A Sendmail fake. | |
7 * | |
8 * Contributed by Scott Erickson <erickson@ics.uci.edu> | |
9 */ | |
10 /* Include files glommed from post.c */ | |
11 | |
12 #include "../h/mh.h" | |
13 #include "../h/addrsbr.h" | |
14 #include "../h/aliasbr.h" | |
15 #include "../h/dropsbr.h" | |
16 #include "../zotnet/tws.h" | |
17 #ifndef MMDFMTS | |
18 #include <ctype.h> | |
19 #include <errno.h> | |
20 #include <setjmp.h> | |
21 #include <stdio.h> | |
22 #include <sys/types.h> | |
23 #else MMDFMTS | |
24 #include "../mts/mmdf/util.h" | |
25 #include "../mts/mmdf/mmdf.h" | |
26 #endif MMDFMTS | |
27 #include "../zotnet/mts.h" | |
28 #ifdef MHMTS | |
29 #ifndef V7 | |
30 #include <sys/ioctl.h> | |
31 #endif not V7 | |
32 #include <sys/stat.h> | |
33 #endif MHMTS | |
34 #ifdef SENDMTS | |
35 #include "../mts/sendmail/smail.h" | |
36 #undef MF | |
37 #endif SENDMTS | |
38 #include <signal.h> | |
39 #ifdef LOCALE | |
40 #include <locale.h> | |
41 #endif | |
42 | |
43 char *SMTPSRVR = "smtpsrvr"; | |
44 | |
45 char msgfname[50]; /* name of message file */ | |
46 char *FullName; /* sender's full name */ | |
47 char *from; /* sender's mail address */ | |
48 int verbose; | |
49 int verify; | |
50 int extract; | |
51 int dodist; | |
52 int rewritefrom; | |
53 int status; /* return value from procedures */ | |
54 static int childid; /* id from smtp child process */ | |
55 TYPESIG die(); | |
56 time_t lclock = 0L; /* the time we started (more or less) */ | |
57 | |
58 | |
59 FILE *fp; /* file pointer for message file */ | |
60 extern FILE *tmpfile(); | |
61 | |
62 static struct swit switches[] = { | |
63 #define ARPASW 0 | |
64 "ba", -2, | |
65 #define DAEMONSW 1 | |
66 "bd", -2, | |
67 #define INITALSW 2 | |
68 "bi", -2, | |
69 #define DELIVSW 3 | |
70 "bm", -2, | |
71 #define QSUMSW 4 | |
72 "bp", -2, | |
73 #define SMTPSW 5 | |
74 "bs", -2, | |
75 #define ADRTSTSW 6 | |
76 "bt", -2, | |
77 #define ADRVRFSW 7 | |
78 "bv", -2, | |
79 #define CFGFRZSW 8 | |
80 "bz", -2, | |
81 #define ALTCFGSW 9 | |
82 "C", -1, | |
83 #define DBGVALSW 10 | |
84 "d", -1, | |
85 #define FULLSW 11 | |
86 "F", -1, | |
87 #define FROMSW 12 | |
88 "f", -1, | |
89 #define HOPCNTSW 13 | |
90 "h", -1, | |
91 #define MSGIDSW 14 | |
92 "M", -1, | |
93 #define NOALISW 15 | |
94 "n", -1, | |
95 #define QTIMESW 16 | |
96 "q", -1, | |
97 #define OBSFRMSW 17 | |
98 "r", -1, | |
99 #define EXTHDRSW 18 | |
100 "t", -1, | |
101 #define VERBSW 19 | |
102 "v", -1, | |
103 #define ALTALISW 20 | |
104 "oA", -2, | |
105 #define NOCONSW 21 | |
106 "oc", -2, | |
107 #define DLVMODSW 22 | |
108 "od", -2, | |
109 #define NEWALISW 23 | |
110 "oD", -2, | |
111 #define ERRMODSW 24 | |
112 "oe", -2, | |
113 #define TMPMODSW 25 | |
114 "oF", -2, | |
115 #define UFROMSW 26 | |
116 "of", -2, | |
117 #define GIDSW 27 | |
118 "og", -2, | |
119 #define HLPFILSW 28 | |
120 "oH", -2, | |
121 #define NODOTSW 29 | |
122 "oi", -2, | |
123 #define LOGLEVSW 30 | |
124 "oL", -2, | |
125 #define MEOKSW 31 | |
126 "om", -2, | |
127 #define OLDHDRSW 32 | |
128 "oo", -2, | |
129 #define QDIRSW 33 | |
130 "oQ", -2, | |
131 #define RTMOUTSW 34 | |
132 "or", -2, | |
133 #define SFILESW 35 | |
134 "oS", -2, | |
135 #define QMSGSW 36 | |
136 "os", -2, | |
137 #define MTMOUTSW 37 | |
138 "oT", -2, | |
139 #define TZSW 38 | |
140 "ot", -2, | |
141 #define UIDSW 39 | |
142 "ou", -2, | |
143 | |
144 NULL, 0 | |
145 }; | |
146 | |
147 #if !defined(POSIX) && !defined(_POSIX_SOURCE) | |
148 extern char *mktemp(); | |
149 #endif | |
150 | |
151 static void removemsg(); | |
152 static int isheader(), sendfile(); | |
153 | |
154 /*ARGSUSED*/ | |
155 main (argc, argv) | |
156 int argc; | |
157 char **argv; | |
158 { | |
159 register char *cp; | |
160 char **argp = argv + 1; | |
161 | |
162 #ifdef LOCALE | |
163 setlocale(LC_ALL, ""); | |
164 #endif | |
165 #ifdef JAPAN | |
166 ml_init(); | |
167 #endif /* JAPAN */ | |
168 invo_name = r1bindex (argv[0], '/'); | |
169 mts_init(argv[0]); | |
170 | |
171 if (signal(SIGINT, SIG_IGN) != SIG_IGN) | |
172 (void) signal(SIGINT, die); | |
173 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) | |
174 (void) signal(SIGHUP, die); | |
175 (void) signal(SIGTERM, die); | |
176 (void) signal(SIGPIPE, die); | |
177 | |
178 FullName = getfullname(); | |
179 from = adrsprintf(NULLCP,NULLCP); | |
180 (void) time (&lclock); | |
181 | |
182 while ( (cp = *argp) && *cp == '-' ) { | |
183 argp++; | |
184 switch (smatch ( ++cp, switches )) { | |
185 case ARPASW: /* smtp on stdin */ | |
186 case SMTPSW: /* smtp on stdin */ | |
187 smtp(); | |
188 exit(98); /* should never happen */ | |
189 | |
190 case DELIVSW: /* just send mail */ | |
191 continue; | |
192 | |
193 case ADRVRFSW: /* verify mode */ | |
194 verify = 1; | |
195 continue; | |
196 | |
197 case FROMSW: /* from address */ | |
198 case OBSFRMSW: /* obsolete -f flag */ | |
199 if (*(++cp) == '\0' && | |
200 (!(cp = *argp++) || *cp == '-')) | |
201 adios (NULLCP, "missing argument to %s", argp[-2]); | |
202 /* At this point, cp points to the from name */ | |
203 if (rewritefrom) { | |
204 adios (NULLCP, "More than one \"from\" person"); | |
205 continue; | |
206 } | |
207 from = cp; | |
208 rewritefrom = 1; | |
209 continue; | |
210 | |
211 case EXTHDRSW: /* read recipients from message */ | |
212 extract = 1; | |
213 continue; | |
214 | |
215 case VERBSW: /* give blow-by-blow description */ | |
216 verbose = 1; | |
217 continue; | |
218 | |
219 /* These switches have no args. */ | |
220 case QMSGSW: /* always queue the message */ | |
221 case DAEMONSW: /* run as a daemon & wait for SMTP */ | |
222 case INITALSW: /* initialize the alias database */ | |
223 case QSUMSW: /* print summary of mail queue */ | |
224 case ADRTSTSW: /* test the addresses to debug config file */ | |
225 case CFGFRZSW: /* create the configuration freeze file */ | |
226 case NOALISW: /* do not do aliasing */ | |
227 case NOCONSW: /* do not initiate immediate host connection */ | |
228 case NEWALISW: /* run newaliases to rebuild db */ | |
229 case UFROMSW: /* save UNIX-style From lines at front of msg*/ | |
230 case NODOTSW: /* dots on line are not msg terminators */ | |
231 case MEOKSW: /* ok to send to me if I'm in an alias */ | |
232 case OLDHDRSW: /* msg may have old-style headers */ | |
233 continue; | |
234 | |
235 /* These switches have string args. */ | |
236 case ALTALISW: /* use alternate alias file */ | |
237 case ALTCFGSW: /* use alternate configuration file */ | |
238 case DBGVALSW: /* set the debug value */ | |
239 case FULLSW: /* set full name */ | |
240 case MSGIDSW: /* try to deliver queued msg with msg-id */ | |
241 case QTIMESW: /* interval between queue passes */ | |
242 case DLVMODSW: /* set the delivery mode */ | |
243 case ERRMODSW: /* set the error mode */ | |
244 case TMPMODSW: /* the mode to use when creating tmp files */ | |
245 case HLPFILSW: /* the SMTP help file */ | |
246 case QDIRSW: /* directory into which to queue messages */ | |
247 case RTMOUTSW: /* timeout on reads */ | |
248 case SFILESW: /* save statistics in this file */ | |
249 case MTMOUTSW: /* timeout on messages in the queue */ | |
250 case TZSW: /* set the name of the timezone */ | |
251 if (*(++cp) == '\0' && | |
252 (!(cp = *argp++) || *cp == '-')) | |
253 adios (NULLCP, "missing argument to %s", argp[-2]); | |
254 /* At this point, cp points to the argument */ | |
255 continue; /* Ignore */ | |
256 | |
257 /* These switches have numeric args. */ | |
258 case HOPCNTSW: /* hop count */ | |
259 case GIDSW: /* gid when calling mailers */ | |
260 case LOGLEVSW: /* the log level */ | |
261 case UIDSW: /* uid when calling mailers */ | |
262 if (*(++cp) == '\0' && | |
263 (!(cp = *argp++) || *cp == '-')) | |
264 adios (NULLCP, "missing argument to %s", argp[-2]); | |
265 /* At this point, cp points to the numeric arg */ | |
266 if (!isdigit(*cp)) | |
267 adios (NULLCP, "non-numeric argument to %s", argp[-2]); | |
268 continue; /* Ignore */ | |
269 } | |
270 } | |
271 | |
272 (void) setuid(getuid()); | |
273 | |
274 if (verify && extract) | |
275 adios (NULLCP, "mode not supported on header components"); | |
276 | |
277 if (*argp == NULL && !extract) | |
278 adios (NULLCP, "usage: ", sendmail, " [flags] addr..."); | |
279 | |
280 strcpy (msgfname, "/tmp/sendmhXXXXXX"); | |
281 if ( mktemp(msgfname) == NULL ) | |
282 adios (msgfname, "can't create msg file "); | |
283 | |
284 if ( (fp = fopen(msgfname,"w") ) == NULL ) { | |
285 adios (msgfname, "error opening "); | |
286 } | |
287 | |
288 doheader(argp); | |
289 if ( verify ) { | |
290 (void) fclose(fp); | |
291 status = doverify(); | |
292 removemsg(); | |
293 exit ( status ) ; | |
294 } | |
295 dobody(); | |
296 status = sendfile(); | |
297 removemsg(); | |
298 exit ( status ); | |
299 } | |
300 | |
301 static void removemsg() | |
302 { | |
303 if ( unlink(msgfname) != 0 ) | |
304 perror("unlink"); | |
305 } | |
306 | |
307 doheader(argp) | |
308 char **argp; | |
309 { | |
310 char line[BUFSIZ]; | |
311 int gotdate, gotfrom, gotsender, gotto; | |
312 | |
313 /* if we're not extracting the headers from the message, then we | |
314 * need to check to see if we need to do a "send" or a "dist". | |
315 */ | |
316 | |
317 if ( !extract ) { | |
318 /* If we're doing a verify, just create a "To:" header. */ | |
319 if ( ! verify ) { | |
320 gotdate = gotfrom = gotto = gotsender = dodist = 0; | |
321 while (fgets (line, BUFSIZ, stdin) != NULL) { | |
322 if (line[0] == '\n') /* end of header */ | |
323 break; | |
324 if ( !isheader(line) ) | |
325 break; | |
326 | |
327 /* if any of the following headers are present, then we | |
328 * want to do a dist. | |
329 */ | |
330 if ( !gotdate && uprf(line, "date") ) | |
331 gotdate = dodist = 1; | |
332 | |
333 else if ( !gotto && (uprf(line, "to") || uprf(line, "cc")) ) | |
334 gotto = dodist = 1; | |
335 | |
336 else if ( uprf(line, "message-id") ) | |
337 dodist = 1; | |
338 | |
339 else if ( !gotsender && uprf(line, "sender") ) | |
340 gotsender = dodist = 1; | |
341 | |
342 else if ( uprf ( line, "resent-" ) ) { | |
343 dodist = 1; | |
344 (void) fputs("Prev-", fp); | |
345 } | |
346 | |
347 /* See if we are re-writing the from line */ | |
348 if ( uprf(line, "from") ) { | |
349 gotfrom = 1; | |
350 if ( rewritefrom ) | |
351 dofrom(); | |
352 else | |
353 (void) fputs(line,fp); | |
354 } | |
355 else | |
356 (void) fputs(line,fp); | |
357 } | |
358 } | |
359 /* Now, generate a "to" line. The first line is easy. | |
360 * Write the rest of the lines with a newline/tab so that we | |
361 * don't accidentally write a line that's too long to be parsed | |
362 * by post. | |
363 */ | |
364 (void) fprintf (fp, "%sTo: %s", (dodist ? "Resent-" : "" ), *argp++); | |
365 while ( *argp ) | |
366 (void) fprintf ( fp, ",\n\t%s", *argp++ ); | |
367 (void) fputs("\n",fp); | |
368 | |
369 /* If we're doing a dist, we must have a "Date:" and "From:" field. | |
370 */ | |
371 if ( dodist ) { | |
372 if ( !gotdate ) | |
373 (void) fprintf (fp, "Date: %s\n", dtime (&lclock)); | |
374 if ( !gotfrom ) | |
375 dofrom(); | |
376 } | |
377 #ifdef MMDFI /* sigh */ | |
378 if ( !gotsender ) | |
379 (void) fprintf (fp, "Sender: %s\n", from); | |
380 #endif MMDFI | |
381 } else { /* we're verifying, so just pass everything through */ | |
382 while (fgets (line, BUFSIZ, stdin) != NULL) { | |
383 if (line[0] == '\n') /* end of header */ | |
384 break; | |
385 | |
386 if ( rewritefrom && uprf(line, "from")) | |
387 dofrom(); | |
388 else | |
389 (void) fputs(line,fp); | |
390 } | |
391 } | |
392 /* At this point, line is either a newline (end of header) or the | |
393 * first line of the body (poorly formatted message). If line | |
394 * contains a line of body from a poorly formatted message, then | |
395 * print a newline to separate the header correctly, then print | |
396 * the body line. | |
397 */ | |
398 if ( line[0] != '\n' ) /* i.e. a "body" line */ | |
399 (void) fputc('\n', fp); | |
400 (void) fputs(line, fp); | |
401 } | |
402 | |
403 static int isheader(s) | |
404 char *s; | |
405 { | |
406 register char *cp; | |
407 | |
408 /* If the first character is a space, assume a continuation of a header */ | |
409 if ( isspace(*s) ) | |
410 return 1; | |
411 | |
412 /* If there's no ':', it's not a header */ | |
413 if ( (cp = index(s,':')) == NULL ) | |
414 return 0; | |
415 | |
416 /* If there's a space between BOL and ':', it's not a header */ | |
417 while ( s < cp ) { | |
418 if ( isspace(*s) ) | |
419 return 0; | |
420 s++; | |
421 } | |
422 return 1; | |
423 } | |
424 | |
425 /* This procedure does the verify and returns the status */ | |
426 doverify() { | |
427 char *command, buf[BUFSIZ], *bp; | |
428 FILE *verfp, *popen(); | |
429 | |
430 /* set up the command line for post */ | |
431 if ( (command = (char *)malloc((strlen(postproc) + | |
432 strlen(" -whom -check -verbose ") + | |
433 strlen(msgfname) + 1 )*sizeof(char))) | |
434 == NULL ) { | |
435 perror("malloc"); | |
436 return NOTOK; | |
437 } | |
438 | |
439 (void) strcpy(command,postproc); | |
440 (void) strcat(command," -whom -check "); | |
441 if ( verbose ) | |
442 (void) strcat(command, "-verbose " ); | |
443 (void) strcat(command, msgfname); | |
444 | |
445 /* open up the pipe */ | |
446 if ( (verfp = popen(command,"r")) == NULL ) | |
447 return NOTOK; | |
448 | |
449 while ( fgets(buf, BUFSIZ, verfp) != NULL ) | |
450 /* sendmail returns: | |
451 * address: result | |
452 * so we need to strip the extra post headers. | |
453 */ | |
454 if ( verbose ) { | |
455 bp = buf; | |
456 while (isspace(*bp)) | |
457 bp++; | |
458 if ( *bp != '-' ) | |
459 (void) fputs(bp,stdout); | |
460 } | |
461 | |
462 /* return the error status of post */ | |
463 return( pclose(verfp) >> 8 ); | |
464 } | |
465 | |
466 static int sendfile() | |
467 { | |
468 char *command, buf[BUFSIZ]; | |
469 FILE *verfp, *popen(); | |
470 | |
471 /* set up the command line for post */ | |
472 if ( (command = (char *)malloc((strlen(postproc) + | |
473 strlen(" -dist -verbose ") + | |
474 strlen(msgfname) + 1 )*sizeof(char))) | |
475 == NULL ) { | |
476 perror("malloc"); | |
477 return NOTOK; | |
478 } | |
479 | |
480 (void) strcpy(command,postproc); | |
481 (void) strcat(command," "); | |
482 if ( verbose ) | |
483 (void) strcat(command, "-verbose " ); | |
484 if ( dodist ) | |
485 (void) strcat(command, "-dist " ); | |
486 (void) strcat(command, msgfname); | |
487 | |
488 /* open up the pipe */ | |
489 if ( (verfp = popen(command,"r")) == NULL ) | |
490 return NOTOK; | |
491 | |
492 while ( fgets(buf, BUFSIZ, verfp) != NULL ) | |
493 (void) fputs(buf,stdout); | |
494 | |
495 /* return the error status of post */ | |
496 return( pclose(verfp) >> 8 ); | |
497 } | |
498 | |
499 dofrom() { | |
500 char line[128]; | |
501 | |
502 if (FullName) | |
503 (void) sprintf(line, "From: %s <%s>\n", FullName, from); | |
504 else | |
505 (void) sprintf(line, "From: %s\n", from); | |
506 (void) fputs(line, fp); | |
507 } | |
508 | |
509 dobody() { | |
510 register int i; | |
511 char buffer[BUFSIZ]; | |
512 | |
513 while (!feof (stdin) && !ferror (stdin) && | |
514 (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0) | |
515 if (fwrite (buffer, sizeof (char), i , fp) != i ) | |
516 adios (NULLCP, "Problem writing body"); | |
517 | |
518 if (ferror (stdin)) | |
519 adios (NULLCP, "Problem reading body"); | |
520 | |
521 if ( fclose(fp) != 0 ) | |
522 adios (NULLCP, "problem ending submission"); | |
523 } | |
524 | |
525 TYPESIG silentdie(); | |
526 | |
527 smtp() | |
528 { | |
529 int sd,len; | |
530 char buf[BUFSIZ], response[BUFSIZ]; | |
531 | |
532 if ((sd = client(NULLCP, "tcp", "smtp", 0, response)) == NOTOK) | |
533 adios (NULLCP, "cannot open smtp client process"); | |
534 | |
535 (void) signal(SIGCHLD, silentdie); | |
536 | |
537 switch ((childid = fork())) { | |
538 case NOTOK: | |
539 adios (NULLCP, "unable to fork smtp process"); | |
540 | |
541 case OK: /* i.e. child */ | |
542 (void) dup2(sd,0); | |
543 break; | |
544 | |
545 default: /* i.e. parent */ | |
546 (void) dup2(sd,1); | |
547 break; | |
548 } | |
549 while ( (len = read(0, buf, BUFSIZ)) > 0) | |
550 (void) write (1, buf, len); | |
551 | |
552 if (childid) | |
553 (void) kill(childid, SIGHUP); | |
554 | |
555 exit(9); | |
556 } | |
557 | |
558 /* ARGSUSED */ | |
559 TYPESIG die(sig) | |
560 int sig; | |
561 { | |
562 if (fp) { | |
563 (void) fclose(fp); | |
564 (void) unlink(msgfname); | |
565 } | |
566 if (sig != SIGHUP) | |
567 (void) fprintf(stderr, "sendmail: dying from signal %d\n", sig); | |
568 exit(99); | |
569 } | |
570 | |
571 /* ARGSUSED */ | |
572 | |
573 TYPESIG silentdie(sig) | |
574 int sig; | |
575 { | |
576 pidwait (childid, OK); | |
577 exit(0); | |
578 } |