]>
diplodocus.org Git - nmh/blob - mts/sendmail/sendmail.c
3 * sendmail.c -- nmh sendmail interface
9 #include <mts/smtp/smtp.h>
10 #include <zotnet/mts/mts.h>
12 #include "h/signals.h" /* for SIGNAL() */
18 * This module implements an interface to SendMail very similar
19 * to the MMDF mm_(3) routines. The sm_() routines herein talk
20 * SMTP to a sendmail process, mapping SMTP reply codes into
25 * On older 4.2BSD machines without the POSIX function `sigaction',
26 * the alarm handing stuff for time-outs will NOT work due to the way
27 * syscalls get restarted. This is not really crucial, since SendMail
28 * is generally well-behaved in this area.
33 * It appears that some versions of Sendmail will return Code 451
34 * when they don't really want to indicate a failure.
35 * "Code 451 almost always means sendmail has deferred; we don't
36 * really want bomb out at this point since sendmail will rectify
37 * things later." So, if you define SENDMAILBUG, Code 451 is
38 * considered the same as Code 250. Yuck!
45 #define NBITS ((sizeof (int)) * 8)
48 * these codes must all be different!
50 #define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */
61 static int sm_addrs
= 0;
62 static int sm_alarmed
= 0;
63 static int sm_child
= NOTOK
;
64 static int sm_debug
= 0;
65 static int sm_nl
= TRUE
;
66 static int sm_verbose
= 0;
68 static FILE *sm_rfp
= NULL
;
69 static FILE *sm_wfp
= NULL
;
72 static int sm_ispool
= 0;
73 static char sm_tmpfil
[BUFSIZ
];
76 static char *sm_noreply
= "No reply text given";
77 static char *sm_moreply
= "; ";
79 struct smtp sm_reply
; /* global... */
84 char *EHLOkeys
[MAXEHLO
+ 1];
89 static int sm_ierror (char *fmt
, ...);
90 static int smtalk (int time
, char *fmt
, ...);
91 static int sm_wrecord (char *, int);
92 static int sm_wstream (char *, int);
93 static int sm_werror (void);
94 static int smhear (void);
95 static int sm_rrecord (char *, int *);
96 static int sm_rerror (void);
97 static RETSIGTYPE
alrmser (int);
101 sm_init (char *client
, char *server
, int watch
, int verbose
,
102 int debug
, int onex
, int queued
, int sasl
, char *saslmech
, char *user
)
111 sm_verbose
= verbose
;
113 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
116 if (client
== NULL
|| *client
== '\0') {
120 client
= LocalName(); /* no clientname -> LocalName */
124 return sm_ierror("SASL authentication not supported with the "
128 if (client
== NULL
|| *client
== '\0')
129 client
= "localhost";
132 if (pipe (pdi
) == NOTOK
)
133 return sm_ierror ("no pipes");
134 if (pipe (pdo
) == NOTOK
) {
137 return sm_ierror ("no pipes");
140 for (i
= 0; (sm_child
= fork ()) == NOTOK
&& i
< 5; i
++)
149 return sm_ierror ("unable to fork");
152 if (pdo
[0] != fileno (stdin
))
153 dup2 (pdo
[0], fileno (stdin
));
154 if (pdi
[1] != fileno (stdout
))
155 dup2 (pdi
[1], fileno (stdout
));
156 if (pdi
[1] != fileno (stderr
))
157 dup2 (pdi
[1], fileno (stderr
));
158 for (i
= fileno (stderr
) + 1; i
< NBITS
; i
++)
162 vec
[vecp
++] = r1bindex (sendmail
, '/');
165 vec
[vecp
++] = watch
? "-odi" : queued
? "-odq" : "-odb";
166 vec
[vecp
++] = "-oem";
171 # endif /* not RAND */
172 #endif /* not ZMAILER */
177 execvp (sendmail
, vec
);
178 fprintf (stderr
, "unable to exec ");
180 _exit (-1); /* NOTREACHED */
183 SIGNAL (SIGALRM
, alrmser
);
184 SIGNAL (SIGPIPE
, SIG_IGN
);
188 if ((sm_rfp
= fdopen (pdi
[0], "r")) == NULL
189 || (sm_wfp
= fdopen (pdo
[1], "w")) == NULL
) {
192 sm_rfp
= sm_wfp
= NULL
;
193 return sm_ierror ("unable to fdopen");
208 if (client
&& *client
) {
210 result
= smtalk (SM_HELO
, "EHLO %s", client
);
213 if (500 <= result
&& result
<= 599)
214 result
= smtalk (SM_HELO
, "HELO %s", client
);
228 smtalk (SM_HELO
, "ONEX");
231 smtalk (SM_HELO
, "VERB on");
239 sm_winit (int mode
, char *from
)
242 if (sm_ispool
&& !sm_wfp
) {
243 strlen (strcpy (sm_reply
.text
, "unable to create new spool file"));
244 sm_reply
.code
= NOTOK
;
249 switch (smtalk (SM_MAIL
, "%s FROM:<%s>",
250 mode
== S_SEND
? "SEND" : mode
== S_SOML
? "SOML"
251 : mode
== S_SAML
? "SAML" : "MAIL", from
)) {
268 sm_wadr (char *mbox
, char *host
, char *path
)
270 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
272 path
? path
: "", mbox
, host
)) {
282 #endif /* SENDMAILBUG */
307 switch (smtalk (SM_DATA
, "DATA")) {
316 #endif /* SENDMAILBUG */
333 sm_wtxt (char *buffer
, int len
)
339 result
= sm_wstream (buffer
, len
);
342 return (result
== NOTOK
? RP_BHST
: RP_OK
);
349 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
352 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
360 #endif /* SENDMAILBUG */
387 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
392 smtalk (SM_QUIT
, "QUIT");
396 sm_note
.code
= sm_reply
.code
;
397 strncpy (sm_note
.text
, sm_reply
.text
, sm_note
.length
= sm_reply
.length
);/* fall */
399 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
401 kill (sm_child
, SIGKILL
);
405 sm_reply
.code
= sm_note
.code
;
406 strncpy (sm_reply
.text
, sm_note
.text
, sm_reply
.length
= sm_note
.length
);
410 if (sm_rfp
!= NULL
) {
415 if (sm_wfp
!= NULL
) {
421 status
= pidwait (sm_child
, OK
);
424 sm_rfp
= sm_wfp
= NULL
;
426 return (status
? RP_BHST
: RP_OK
);
431 sm_ierror (char *fmt
, ...)
436 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
439 sm_reply
.length
= strlen (sm_reply
.text
);
440 sm_reply
.code
= NOTOK
;
447 smtalk (int time
, char *fmt
, ...)
454 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
458 printf ("=> %s\n", buffer
);
466 if (strcmp (buffer
, ".") == 0)
468 fprintf (sm_wfp
, "%s\r\n", buffer
);
474 snprintf (file
, sizeof(file
), "%s%c.bulk", sm_tmpfil
,
475 (char) (sm_ispool
+ 'a' - 1));
476 if (rename (sm_tmpfil
, file
) == NOTOK
) {
480 snprintf (sm_reply
.text
, sizeof(sm_reply
.text
),
481 "error renaming %s to %s: ", sm_tmpfil
, file
);
485 if ((s
= strerror (errno
)))
486 strncpy (bp
, s
, sizeof(sm_reply
.text
) - len
);
488 snprintf (bp
, sizeof(sm_reply
.text
) - len
,
489 "unknown error %d", errno
);
490 sm_reply
.length
= strlen (sm_reply
.text
);
491 sm_reply
.code
= NOTOK
;
495 if (sm_wfp
= fopen (sm_tmpfil
, "w"))
496 chmod (sm_tmpfil
, 0600);
507 ftruncate (fileno (sm_wfp
), 0L);
508 fseek (sm_wfp
, 0L, SEEK_SET
);
527 printf ("<= %d\n", result
);
531 sm_reply
.text
[sm_reply
.length
= 0] = NULL
;
532 return (sm_reply
.code
= result
);
537 alarm ((unsigned) time
);
538 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
547 sm_wrecord (char *buffer
, int len
)
552 fwrite (buffer
, sizeof *buffer
, len
, sm_wfp
);
553 fputs ("\r\n", sm_wfp
);
556 return (ferror (sm_wfp
) ? sm_werror () : OK
);
561 sm_wstream (char *buffer
, int len
)
569 if (buffer
== NULL
&& len
== 0) {
571 fputs ("\r\n", sm_wfp
);
573 return (ferror (sm_wfp
) ? sm_werror () : OK
);
576 for (bp
= buffer
; len
> 0; bp
++, len
--) {
580 fputc ('\r', sm_wfp
);
585 fputc ('.', sm_wfp
);/* FALL THROUGH */
596 return (ferror (sm_wfp
) ? sm_werror () : OK
);
602 * AIX by default will inline the strlen and strcpy commands by redefining
603 * them as __strlen and __strcpy respectively. This causes compile problems
604 * with the #ifdef MPOP in the middle. Should the #ifdef MPOP be removed,
605 * remove these #undefs.
615 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no pipe opened"
616 : sm_alarmed
? "write to pipe timed out"
617 : "error writing to pipe"));
619 return (sm_reply
.code
= NOTOK
);
626 int i
, code
, cont
, bc
, rc
, more
;
628 char **ehlo
, buffer
[BUFSIZ
];
631 static int at_least_once
= 0;
634 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++)
640 *(ehlo
= EHLOkeys
) = NULL
;
645 sm_reply
.text
[sm_reply
.length
= 0] = 0;
648 rc
= sizeof(sm_reply
.text
) - 1;
650 for (more
= FALSE
; sm_rrecord (bp
= buffer
, &bc
) != NOTOK
;) {
652 printf ("<= %s\n", buffer
);
657 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
658 && (buffer
[3] == '-' || doingEHLO
== 2)
660 if (doingEHLO
== 2) {
661 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
662 strcpy (*ehlo
++, buffer
+ 4);
664 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
674 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
680 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
682 if (bc
> 0 && *bp
== '-') {
685 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
690 if (code
!= sm_reply
.code
|| cont
)
694 sm_reply
.code
= code
;
697 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
699 bc
= strlen (sm_noreply
);
702 if ((i
= min (bc
, rc
)) > 0) {
706 if (more
&& rc
> strlen (sm_moreply
) + 1) {
707 strncpy (sm_reply
.text
+ rc
, sm_moreply
, sizeof(sm_reply
.text
) - rc
);
708 rc
+= strlen (sm_moreply
);
713 if (sm_reply
.code
< 100) {
715 printf ("%s\n", sm_reply
.text
);
721 sm_reply
.length
= rp
- sm_reply
.text
;
723 return sm_reply
.code
;
731 sm_rrecord (char *buffer
, int *len
)
736 buffer
[*len
= 0] = 0;
738 fgets (buffer
, BUFSIZ
, sm_rfp
);
739 *len
= strlen (buffer
);
740 if (ferror (sm_rfp
) || feof (sm_rfp
))
742 if (buffer
[*len
- 1] != '\n')
743 while (getc (sm_rfp
) != '\n' && !ferror (sm_rfp
) && !feof (sm_rfp
))
746 if (buffer
[*len
- 2] == '\r')
748 buffer
[*len
- 1] = 0;
758 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no pipe opened"
759 : sm_alarmed
? "read from pipe timed out"
760 : feof (sm_rfp
) ? "premature end-of-file on pipe"
761 : "error reading from pipe"));
763 return (sm_reply
.code
= NOTOK
);
770 #ifndef RELIABLE_SIGNALS
771 SIGNAL (SIGALRM
, alrmser
);
776 printf ("timed out...\n");
786 static char buffer
[BUFSIZ
];
788 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
808 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
828 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
829 text
, sm_reply
.code
, sm_reply
.text
);