]>
diplodocus.org Git - nmh/blob - mts/smtp/smtp.c
3 * smtp.c -- nmh SMTP interface
10 #include <zotnet/mts/mts.h>
12 #include <h/signals.h>
20 * This module implements an interface to SendMail very similar
21 * to the MMDF mm_(3) routines. The sm_() routines herein talk
22 * SMTP to a sendmail process, mapping SMTP reply codes into
27 * On older 4.2BSD machines without the POSIX function `sigaction',
28 * the alarm handing stuff for time-outs will NOT work due to the way
29 * syscalls get restarted. This is not really crucial, since SendMail
30 * is generally well-behaved in this area.
35 * It appears that some versions of Sendmail will return Code 451
36 * when they don't really want to indicate a failure.
37 * "Code 451 almost always means sendmail has deferred; we don't
38 * really want bomb out at this point since sendmail will rectify
39 * things later." So, if you define SENDMAILBUG, Code 451 is
40 * considered the same as Code 250. Yuck!
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_debug
= 0;
64 static int sm_nl
= TRUE
;
65 static int sm_verbose
= 0;
67 static FILE *sm_rfp
= NULL
;
68 static FILE *sm_wfp
= NULL
;
71 static int sm_ispool
= 0;
72 static char sm_tmpfil
[BUFSIZ
];
75 static char *sm_noreply
= "No reply text given";
76 static char *sm_moreply
= "; ";
78 struct smtp sm_reply
; /* global... */
84 char *EHLOkeys
[MAXEHLO
+ 1];
89 static int rclient (char *, char *, char *);
90 static int sm_ierror (char *fmt
, ...);
91 static int smtalk (int time
, char *fmt
, ...);
92 static int sm_wrecord (char *, int);
93 static int sm_wstream (char *, int);
94 static int sm_werror (void);
95 static int smhear (void);
96 static int sm_rrecord (char *, int *);
97 static int sm_rerror (void);
98 static RETSIGTYPE
alrmser (int);
99 static char *EHLOset (char *);
103 * smtp.c's own static copy of several nmh library subroutines
105 static char **smail_brkstring (char *, char *, char *);
106 static int smail_brkany (char, char *);
107 char **smail_copyip (char **, char **, int);
110 /* from zotnet/mts/client.c */
111 int client (char *, char *, char *, int, char *, int);
114 sm_init (char *client
, char *server
, int watch
, int verbose
,
115 int debug
, int onex
, int queued
)
117 int result
, sd1
, sd2
;
122 sm_verbose
= verbose
;
130 if (sm_rfp
!= NULL
&& sm_wfp
!= NULL
)
133 if (client
== NULL
|| *client
== '\0') {
137 client
= LocalName(); /* no clientname -> LocalName */
142 if (client
== NULL
|| *client
== '\0')
143 client
= "localhost";
146 if ((sd1
= rclient (server
, "tcp", "smtp")) == NOTOK
)
157 if ((sm_wfp
= fdopen (sd1
, "w")) == NULL
) {
160 return sm_ierror ("unable to fdopen");
163 sm_reply
.text
[sm_reply
.length
= 0] = NULL
;
164 return (sm_reply
.code
= RP_OK
);
168 if ((sd2
= dup (sd1
)) == NOTOK
) {
170 return sm_ierror ("unable to dup");
173 SIGNAL (SIGALRM
, alrmser
);
174 SIGNAL (SIGPIPE
, SIG_IGN
);
176 if ((sm_rfp
= fdopen (sd1
, "r")) == NULL
177 || (sm_wfp
= fdopen (sd2
, "w")) == NULL
) {
180 sm_rfp
= sm_wfp
= NULL
;
181 return sm_ierror ("unable to fdopen");
199 * Give EHLO or HELO command
201 if (client
&& *client
) {
203 result
= smtalk (SM_HELO
, "EHLO %s", client
);
206 if (result
>= 500 && result
<= 599)
207 result
= smtalk (SM_HELO
, "HELO %s", client
);
216 if (watch
&& EHLOset ("XVRB"))
217 smtalk (SM_HELO
, "VERB on");
218 if (onex
&& EHLOset ("XONE"))
219 smtalk (SM_HELO
, "ONEX");
220 if (queued
&& EHLOset ("XQUE"))
221 smtalk (SM_HELO
, "QUED");
228 # define MAXARGS 1000
232 rclient (char *server
, char *protocol
, char *service
)
235 char response
[BUFSIZ
];
240 if ((sd
= client (server
, protocol
, service
, FALSE
, response
, sizeof(response
))) != NOTOK
)
244 if (!server
&& servers
&& (cp
= strchr(servers
, '/'))) {
246 char *arguments
[MAXARGS
];
248 smail_copyip (smail_brkstring (cp
= getcpy (servers
), " ", "\n"), arguments
, MAXARGS
);
250 for (ap
= arguments
; *ap
; ap
++)
254 if ((dp
= strrchr(*ap
, '/')) && *++dp
== NULL
)
256 snprintf (sm_tmpfil
, sizeof(sm_tmpfil
), "%s/smtpXXXXXX", *ap
);
258 sd
= mkstemp (sm_tmpfil
);
262 if ((sd
= creat (sm_tmpfil
, 0600)) != NOTOK
) {
275 sm_ierror ("%s", response
);
281 sm_winit (int mode
, char *from
)
286 if (sm_ispool
&& !sm_wfp
) {
287 strlen (strcpy (sm_reply
.text
, "unable to create new spool file"));
288 sm_reply
.code
= NOTOK
;
311 switch (smtalk (SM_MAIL
, "%s FROM:<%s>", smtpcom
, from
)) {
328 sm_wadr (char *mbox
, char *host
, char *path
)
330 switch (smtalk (SM_RCPT
, host
&& *host
? "RCPT TO:<%s%s@%s>"
332 path
? path
: "", mbox
, host
)) {
342 #endif /* SENDMAILBUG */
367 switch (smtalk (SM_DATA
, "DATA")) {
376 #endif /* SENDMAILBUG */
393 sm_wtxt (char *buffer
, int len
)
399 result
= sm_wstream (buffer
, len
);
402 return (result
== NOTOK
? RP_BHST
: RP_OK
);
409 if (sm_wstream ((char *) NULL
, 0) == NOTOK
)
412 switch (smtalk (SM_DOT
+ 3 * sm_addrs
, ".")) {
420 #endif /* SENDMAILBUG */
438 if (sm_rfp
== NULL
&& sm_wfp
== NULL
)
443 smtalk (SM_QUIT
, "QUIT");
447 sm_note
.code
= sm_reply
.code
;
448 strncpy (sm_note
.text
, sm_reply
.text
, sm_note
.length
= sm_reply
.length
);/* fall */
450 if (smtalk (SM_RSET
, "RSET") == 250 && type
== DONE
)
452 smtalk (SM_QUIT
, "QUIT");
454 sm_reply
.code
= sm_note
.code
;
455 strncpy (sm_reply
.text
, sm_note
.text
, sm_reply
.length
= sm_note
.length
);
472 if (sm_rfp
!= NULL
) {
477 if (sm_wfp
!= NULL
) {
484 sm_rfp
= sm_wfp
= NULL
;
485 return (status
? RP_BHST
: RP_OK
);
494 int cc
, i
, j
, k
, result
;
496 char *dp
, *bp
, *cp
, s
;
497 char buffer
[BUFSIZ
], sender
[BUFSIZ
];
501 k
= strlen (file
) - sizeof(".bulk");
502 if ((fp
= fopen (file
, "r")) == NULL
) {
505 snprintf (sm_reply
.text
, sizeof(sm_reply
.text
),
506 "unable to read %s: ", file
);
510 if ((s
= strerror (errno
)))
511 strncpy (bp
, s
, sizeof(sm_reply
.text
) - len
);
513 snprintf (bp
, sizeof(sm_reply
.text
) - len
, "Error %d", errno
);
514 sm_reply
.length
= strlen (sm_reply
.text
);
515 sm_reply
.code
= NOTOK
;
519 printf ("reading file %s\n", file
);
524 while (fgets (buffer
, sizeof(buffer
), fp
)) {
526 strncpy (sender
, buffer
+ sizeof("MAIL FROM:") - 1, sizeof(sender
));
527 if (strcmp (buffer
, "DATA\r\n") == 0) {
534 printf ("no DATA...\n");
538 snprintf (buffer
, sizeof(buffer
), "%s.bad", file
);
539 rename (file
, buffer
);
541 snprintf (buffer
, sizeof(buffer
), "%*.*sA.bulk", k
, k
, file
);
550 printf ("no %srecipients...\n", j
< 1 ? "sender or " : "");
556 if ((cp
= malloc ((size_t) (cc
= (pos
= ftell (fp
)) + 1))) == NULL
) {
557 sm_reply
.length
= strlen (strcpy (sm_reply
.text
, "out of memory"));
559 sm_reply
.code
= NOTOK
;
563 fseek (fp
, 0L, SEEK_SET
);
564 for (dp
= cp
, i
= 0; i
++ < j
; dp
+= strlen (dp
))
565 if (fgets (dp
, cc
- (dp
- cp
), fp
) == NULL
) {
566 sm_reply
.length
= strlen (strcpy (sm_reply
.text
, "premature eof"));
573 for (dp
= cp
, i
= cc
- 1; i
> 0; dp
+= cc
, i
-= cc
)
574 if ((cc
= write (fileno (sm_wfp
), dp
, i
)) == NOTOK
) {
577 strcpy (sm_reply
.text
, "error writing to server: ",
578 sizeof(sm_reply
.text
));
582 if ((s
= strerror (errno
)))
583 strncpy (bp
, s
, sizeof(sm_reply
.text
) - len
);
585 snprintf (bp
, sizeof(sm_reply
.text
) - len
,
586 "unknown error %d", errno
);
587 sm_reply
.length
= strlen (sm_reply
.text
);
592 printf ("wrote %d octets to server\n", cc
);
596 for (dp
= cp
, i
= 0; i
++ < j
; dp
= strchr(dp
, '\n'), dp
++) {
598 if (bp
= strchr(dp
, '\r'))
600 printf ("=> %s\n", dp
);
606 switch (smhear () + (i
== 1 ? 1000 : i
!= j
? 2000 : 3000)) {
618 smtalk (SM_RSET
, "RSET");
646 if (k
<= 0 || strcmp (sender
, "<>\r\n") == 0)
650 snprintf (buffer
, sizeof(buffer
), "%*.*sA.bulk", k
, k
, file
);
651 if ((gp
= fopen (buffer
, "w+")) == NULL
)
653 fprintf (gp
, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender
);
656 "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n",
657 l
- 4, l
- 4, sender
+ 1, file
);
658 fprintf (gp
, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
659 dtimenow (0), LocalName ());
661 if (bp
= strchr(dp
, '\r'))
663 fprintf (gp
, "=> %s\r\n", dp
);
666 fprintf (gp
, "<= %s\r\n", rp_string (result
));
684 smtalk (SM_RSET
, "RSET");
687 snprintf (buffer
, sizeof(buffer
), "%*.*sA.bulk", k
, k
, file
);
698 smtalk (SM_RSET
, "RSET");
710 #ifdef HAVE_ST_BLKSIZE
713 if (fstat (fileno (sm_wfp
), &st
) == NOTOK
|| (cc
= st
.st_blksize
) < BUFSIZ
)
718 if ((cp
= malloc ((size_t) cc
)) == NULL
) {
719 smtalk (SM_RSET
, "RSET");
720 sm_reply
.length
= strlen (strcpy (sm_reply
.text
, "out of memory"));
725 fseek (fp
, pos
, SEEK_SET
);
729 for (dp
= cp
, i
= cc
; i
> 0; dp
+= j
, i
-= j
)
730 if ((j
= fread (cp
, sizeof(*cp
), i
, fp
)) == OK
) {
734 snprintf (sm_reply
.text
, sizeof(sm_reply
.text
),
735 "error reading %s: ", file
);
739 if ((s
= strerror (errno
)))
740 strncpy (bp
, s
, sizeof(sm_reply
.text
) - len
);
742 snprintf (bp
, sizeof(sm_reply
.text
) - len
,
743 "unknown error %d", errno
);
744 sm_reply
.length
= strlen (sm_reply
.text
);
752 for (dp
= cp
, i
= cc
; i
> 0; dp
+= j
, i
-= j
)
753 if ((j
= write (fileno (sm_wfp
), dp
, i
)) == NOTOK
)
757 printf ("wrote %d octets to server\n", j
);
784 snprintf (buffer
, sizeof(buffer
), "%*.*sA.bulk", k
, k
, file
);
795 if (k
<= 0 || strcmp (sender
, "<>\r\n") == 0) {
801 ftruncate (fileno (gp
), 0L);
802 fseek (gp
, 0L, SEEK_SET
);
805 snprintf (buffer
, sizeof(buffer
), "%*.*sA.bulk", k
, k
, file
);
806 if ((gp
= fopen (buffer
, "w")) == NULL
)
809 fprintf (gp
, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender
);
811 fprintf (gp
, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n",
812 i
- 4, i
- 4, sender
+ 1, file
);
813 fprintf (gp
, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
814 dtimenow (0), LocalName ());
819 fputs ("\r\n------- Begin Returned message\r\n\r\n", gp
);
820 fseek (fp
, pos
, SEEK_SET
);
821 while (fgets (buffer
, sizeof(buffer
), fp
)) {
822 if (buffer
[0] == '-')
824 if (strcmp (buffer
, ".\r\n"))
827 fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp
);
841 sm_ierror (char *fmt
, ...)
846 vsnprintf (sm_reply
.text
, sizeof(sm_reply
.text
), fmt
, ap
);
849 sm_reply
.length
= strlen (sm_reply
.text
);
850 sm_reply
.code
= NOTOK
;
857 smtalk (int time
, char *fmt
, ...)
864 vsnprintf (buffer
, sizeof(buffer
), fmt
, ap
);
868 printf ("=> %s\n", buffer
);
876 if (strcmp (buffer
, ".") == 0)
878 fprintf (sm_wfp
, "%s\r\n", buffer
);
884 snprintf (file
, sizeof(file
), "%s%c.bulk", sm_tmpfil
,
885 (char) (sm_ispool
+ 'a' - 1));
886 if (rename (sm_tmpfil
, file
) == NOTOK
) {
890 snprintf (sm_reply
.text
, sizeof(sm_reply
.text
),
891 "error renaming %s to %s: ", sm_tmpfil
, file
);
895 if ((s
= strerror (errno
)))
896 strncpy (bp
, s
, sizeof(sm_reply
.text
) - len
);
898 snprintf (bp
, sizeof(sm_reply
.text
) - len
,
899 "unknown error %d", errno
);
900 sm_reply
.length
= strlen (sm_reply
.text
);
901 sm_reply
.code
= NOTOK
;
905 if (sm_wfp
= fopen (sm_tmpfil
, "w"))
906 chmod (sm_tmpfil
, 0600);
917 ftruncate (fileno (sm_wfp
), 0L);
918 fseek (sm_wfp
, 0L, SEEK_SET
);
937 printf ("<= %d\n", result
);
941 sm_reply
.text
[sm_reply
.length
= 0] = NULL
;
942 return (sm_reply
.code
= result
);
947 alarm ((unsigned) time
);
948 if ((result
= sm_wrecord (buffer
, strlen (buffer
))) != NOTOK
)
957 * write the buffer to the open SMTP channel
961 sm_wrecord (char *buffer
, int len
)
966 fwrite (buffer
, sizeof(*buffer
), len
, sm_wfp
);
967 fputs ("\r\n", sm_wfp
);
970 return (ferror (sm_wfp
) ? sm_werror () : OK
);
975 sm_wstream (char *buffer
, int len
)
978 static char lc
= '\0';
983 if (buffer
== NULL
&& len
== 0) {
985 fputs ("\r\n", sm_wfp
);
987 return (ferror (sm_wfp
) ? sm_werror () : OK
);
990 for (bp
= buffer
; len
> 0; bp
++, len
--) {
994 fputc ('\r', sm_wfp
);
999 fputc ('.', sm_wfp
);/* FALL THROUGH */
1003 fputc (*bp
, sm_wfp
);
1004 if (ferror (sm_wfp
))
1005 return sm_werror ();
1010 return (ferror (sm_wfp
) ? sm_werror () : OK
);
1015 * On some systems, strlen and strcpy are defined as preprocessor macros. This
1016 * causes compile problems with the #ifdef MPOP in the middle. Should the
1017 * #ifdef MPOP be removed, remove these #undefs.
1030 strlen (strcpy (sm_reply
.text
, sm_wfp
== NULL
? "no socket opened"
1031 : sm_alarmed
? "write to socket timed out"
1033 : sm_ispool
? "error writing to spool file"
1035 : "error writing to socket"));
1037 return (sm_reply
.code
= NOTOK
);
1044 int i
, code
, cont
, bc
, rc
, more
;
1046 char **ehlo
, buffer
[BUFSIZ
];
1049 static int at_least_once
= 0;
1051 if (at_least_once
) {
1054 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1068 sm_reply
.length
= 0;
1069 sm_reply
.text
[0] = 0;
1071 rc
= sizeof(sm_reply
.text
) - 1;
1073 for (more
= FALSE
; sm_rrecord (bp
= buffer
, &bc
) != NOTOK
;) {
1075 printf ("<= %s\n", buffer
);
1080 && strncmp (buffer
, "250", sizeof("250") - 1) == 0
1081 && (buffer
[3] == '-' || doingEHLO
== 2)
1083 if (doingEHLO
== 2) {
1084 if ((*ehlo
= malloc ((size_t) (strlen (buffer
+ 4) + 1)))) {
1085 strcpy (*ehlo
++, buffer
+ 4);
1087 if (ehlo
>= EHLOkeys
+ MAXEHLO
)
1097 for (; bc
> 0 && (!isascii (*bp
) || !isdigit (*bp
)); bp
++, bc
--)
1103 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1105 if (bc
> 0 && *bp
== '-') {
1108 for (; bc
> 0 && isspace (*bp
); bp
++, bc
--)
1113 if (code
!= sm_reply
.code
|| cont
)
1117 sm_reply
.code
= code
;
1120 strncpy (buffer
, sm_noreply
, sizeof(buffer
));
1122 bc
= strlen (sm_noreply
);
1126 if ((i
= min (bc
, rc
)) > 0) {
1127 strncpy (rp
, bp
, i
);
1129 if (more
&& rc
> strlen (sm_moreply
) + 1) {
1130 strcpy (sm_reply
.text
+ rc
, sm_moreply
);
1131 rc
+= strlen (sm_moreply
);
1136 if (sm_reply
.code
< 100) {
1138 printf ("%s\n", sm_reply
.text
);
1144 sm_reply
.length
= rp
- sm_reply
.text
;
1145 return sm_reply
.code
;
1152 sm_rrecord (char *buffer
, int *len
)
1155 return sm_rerror ();
1157 buffer
[*len
= 0] = 0;
1159 fgets (buffer
, BUFSIZ
, sm_rfp
);
1160 *len
= strlen (buffer
);
1161 if (ferror (sm_rfp
) || feof (sm_rfp
))
1162 return sm_rerror ();
1163 if (buffer
[*len
- 1] != '\n')
1164 while (getc (sm_rfp
) != '\n' && !ferror (sm_rfp
) && !feof (sm_rfp
))
1167 if (buffer
[*len
- 2] == '\r')
1169 buffer
[*len
- 1] = 0;
1179 strlen (strcpy (sm_reply
.text
, sm_rfp
== NULL
? "no socket opened"
1180 : sm_alarmed
? "read from socket timed out"
1181 : feof (sm_rfp
) ? "premature end-of-file on socket"
1182 : "error reading from socket"));
1184 return (sm_reply
.code
= NOTOK
);
1191 #ifndef RELIABLE_SIGNALS
1192 SIGNAL (SIGALRM
, alrmser
);
1197 printf ("timed out...\n");
1204 rp_string (int code
)
1207 static char buffer
[BUFSIZ
];
1209 switch (sm_reply
.code
!= NOTOK
? code
: NOTOK
) {
1229 snprintf (buffer
, sizeof(buffer
), "[%s] %s", text
, sm_reply
.text
);
1249 snprintf (buffer
, sizeof(buffer
), "[%s] %3d %s",
1250 text
, sm_reply
.code
, sm_reply
.text
);
1257 static char *broken
[MAXARGS
+ 1];
1260 smail_brkstring (char *strg
, char *brksep
, char *brkterm
)
1267 for (bi
= 0; bi
< MAXARGS
; bi
++) {
1268 while (smail_brkany (c
= *sp
, brksep
))
1270 if (!c
|| smail_brkany (c
, brkterm
)) {
1277 while ((c
= *++sp
) && !smail_brkany (c
, brksep
) && !smail_brkany (c
, brkterm
))
1280 broken
[MAXARGS
] = 0;
1287 * returns 1 if chr in strg, 0 otherwise
1290 smail_brkany (char chr
, char *strg
)
1295 for (sp
= strg
; *sp
; sp
++)
1302 * copy a string array and return pointer to end
1305 smail_copyip (char **p
, char **q
, int len_q
)
1307 while (*p
&& --len_q
> 0)
1326 for (ehlo
= EHLOkeys
; *ehlo
; ehlo
++) {
1328 if (strncmp (ep
, s
, len
) == 0) {
1329 for (ep
+= len
; *ep
== ' '; ep
++)