]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/sendmail.c
aliasbr.c: Remove duplicate prototypes. Others in aliasbr.h.
[nmh] / docs / historical / mh-6.8.5 / uip / sendmail.c
1 /* sendmail.c - */
2 #ifndef lint
3 static char Id[] = "$Id: sendmail.c,v 1.9 1992/11/24 18:37:01 jromine Exp $";
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 long 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 invo_name = r1bindex (argv[0], '/');
166 mts_init(argv[0]);
167
168 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
169 (void) signal(SIGINT, die);
170 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
171 (void) signal(SIGHUP, die);
172 (void) signal(SIGTERM, die);
173 (void) signal(SIGPIPE, die);
174
175 FullName = getfullname();
176 from = adrsprintf(NULLCP,NULLCP);
177 (void) time (&lclock);
178
179 while ( (cp = *argp) && *cp == '-' ) {
180 argp++;
181 switch (smatch ( ++cp, switches )) {
182 case ARPASW: /* smtp on stdin */
183 case SMTPSW: /* smtp on stdin */
184 smtp();
185 exit(98); /* should never happen */
186
187 case DELIVSW: /* just send mail */
188 continue;
189
190 case ADRVRFSW: /* verify mode */
191 verify = 1;
192 continue;
193
194 case FROMSW: /* from address */
195 case OBSFRMSW: /* obsolete -f flag */
196 if (*(++cp) == '\0' &&
197 (!(cp = *argp++) || *cp == '-'))
198 adios (NULLCP, "missing argument to %s", argp[-2]);
199 /* At this point, cp points to the from name */
200 if (rewritefrom) {
201 adios (NULLCP, "More than one \"from\" person");
202 continue;
203 }
204 from = cp;
205 rewritefrom = 1;
206 continue;
207
208 case EXTHDRSW: /* read recipients from message */
209 extract = 1;
210 continue;
211
212 case VERBSW: /* give blow-by-blow description */
213 verbose = 1;
214 continue;
215
216 /* These switches have no args. */
217 case QMSGSW: /* always queue the message */
218 case DAEMONSW: /* run as a daemon & wait for SMTP */
219 case INITALSW: /* initialize the alias database */
220 case QSUMSW: /* print summary of mail queue */
221 case ADRTSTSW: /* test the addresses to debug config file */
222 case CFGFRZSW: /* create the configuration freeze file */
223 case NOALISW: /* do not do aliasing */
224 case NOCONSW: /* do not initiate immediate host connection */
225 case NEWALISW: /* run newaliases to rebuild db */
226 case UFROMSW: /* save UNIX-style From lines at front of msg*/
227 case NODOTSW: /* dots on line are not msg terminators */
228 case MEOKSW: /* ok to send to me if I'm in an alias */
229 case OLDHDRSW: /* msg may have old-style headers */
230 continue;
231
232 /* These switches have string args. */
233 case ALTALISW: /* use alternate alias file */
234 case ALTCFGSW: /* use alternate configuration file */
235 case DBGVALSW: /* set the debug value */
236 case FULLSW: /* set full name */
237 case MSGIDSW: /* try to deliver queued msg with msg-id */
238 case QTIMESW: /* interval between queue passes */
239 case DLVMODSW: /* set the delivery mode */
240 case ERRMODSW: /* set the error mode */
241 case TMPMODSW: /* the mode to use when creating tmp files */
242 case HLPFILSW: /* the SMTP help file */
243 case QDIRSW: /* directory into which to queue messages */
244 case RTMOUTSW: /* timeout on reads */
245 case SFILESW: /* save statistics in this file */
246 case MTMOUTSW: /* timeout on messages in the queue */
247 case TZSW: /* set the name of the timezone */
248 if (*(++cp) == '\0' &&
249 (!(cp = *argp++) || *cp == '-'))
250 adios (NULLCP, "missing argument to %s", argp[-2]);
251 /* At this point, cp points to the argument */
252 continue; /* Ignore */
253
254 /* These switches have numeric args. */
255 case HOPCNTSW: /* hop count */
256 case GIDSW: /* gid when calling mailers */
257 case LOGLEVSW: /* the log level */
258 case UIDSW: /* uid when calling mailers */
259 if (*(++cp) == '\0' &&
260 (!(cp = *argp++) || *cp == '-'))
261 adios (NULLCP, "missing argument to %s", argp[-2]);
262 /* At this point, cp points to the numeric arg */
263 if (!isdigit(*cp))
264 adios (NULLCP, "non-numeric argument to %s", argp[-2]);
265 continue; /* Ignore */
266 }
267 }
268
269 (void) setuid(getuid());
270
271 if (verify && extract)
272 adios (NULLCP, "mode not supported on header components");
273
274 if (*argp == NULL && !extract)
275 adios (NULLCP, "usage: /usr/lib/sendmail [flags] addr...");
276
277 strcpy (msgfname, "/tmp/sendmhXXXXXX");
278 if ( mktemp(msgfname) == NULL )
279 adios (msgfname, "can't create msg file ");
280
281 if ( (fp = fopen(msgfname,"w") ) == NULL ) {
282 adios (msgfname, "error opening ");
283 }
284
285 doheader(argp);
286 if ( verify ) {
287 (void) fclose(fp);
288 status = doverify();
289 removemsg();
290 exit ( status ) ;
291 }
292 dobody();
293 status = sendfile();
294 removemsg();
295 exit ( status );
296 }
297
298 static void removemsg()
299 {
300 if ( unlink(msgfname) != 0 )
301 perror("unlink");
302 }
303
304 doheader(argp)
305 char **argp;
306 {
307 char line[BUFSIZ];
308 int gotdate, gotfrom, gotsender, gotto;
309
310 /* if we're not extracting the headers from the message, then we
311 * need to check to see if we need to do a "send" or a "dist".
312 */
313
314 if ( !extract ) {
315 /* If we're doing a verify, just create a "To:" header. */
316 if ( ! verify ) {
317 gotdate = gotfrom = gotto = gotsender = dodist = 0;
318 while (fgets (line, BUFSIZ, stdin) != NULL) {
319 if (line[0] == '\n') /* end of header */
320 break;
321 if ( !isheader(line) )
322 break;
323
324 /* if any of the following headers are present, then we
325 * want to do a dist.
326 */
327 if ( !gotdate && uprf(line, "date") )
328 gotdate = dodist = 1;
329
330 else if ( !gotto && (uprf(line, "to") || uprf(line, "cc")) )
331 gotto = dodist = 1;
332
333 else if ( uprf(line, "message-id") )
334 dodist = 1;
335
336 else if ( !gotsender && uprf(line, "sender") )
337 gotsender = dodist = 1;
338
339 else if ( uprf ( line, "resent-" ) ) {
340 dodist = 1;
341 (void) fputs("Prev-", fp);
342 }
343
344 /* See if we are re-writing the from line */
345 if ( uprf(line, "from") ) {
346 gotfrom = 1;
347 if ( rewritefrom )
348 dofrom();
349 else
350 (void) fputs(line,fp);
351 }
352 else
353 (void) fputs(line,fp);
354 }
355 }
356 /* Now, generate a "to" line. The first line is easy.
357 * Write the rest of the lines with a newline/tab so that we
358 * don't accidentally write a line that's too long to be parsed
359 * by post.
360 */
361 (void) fprintf (fp, "%sTo: %s", (dodist ? "Resent-" : "" ), *argp++);
362 while ( *argp )
363 (void) fprintf ( fp, ",\n\t%s", *argp++ );
364 (void) fputs("\n",fp);
365
366 /* If we're doing a dist, we must have a "Date:" and "From:" field.
367 */
368 if ( dodist ) {
369 if ( !gotdate )
370 (void) fprintf (fp, "Date: %s\n", dtime (&lclock));
371 if ( !gotfrom )
372 dofrom();
373 }
374 #ifdef MMDFI /* sigh */
375 if ( !gotsender )
376 (void) fprintf (fp, "Sender: %s\n", from);
377 #endif MMDFI
378 } else { /* we're verifying, so just pass everything through */
379 while (fgets (line, BUFSIZ, stdin) != NULL) {
380 if (line[0] == '\n') /* end of header */
381 break;
382
383 if ( rewritefrom && uprf(line, "from"))
384 dofrom();
385 else
386 (void) fputs(line,fp);
387 }
388 }
389 /* At this point, line is either a newline (end of header) or the
390 * first line of the body (poorly formatted message). If line
391 * contains a line of body from a poorly formatted message, then
392 * print a newline to separate the header correctly, then print
393 * the body line.
394 */
395 if ( line[0] != '\n' ) /* i.e. a "body" line */
396 (void) fputc('\n', fp);
397 (void) fputs(line, fp);
398 }
399
400 static int isheader(s)
401 char *s;
402 {
403 register char *cp;
404
405 /* If the first character is a space, assume a continuation of a header */
406 if ( isspace(*s) )
407 return 1;
408
409 /* If there's no ':', it's not a header */
410 if ( (cp = index(s,':')) == NULL )
411 return 0;
412
413 /* If there's a space between BOL and ':', it's not a header */
414 while ( s < cp ) {
415 if ( isspace(*s) )
416 return 0;
417 s++;
418 }
419 return 1;
420 }
421
422 /* This procedure does the verify and returns the status */
423 doverify() {
424 char *command, buf[BUFSIZ], *bp;
425 FILE *verfp, *popen();
426
427 /* set up the command line for post */
428 if ( (command = (char *)malloc((strlen(postproc) +
429 strlen(" -whom -check -verbose ") +
430 strlen(msgfname) + 1 )*sizeof(char)))
431 == NULL ) {
432 perror("malloc");
433 return NOTOK;
434 }
435
436 (void) strcpy(command,postproc);
437 (void) strcat(command," -whom -check ");
438 if ( verbose )
439 (void) strcat(command, "-verbose " );
440 (void) strcat(command, msgfname);
441
442 /* open up the pipe */
443 if ( (verfp = popen(command,"r")) == NULL )
444 return NOTOK;
445
446 while ( fgets(buf, BUFSIZ, verfp) != NULL )
447 /* sendmail returns:
448 * address: result
449 * so we need to strip the extra post headers.
450 */
451 if ( verbose ) {
452 bp = buf;
453 while (isspace(*bp))
454 bp++;
455 if ( *bp != '-' )
456 (void) fputs(bp,stdout);
457 }
458
459 /* return the error status of post */
460 return( pclose(verfp) >> 8 );
461 }
462
463 static int sendfile()
464 {
465 char *command, buf[BUFSIZ];
466 FILE *verfp, *popen();
467
468 /* set up the command line for post */
469 if ( (command = (char *)malloc((strlen(postproc) +
470 strlen(" -dist -verbose ") +
471 strlen(msgfname) + 1 )*sizeof(char)))
472 == NULL ) {
473 perror("malloc");
474 return NOTOK;
475 }
476
477 (void) strcpy(command,postproc);
478 (void) strcat(command," ");
479 if ( verbose )
480 (void) strcat(command, "-verbose " );
481 if ( dodist )
482 (void) strcat(command, "-dist " );
483 (void) strcat(command, msgfname);
484
485 /* open up the pipe */
486 if ( (verfp = popen(command,"r")) == NULL )
487 return NOTOK;
488
489 while ( fgets(buf, BUFSIZ, verfp) != NULL )
490 (void) fputs(buf,stdout);
491
492 /* return the error status of post */
493 return( pclose(verfp) >> 8 );
494 }
495
496 dofrom() {
497 char line[128];
498
499 if (FullName)
500 (void) sprintf(line, "From: %s <%s>\n", FullName, from);
501 else
502 (void) sprintf(line, "From: %s\n", from);
503 (void) fputs(line, fp);
504 }
505
506 dobody() {
507 register int i;
508 char buffer[BUFSIZ];
509
510 while (!feof (stdin) && !ferror (stdin) &&
511 (i = fread (buffer, sizeof (char), sizeof (buffer), stdin)) > 0)
512 if (fwrite (buffer, sizeof (char), i , fp) != i )
513 adios (NULLCP, "Problem writing body");
514
515 if (ferror (stdin))
516 adios (NULLCP, "Problem reading body");
517
518 if ( fclose(fp) != 0 )
519 adios (NULLCP, "problem ending submission");
520 }
521
522 TYPESIG silentdie();
523
524 smtp()
525 {
526 int sd,len;
527 char buf[BUFSIZ], response[BUFSIZ];
528
529 if ((sd = client(NULLCP, "tcp", "smtp", 0, response)) == NOTOK)
530 adios (NULLCP, "cannot open smtp client process");
531
532 (void) signal(SIGCHLD, silentdie);
533
534 switch ((childid = fork())) {
535 case NOTOK:
536 adios (NULLCP, "unable to fork smtp process");
537
538 case OK: /* i.e. child */
539 (void) dup2(sd,0);
540 break;
541
542 default: /* i.e. parent */
543 (void) dup2(sd,1);
544 break;
545 }
546 while ( (len = read(0, buf, BUFSIZ)) > 0)
547 (void) write (1, buf, len);
548
549 if (childid)
550 (void) kill(childid, SIGHUP);
551
552 exit(9);
553 }
554
555 /* ARGSUSED */
556 TYPESIG die(sig)
557 int sig;
558 {
559 if (fp) {
560 (void) fclose(fp);
561 (void) unlink(msgfname);
562 }
563 if (sig != SIGHUP)
564 (void) fprintf(stderr, "sendmail: dying from signal %d\n", sig);
565 exit(99);
566 }
567
568 /* ARGSUSED */
569
570 TYPESIG silentdie(sig)
571 int sig;
572 {
573 pidwait (childid, OK);
574 exit(0);
575 }