]>
diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/sendmail.c
3 static char Id
[] = "$Id: sendmail.c,v 1.9 1992/11/24 18:37:01 jromine Exp $";
8 * Contributed by Scott Erickson <erickson@ics.uci.edu>
10 /* Include files glommed from post.c */
13 #include "../h/addrsbr.h"
14 #include "../h/aliasbr.h"
15 #include "../h/dropsbr.h"
16 #include "../zotnet/tws.h"
22 #include <sys/types.h>
24 #include "../mts/mmdf/util.h"
25 #include "../mts/mmdf/mmdf.h"
27 #include "../zotnet/mts.h"
30 #include <sys/ioctl.h>
35 #include "../mts/sendmail/smail.h"
43 char *SMTPSRVR
= "smtpsrvr";
45 char msgfname
[50]; /* name of message file */
46 char *FullName
; /* sender's full name */
47 char *from
; /* sender's mail address */
53 int status
; /* return value from procedures */
54 static int childid
; /* id from smtp child process */
56 long lclock
= 0L; /* the time we started (more or less) */
59 FILE *fp
; /* file pointer for message file */
60 extern FILE *tmpfile();
62 static struct swit switches
[] = {
147 #if !defined(POSIX) && !defined(_POSIX_SOURCE)
148 extern char *mktemp();
151 static void removemsg();
152 static int isheader(), sendfile();
160 char **argp
= argv
+ 1;
163 setlocale(LC_ALL
, "");
165 invo_name
= r1bindex (argv
[0], '/');
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
);
175 FullName
= getfullname();
176 from
= adrsprintf(NULLCP
,NULLCP
);
177 (void) time (&lclock
);
179 while ( (cp
= *argp
) && *cp
== '-' ) {
181 switch (smatch ( ++cp
, switches
)) {
182 case ARPASW
: /* smtp on stdin */
183 case SMTPSW
: /* smtp on stdin */
185 exit(98); /* should never happen */
187 case DELIVSW
: /* just send mail */
190 case ADRVRFSW
: /* verify mode */
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 */
201 adios (NULLCP
, "More than one \"from\" person");
208 case EXTHDRSW
: /* read recipients from message */
212 case VERBSW
: /* give blow-by-blow description */
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 */
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 */
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 */
264 adios (NULLCP
, "non-numeric argument to %s", argp
[-2]);
265 continue; /* Ignore */
269 (void) setuid(getuid());
271 if (verify
&& extract
)
272 adios (NULLCP
, "mode not supported on header components");
274 if (*argp
== NULL
&& !extract
)
275 adios (NULLCP
, "usage: /usr/lib/sendmail [flags] addr...");
277 strcpy (msgfname
, "/tmp/sendmhXXXXXX");
278 if ( mktemp(msgfname
) == NULL
)
279 adios (msgfname
, "can't create msg file ");
281 if ( (fp
= fopen(msgfname
,"w") ) == NULL
) {
282 adios (msgfname
, "error opening ");
298 static void removemsg()
300 if ( unlink(msgfname
) != 0 )
308 int gotdate
, gotfrom
, gotsender
, gotto
;
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".
315 /* If we're doing a verify, just create a "To:" header. */
317 gotdate
= gotfrom
= gotto
= gotsender
= dodist
= 0;
318 while (fgets (line
, BUFSIZ
, stdin
) != NULL
) {
319 if (line
[0] == '\n') /* end of header */
321 if ( !isheader(line
) )
324 /* if any of the following headers are present, then we
327 if ( !gotdate
&& uprf(line
, "date") )
328 gotdate
= dodist
= 1;
330 else if ( !gotto
&& (uprf(line
, "to") || uprf(line
, "cc")) )
333 else if ( uprf(line
, "message-id") )
336 else if ( !gotsender
&& uprf(line
, "sender") )
337 gotsender
= dodist
= 1;
339 else if ( uprf ( line
, "resent-" ) ) {
341 (void) fputs("Prev-", fp
);
344 /* See if we are re-writing the from line */
345 if ( uprf(line
, "from") ) {
350 (void) fputs(line
,fp
);
353 (void) fputs(line
,fp
);
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
361 (void) fprintf (fp
, "%sTo: %s", (dodist
? "Resent-" : "" ), *argp
++);
363 (void) fprintf ( fp
, ",\n\t%s", *argp
++ );
364 (void) fputs("\n",fp
);
366 /* If we're doing a dist, we must have a "Date:" and "From:" field.
370 (void) fprintf (fp
, "Date: %s\n", dtime (&lclock
));
374 #ifdef MMDFI /* sigh */
376 (void) fprintf (fp
, "Sender: %s\n", from
);
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 */
383 if ( rewritefrom
&& uprf(line
, "from"))
386 (void) fputs(line
,fp
);
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
395 if ( line
[0] != '\n' ) /* i.e. a "body" line */
396 (void) fputc('\n', fp
);
397 (void) fputs(line
, fp
);
400 static int isheader(s
)
405 /* If the first character is a space, assume a continuation of a header */
409 /* If there's no ':', it's not a header */
410 if ( (cp
= index(s
,':')) == NULL
)
413 /* If there's a space between BOL and ':', it's not a header */
422 /* This procedure does the verify and returns the status */
424 char *command
, buf
[BUFSIZ
], *bp
;
425 FILE *verfp
, *popen();
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)))
436 (void) strcpy(command
,postproc
);
437 (void) strcat(command
," -whom -check ");
439 (void) strcat(command
, "-verbose " );
440 (void) strcat(command
, msgfname
);
442 /* open up the pipe */
443 if ( (verfp
= popen(command
,"r")) == NULL
)
446 while ( fgets(buf
, BUFSIZ
, verfp
) != NULL
)
449 * so we need to strip the extra post headers.
456 (void) fputs(bp
,stdout
);
459 /* return the error status of post */
460 return( pclose(verfp
) >> 8 );
463 static int sendfile()
465 char *command
, buf
[BUFSIZ
];
466 FILE *verfp
, *popen();
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)))
477 (void) strcpy(command
,postproc
);
478 (void) strcat(command
," ");
480 (void) strcat(command
, "-verbose " );
482 (void) strcat(command
, "-dist " );
483 (void) strcat(command
, msgfname
);
485 /* open up the pipe */
486 if ( (verfp
= popen(command
,"r")) == NULL
)
489 while ( fgets(buf
, BUFSIZ
, verfp
) != NULL
)
490 (void) fputs(buf
,stdout
);
492 /* return the error status of post */
493 return( pclose(verfp
) >> 8 );
500 (void) sprintf(line
, "From: %s <%s>\n", FullName
, from
);
502 (void) sprintf(line
, "From: %s\n", from
);
503 (void) fputs(line
, fp
);
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");
516 adios (NULLCP
, "Problem reading body");
518 if ( fclose(fp
) != 0 )
519 adios (NULLCP
, "problem ending submission");
527 char buf
[BUFSIZ
], response
[BUFSIZ
];
529 if ((sd
= client(NULLCP
, "tcp", "smtp", 0, response
)) == NOTOK
)
530 adios (NULLCP
, "cannot open smtp client process");
532 (void) signal(SIGCHLD
, silentdie
);
534 switch ((childid
= fork())) {
536 adios (NULLCP
, "unable to fork smtp process");
538 case OK
: /* i.e. child */
542 default: /* i.e. parent */
546 while ( (len
= read(0, buf
, BUFSIZ
)) > 0)
547 (void) write (1, buf
, len
);
550 (void) kill(childid
, SIGHUP
);
561 (void) unlink(msgfname
);
564 (void) fprintf(stderr
, "sendmail: dying from signal %d\n", sig
);
570 TYPESIG
silentdie(sig
)
573 pidwait (childid
, OK
);