]> diplodocus.org Git - nmh/blob - mts/smtp/smtp.c
f7756381d2df2aae2858534215fa9ab575f9d79b
[nmh] / mts / smtp / smtp.c
1
2 /*
3 * smtp.c -- nmh SMTP interface
4 *
5 * $Id$
6 */
7
8 #include <h/mh.h>
9 #include "smtp.h"
10 #include <zotnet/mts/mts.h>
11 #include <signal.h>
12
13 /*
14 * This module implements an interface to SendMail very similar
15 * to the MMDF mm_(3) routines. The sm_() routines herein talk
16 * SMTP to a sendmail process, mapping SMTP reply codes into
17 * RP_-style codes.
18 */
19
20 /*
21 * On older 4.2BSD machines without the POSIX function `sigaction',
22 * the alarm handing stuff for time-outs will NOT work due to the way
23 * syscalls get restarted. This is not really crucial, since SendMail
24 * is generally well-behaved in this area.
25 */
26
27 #ifdef SENDMAILBUG
28 /*
29 * It appears that some versions of Sendmail will return Code 451
30 * when they don't really want to indicate a failure.
31 * "Code 451 almost always means sendmail has deferred; we don't
32 * really want bomb out at this point since sendmail will rectify
33 * things later." So, if you define SENDMAILBUG, Code 451 is
34 * considered the same as Code 250. Yuck!
35 */
36 #endif
37
38 #define TRUE 1
39 #define FALSE 0
40
41 /*
42 * these codes must all be different!
43 */
44 #define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */
45 #define SM_HELO 20
46 #define SM_RSET 15
47 #define SM_MAIL 40
48 #define SM_RCPT 120
49 #define SM_DATA 20
50 #define SM_TEXT 150
51 #define SM_DOT 180
52 #define SM_QUIT 30
53 #define SM_CLOS 10
54
55 static int sm_addrs = 0;
56 static int sm_alarmed = 0;
57 static int sm_debug = 0;
58 static int sm_nl = TRUE;
59 static int sm_verbose = 0;
60
61 static FILE *sm_rfp = NULL;
62 static FILE *sm_wfp = NULL;
63
64 #ifdef MPOP
65 static int sm_ispool = 0;
66 static char sm_tmpfil[BUFSIZ];
67 #endif /* MPOP */
68
69 static char *sm_noreply = "No reply text given";
70 static char *sm_moreply = "; ";
71
72 struct smtp sm_reply; /* global... */
73
74 #ifdef MPOP
75 extern int errno;
76 #endif
77
78
79 #define MAXEHLO 20
80
81 static int doingEHLO;
82 char *EHLOkeys[MAXEHLO + 1];
83
84 /*
85 * static prototypes
86 */
87 static int rclient (char *, char *, char *);
88 static int sm_ierror (char *fmt, ...);
89 static int smtalk (int time, char *fmt, ...);
90 static int sm_wrecord (char *, int);
91 static int sm_wstream (char *, int);
92 static int sm_werror (void);
93 static int smhear (void);
94 static int sm_rrecord (char *, int *);
95 static int sm_rerror (void);
96 static RETSIGTYPE alrmser (int);
97 static char *EHLOset (char *);
98
99 #ifdef MPOP
100 /*
101 * smtp.c's own static copy of several nmh library subroutines
102 */
103 static char **smail_brkstring (char *, char *, char *);
104 static int smail_brkany (char, char *);
105 char **smail_copyip (char **, char **, int);
106 #endif
107
108
109 int
110 sm_init (char *client, char *server, int watch, int verbose,
111 int debug, int onex, int queued)
112 {
113 int result, sd1, sd2;
114
115 if (watch)
116 verbose = TRUE;
117
118 sm_verbose = verbose;
119 sm_debug = debug;
120
121 #ifdef MPOP
122 if (sm_ispool)
123 goto all_done;
124 #endif
125
126 if (sm_rfp != NULL && sm_wfp != NULL)
127 goto send_options;
128
129 if (client == NULL || *client == '\0')
130 if (clientname)
131 client = clientname;
132 else
133 client = LocalName(); /* no clientname -> LocalName */
134
135 #ifdef ZMAILER
136 if (client == NULL || *client == '\0')
137 client = "localhost";
138 #endif
139
140 if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK)
141 return RP_BHST;
142
143 #ifdef MPOP
144 if (sm_ispool) {
145 if (sm_rfp) {
146 alarm (SM_CLOS);
147 fclose (sm_rfp);
148 alarm (0);
149 sm_rfp = NULL;
150 }
151 if ((sm_wfp = fdopen (sd1, "w")) == NULL) {
152 unlink (sm_tmpfil);
153 close (sd1);
154 return sm_ierror ("unable to fdopen");
155 }
156 all_done: ;
157 sm_reply.text[sm_reply.length = 0] = NULL;
158 return (sm_reply.code = RP_OK);
159 }
160 #endif /* MPOP */
161
162 if ((sd2 = dup (sd1)) == NOTOK) {
163 close (sd1);
164 return sm_ierror ("unable to dup");
165 }
166
167 SIGNAL (SIGALRM, alrmser);
168 SIGNAL (SIGPIPE, SIG_IGN);
169
170 if ((sm_rfp = fdopen (sd1, "r")) == NULL
171 || (sm_wfp = fdopen (sd2, "w")) == NULL) {
172 close (sd1);
173 close (sd2);
174 sm_rfp = sm_wfp = NULL;
175 return sm_ierror ("unable to fdopen");
176 }
177
178 sm_alarmed = 0;
179 alarm (SM_OPEN);
180 result = smhear ();
181 alarm (0);
182
183 switch (result) {
184 case 220:
185 break;
186
187 default:
188 sm_end (NOTOK);
189 return RP_RPLY;
190 }
191
192 /*
193 * Give EHLO or HELO command
194 */
195 if (client && *client) {
196 doingEHLO = 1;
197 result = smtalk (SM_HELO, "EHLO %s", client);
198 doingEHLO = 0;
199
200 if (result >= 500 && result <= 599)
201 result = smtalk (SM_HELO, "HELO %s", client);
202
203 if (result != 250) {
204 sm_end (NOTOK);
205 return RP_RPLY;
206 }
207 }
208
209 send_options: ;
210 if (watch && EHLOset ("XVRB"))
211 smtalk (SM_HELO, "VERB on");
212 if (onex && EHLOset ("XONE"))
213 smtalk (SM_HELO, "ONEX");
214 if (queued && EHLOset ("XQUE"))
215 smtalk (SM_HELO, "QUED");
216
217 return RP_OK;
218 }
219
220
221 #ifdef MPOP
222 # define MAXARGS 1000
223 #endif /* MPOP */
224
225 static int
226 rclient (char *server, char *protocol, char *service)
227 {
228 int sd;
229 char response[BUFSIZ];
230 #ifdef MPOP
231 char *cp;
232 #endif /* MPOP */
233
234 if ((sd = client (server, protocol, service, FALSE, response, sizeof(response))) != NOTOK)
235 return sd;
236
237 #ifdef MPOP
238 if (!server && servers && (cp = strchr(servers, '/'))) {
239 char **ap;
240 char *arguments[MAXARGS];
241
242 smail_copyip (smail_brkstring (cp = getcpy (servers), " ", "\n"), arguments, MAXARGS);
243
244 for (ap = arguments; *ap; ap++)
245 if (**ap == '/') {
246 char *dp;
247
248 if ((dp = strrchr(*ap, '/')) && *++dp == NULL)
249 *--dp = NULL;
250 snprintf (sm_tmpfil, sizeof(sm_tmpfil), "%s/smtpXXXXXX", *ap);
251 mktemp (sm_tmpfil);
252
253 if ((sd = creat (sm_tmpfil, 0600)) != NOTOK) {
254 sm_ispool = 1;
255 break;
256 }
257 }
258
259 free (cp);
260 if (sd != NOTOK)
261 return sd;
262 }
263 #endif /* MPOP */
264
265 sm_ierror ("%s", response);
266 return NOTOK;
267 }
268
269
270 int
271 sm_winit (int mode, char *from)
272 {
273 char *smtpcom;
274
275 #ifdef MPOP
276 if (sm_ispool && !sm_wfp) {
277 strlen (strcpy (sm_reply.text, "unable to create new spool file"));
278 sm_reply.code = NOTOK;
279 return RP_BHST;
280 }
281 #endif /* MPOP */
282
283 switch (mode) {
284 case S_MAIL:
285 smtpcom = "MAIL";
286 break;
287
288 case S_SEND:
289 smtpcom = "SEND";
290 break;
291
292 case S_SOML:
293 smtpcom = "SOML";
294 break;
295
296 case S_SAML:
297 smtpcom = "SAML";
298 break;
299 }
300
301 switch (smtalk (SM_MAIL, "%s FROM:<%s>", smtpcom, from)) {
302 case 250:
303 sm_addrs = 0;
304 return RP_OK;
305
306 case 500:
307 case 501:
308 case 552:
309 return RP_PARM;
310
311 default:
312 return RP_RPLY;
313 }
314 }
315
316
317 int
318 sm_wadr (char *mbox, char *host, char *path)
319 {
320 switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@%s>"
321 : "RCPT TO:<%s%s>",
322 path ? path : "", mbox, host)) {
323 case 250:
324 case 251:
325 sm_addrs++;
326 return RP_OK;
327
328 case 451:
329 #ifdef SENDMAILBUG
330 sm_addrs++;
331 return RP_OK;
332 #endif /* SENDMAILBUG */
333 case 421:
334 case 450:
335 case 452:
336 return RP_NO;
337
338 case 500:
339 case 501:
340 return RP_PARM;
341
342 case 550:
343 case 551:
344 case 552:
345 case 553:
346 return RP_USER;
347
348 default:
349 return RP_RPLY;
350 }
351 }
352
353
354 int
355 sm_waend (void)
356 {
357 switch (smtalk (SM_DATA, "DATA")) {
358 case 354:
359 sm_nl = TRUE;
360 return RP_OK;
361
362 case 451:
363 #ifdef SENDMAILBUG
364 sm_nl = TRUE;
365 return RP_OK;
366 #endif /* SENDMAILBUG */
367 case 421:
368 return RP_NO;
369
370 case 500:
371 case 501:
372 case 503:
373 case 554:
374 return RP_NDEL;
375
376 default:
377 return RP_RPLY;
378 }
379 }
380
381
382 int
383 sm_wtxt (char *buffer, int len)
384 {
385 int result;
386
387 sm_alarmed = 0;
388 alarm (SM_TEXT);
389 result = sm_wstream (buffer, len);
390 alarm (0);
391
392 return (result == NOTOK ? RP_BHST : RP_OK);
393 }
394
395
396 int
397 sm_wtend (void)
398 {
399 if (sm_wstream ((char *) NULL, 0) == NOTOK)
400 return RP_BHST;
401
402 switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) {
403 case 250:
404 case 251:
405 return RP_OK;
406
407 case 451:
408 #ifdef SENDMAILBUG
409 return RP_OK;
410 #endif /* SENDMAILBUG */
411 case 452:
412 default:
413 return RP_NO;
414
415 case 552:
416 case 554:
417 return RP_NDEL;
418 }
419 }
420
421
422 int
423 sm_end (int type)
424 {
425 int status;
426 struct smtp sm_note;
427
428 if (sm_rfp == NULL && sm_wfp == NULL)
429 return RP_OK;
430
431 switch (type) {
432 case OK:
433 smtalk (SM_QUIT, "QUIT");
434 break;
435
436 case NOTOK:
437 sm_note.code = sm_reply.code;
438 strncpy (sm_note.text, sm_reply.text, sm_note.length = sm_reply.length);/* fall */
439 case DONE:
440 if (smtalk (SM_RSET, "RSET") == 250 && type == DONE)
441 return RP_OK;
442 smtalk (SM_QUIT, "QUIT");
443 if (type == NOTOK) {
444 sm_reply.code = sm_note.code;
445 strncpy (sm_reply.text, sm_note.text, sm_reply.length = sm_note.length);
446 }
447 break;
448 }
449
450 #ifdef MPOP
451 if (sm_ispool) {
452 sm_ispool = 0;
453
454 if (sm_wfp) {
455 unlink (sm_tmpfil);
456 fclose (sm_wfp);
457 sm_wfp = NULL;
458 }
459 }
460 #endif /* MPOP */
461
462 if (sm_rfp != NULL) {
463 alarm (SM_CLOS);
464 fclose (sm_rfp);
465 alarm (0);
466 }
467 if (sm_wfp != NULL) {
468 alarm (SM_CLOS);
469 fclose (sm_wfp);
470 alarm (0);
471 }
472
473 status = 0;
474 sm_rfp = sm_wfp = NULL;
475 return (status ? RP_BHST : RP_OK);
476 }
477
478
479 #ifdef MPOP
480
481 int
482 sm_bulk (char *file)
483 {
484 int cc, i, j, k, result;
485 long pos;
486 char *dp, *bp, *cp, s;
487 char buffer[BUFSIZ], sender[BUFSIZ];
488 FILE *fp, *gp;
489
490 gp = NULL;
491 k = strlen (file) - sizeof(".bulk");
492 if ((fp = fopen (file, "r")) == NULL) {
493 int len;
494
495 snprintf (sm_reply.text, sizeof(sm_reply.text),
496 "unable to read %s: ", file);
497 bp = sm_reply.text;
498 len = strlen (bp);
499 bp += len;
500 if ((s = strerror (errno)))
501 strncpy (bp, s, sizeof(sm_reply.text) - len);
502 else
503 snprintf (bp, sizeof(sm_reply.text) - len, "Error %d", errno);
504 sm_reply.length = strlen (sm_reply.text);
505 sm_reply.code = NOTOK;
506 return RP_BHST;
507 }
508 if (sm_debug) {
509 printf ("reading file %s\n", file);
510 fflush (stdout);
511 }
512
513 i = j = 0;
514 while (fgets (buffer, sizeof(buffer), fp)) {
515 if (j++ == 0)
516 strncpy (sender, buffer + sizeof("MAIL FROM:") - 1, sizeof(sender));
517 if (strcmp (buffer, "DATA\r\n") == 0) {
518 i = 1;
519 break;
520 }
521 }
522 if (i == 0) {
523 if (sm_debug) {
524 printf ("no DATA...\n");
525 fflush (stdout);
526 }
527 losing0:
528 snprintf (buffer, sizeof(buffer), "%s.bad", file);
529 rename (file, buffer);
530 if (gp) {
531 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
532 unlink (buffer);
533 fclose (gp);
534 }
535 fclose (fp);
536 return RP_OK;
537 }
538 if (j < 3) {
539 if (sm_debug) {
540 printf ("no %srecipients...\n", j < 1 ? "sender or " : "");
541 fflush (stdout);
542 }
543 goto losing0;
544 }
545
546 if ((cp = malloc ((size_t) (cc = (pos = ftell (fp)) + 1))) == NULL) {
547 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
548 losing1: ;
549 sm_reply.code = NOTOK;
550 fclose (fp);
551 return RP_BHST;
552 }
553 fseek (fp, 0L, SEEK_SET);
554 for (dp = cp, i = 0; i++ < j; dp += strlen (dp))
555 if (fgets (dp, cc - (dp - cp), fp) == NULL) {
556 sm_reply.length = strlen (strcpy (sm_reply.text, "premature eof"));
557 losing2:
558 free (cp);
559 goto losing1;
560 }
561 *dp = NULL;
562
563 for (dp = cp, i = cc - 1; i > 0; dp += cc, i -= cc)
564 if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) {
565 int len;
566 losing3:
567 strcpy (sm_reply.text, "error writing to server: ",
568 sizeof(sm_reply.text));
569 bp = sm_reply.text;
570 len = strlen (bp);
571 bp += len;
572 if ((s = strerror (errno)))
573 strncpy (bp, s, sizeof(sm_reply.text) - len);
574 else
575 snprintf (bp, sizeof(sm_reply.text) - len,
576 "unknown error %d", errno);
577 sm_reply.length = strlen (sm_reply.text);
578 goto losing2;
579 }
580 else
581 if (sm_debug) {
582 printf ("wrote %d octets to server\n", cc);
583 fflush (stdout);
584 }
585
586 for (dp = cp, i = 0; i++ < j; dp = strchr(dp, '\n'), dp++) {
587 if (sm_debug) {
588 if (bp = strchr(dp, '\r'))
589 *bp = NULL;
590 printf ("=> %s\n", dp);
591 fflush (stdout);
592 if (bp)
593 *bp = '\r';
594 }
595
596 switch (smhear () + (i == 1 ? 1000 : i != j ? 2000 : 3000)) {
597 case 1000 + 250:
598 sm_addrs = 0;
599 result = RP_OK;
600 break;
601
602 case 1000 + 500:
603 case 1000 + 501:
604 case 1000 + 552:
605 case 2000 + 500:
606 case 2000 + 501:
607 result = RP_PARM;
608 smtalk (SM_RSET, "RSET");
609 free (cp);
610 goto losing0;
611
612 case 2000 + 250:
613 case 2000 + 251:
614 sm_addrs++;
615 result = RP_OK;
616 break;
617
618 case 2000 + 451:
619 #ifdef SENDMAILBUG
620 sm_addrs++;
621 result = RP_OK;
622 break;
623 #endif
624 case 2000 + 421:
625 case 2000 + 450:
626 case 2000 + 452:
627 result = RP_NO;
628 goto bad_addr;
629
630 case 2000 + 550:
631 case 2000 + 551:
632 case 2000 + 552:
633 case 2000 + 553:
634 result = RP_USER;
635 bad_addr:
636 if (k <= 0 || strcmp (sender, "<>\r\n") == 0)
637 break;
638 if (gp == NULL) {
639 int l;
640 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
641 if ((gp = fopen (buffer, "w+")) == NULL)
642 goto bad_data;
643 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
644 l = strlen (sender);
645 fprintf (gp,
646 "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n",
647 l - 4, l - 4, sender + 1, file);
648 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
649 dtimenow (0), LocalName ());
650 }
651 if (bp = strchr(dp, '\r'))
652 *bp = NULL;
653 fprintf (gp, "=> %s\r\n", dp);
654 if (bp)
655 *bp = '\r';
656 fprintf (gp, "<= %s\r\n", rp_string (result));
657 fflush (gp);
658 break;
659
660 case 3000 + 354:
661 #ifdef SENDMAILBUG
662 ok_data:
663 #endif
664 result = RP_OK;
665 break;
666
667 case 3000 + 451:
668 #ifdef SENDMAILBUG
669 goto ok_data;
670 #endif
671 case 3000 + 421:
672 result = RP_NO;
673 bad_data:
674 smtalk (SM_RSET, "RSET");
675 free (cp);
676 if (gp) {
677 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
678 unlink (buffer);
679 fclose (gp);
680 }
681 fclose (fp);
682 return result;
683
684 case 3000 + 500:
685 case 3000 + 501:
686 case 3000 + 503:
687 case 3000 + 554:
688 smtalk (SM_RSET, "RSET");
689 free (cp);
690 goto no_dice;
691
692 default:
693 result = RP_RPLY;
694 goto bad_data;
695 }
696 }
697 free (cp);
698
699 {
700 #ifdef HAVE_ST_BLKSIZE
701 struct stat st;
702
703 if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ)
704 cc = BUFSIZ;
705 #else
706 cc = BUFSIZ;
707 #endif
708 if ((cp = malloc ((size_t) cc)) == NULL) {
709 smtalk (SM_RSET, "RSET");
710 sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory"));
711 goto losing1;
712 }
713 }
714
715 fseek (fp, pos, SEEK_SET);
716 for (;;) {
717 int eof = 0;
718
719 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
720 if ((j = fread (cp, sizeof(*cp), i, fp)) == OK) {
721 if (ferror (fp)) {
722 int len;
723
724 snprintf (sm_reply.text, sizeof(sm_reply.text),
725 "error reading %s: ", file);
726 bp = sm_reply.text;
727 len = strlen (bp);
728 bp += len;
729 if ((s = strerror (errno)))
730 strncpy (bp, s, sizeof(sm_reply.text) - len);
731 else
732 snprintf (bp, sizeof(sm_reply.text) - len,
733 "unknown error %d", errno);
734 sm_reply.length = strlen (sm_reply.text);
735 goto losing2;
736 }
737 cc = dp - cp;
738 eof = 1;
739 break;
740 }
741
742 for (dp = cp, i = cc; i > 0; dp += j, i -= j)
743 if ((j = write (fileno (sm_wfp), dp, i)) == NOTOK)
744 goto losing3;
745 else
746 if (sm_debug) {
747 printf ("wrote %d octets to server\n", j);
748 fflush (stdout);
749 }
750
751 if (eof)
752 break;
753 }
754 free (cp);
755
756 switch (smhear ()) {
757 case 250:
758 case 251:
759 #ifdef SENDMAILBUG
760 ok_dot:
761 #endif
762 result = RP_OK;
763 unlink (file);
764 break;
765
766 case 451:
767 #ifdef SENDMAILBUG
768 goto ok_dot;
769 #endif
770 case 452:
771 default:
772 result = RP_NO;
773 if (gp) {
774 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
775 unlink (buffer);
776 fclose (gp);
777 gp = NULL;
778 }
779 break;
780
781 case 552:
782 case 554:
783 no_dice:
784 result = RP_NDEL;
785 if (k <= 0 || strcmp (sender, "<>\r\n") == 0) {
786 unlink (file);
787 break;
788 }
789 if (gp) {
790 fflush (gp);
791 ftruncate (fileno (gp), 0L);
792 fseek (gp, 0L, SEEK_SET);
793 }
794 else {
795 snprintf (buffer, sizeof(buffer), "%*.*sA.bulk", k, k, file);
796 if ((gp = fopen (buffer, "w")) == NULL)
797 break;
798 }
799 fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender);
800 i = strlen (sender);
801 fprintf (gp, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n",
802 i - 4, i - 4, sender + 1, file);
803 fprintf (gp, "Date: %s\r\nFrom: Postmaster@%s\r\n\r\n",
804 dtimenow (0), LocalName ());
805 break;
806 }
807
808 if (gp) {
809 fputs ("\r\n------- Begin Returned message\r\n\r\n", gp);
810 fseek (fp, pos, SEEK_SET);
811 while (fgets (buffer, sizeof(buffer), fp)) {
812 if (buffer[0] == '-')
813 fputs ("- ", gp);
814 if (strcmp (buffer, ".\r\n"))
815 fputs (buffer, gp);
816 }
817 fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp);
818 fflush (gp);
819 if (!ferror (gp))
820 unlink (file);
821 fclose (gp);
822 }
823 fclose (fp);
824
825 return result;
826 }
827 #endif /* MPOP */
828
829
830 static int
831 sm_ierror (char *fmt, ...)
832 {
833 va_list ap;
834
835 va_start(ap, fmt);
836 vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap);
837 va_end(ap);
838
839 sm_reply.length = strlen (sm_reply.text);
840 sm_reply.code = NOTOK;
841
842 return RP_BHST;
843 }
844
845
846 static int
847 smtalk (int time, char *fmt, ...)
848 {
849 va_list ap;
850 int result;
851 char buffer[BUFSIZ];
852
853 va_start(ap, fmt);
854 vsnprintf (buffer, sizeof(buffer), fmt, ap);
855 va_end(ap);
856
857 if (sm_debug) {
858 printf ("=> %s\n", buffer);
859 fflush (stdout);
860 }
861
862 #ifdef MPOP
863 if (sm_ispool) {
864 char file[BUFSIZ];
865
866 if (strcmp (buffer, ".") == 0)
867 time = SM_DOT;
868 fprintf (sm_wfp, "%s\r\n", buffer);
869 switch (time) {
870 case SM_DOT:
871 fflush (sm_wfp);
872 if (ferror (sm_wfp))
873 return sm_werror ();
874 snprintf (file, sizeof(file), "%s%c.bulk", sm_tmpfil,
875 (char) (sm_ispool + 'a' - 1));
876 if (rename (sm_tmpfil, file) == NOTOK) {
877 int len;
878 char *bp;
879
880 snprintf (sm_reply.text, sizeof(sm_reply.text),
881 "error renaming %s to %s: ", sm_tmpfil, file);
882 bp = sm_reply.text;
883 len = strlen (bp);
884 bp += len;
885 if ((s = strerror (errno)))
886 strncpy (bp, s, sizeof(sm_reply.text) - len);
887 else
888 snprintf (bp, sizeof(sm_reply.text) - len,
889 "unknown error %d", errno);
890 sm_reply.length = strlen (sm_reply.text);
891 sm_reply.code = NOTOK;
892 return RP_BHST;
893 }
894 fclose (sm_wfp);
895 if (sm_wfp = fopen (sm_tmpfil, "w"))
896 chmod (sm_tmpfil, 0600);
897 sm_ispool++;
898 /* and fall... */
899
900 case SM_MAIL:
901 case SM_RCPT:
902 result = 250;
903 break;
904
905 case SM_RSET:
906 fflush (sm_wfp);
907 ftruncate (fileno (sm_wfp), 0L);
908 fseek (sm_wfp, 0L, SEEK_SET);
909 result = 250;
910 break;
911
912 case SM_DATA:
913 result = 354;
914 break;
915
916 case SM_QUIT:
917 unlink (sm_tmpfil);
918 sm_ispool = 0;
919 result = 221;
920 break;
921
922 default:
923 result = 500;
924 break;
925 }
926 if (sm_debug) {
927 printf ("<= %d\n", result);
928 fflush (stdout);
929 }
930
931 sm_reply.text[sm_reply.length = 0] = NULL;
932 return (sm_reply.code = result);
933 }
934 #endif /* MPOP */
935
936 sm_alarmed = 0;
937 alarm ((unsigned) time);
938 if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK)
939 result = smhear ();
940 alarm (0);
941
942 return result;
943 }
944
945
946 /*
947 * write the buffer to the open SMTP channel
948 */
949
950 static int
951 sm_wrecord (char *buffer, int len)
952 {
953 if (sm_wfp == NULL)
954 return sm_werror ();
955
956 fwrite (buffer, sizeof(*buffer), len, sm_wfp);
957 fputs ("\r\n", sm_wfp);
958 fflush (sm_wfp);
959
960 return (ferror (sm_wfp) ? sm_werror () : OK);
961 }
962
963
964 static int
965 sm_wstream (char *buffer, int len)
966 {
967 char *bp;
968 static char lc = '\0';
969
970 if (sm_wfp == NULL)
971 return sm_werror ();
972
973 if (buffer == NULL && len == 0) {
974 if (lc != '\n')
975 fputs ("\r\n", sm_wfp);
976 lc = '\0';
977 return (ferror (sm_wfp) ? sm_werror () : OK);
978 }
979
980 for (bp = buffer; len > 0; bp++, len--) {
981 switch (*bp) {
982 case '\n':
983 sm_nl = TRUE;
984 fputc ('\r', sm_wfp);
985 break;
986
987 case '.':
988 if (sm_nl)
989 fputc ('.', sm_wfp);/* FALL THROUGH */
990 default:
991 sm_nl = FALSE;
992 }
993 fputc (*bp, sm_wfp);
994 if (ferror (sm_wfp))
995 return sm_werror ();
996 }
997
998 if (bp > buffer)
999 lc = *--bp;
1000 return (ferror (sm_wfp) ? sm_werror () : OK);
1001 }
1002
1003
1004 #ifdef _AIX
1005 /*
1006 * AIX by default will inline the strlen and strcpy commands by redefining
1007 * them as __strlen and __strcpy respectively. This causes compile problems
1008 * with the #ifdef MPOP in the middle. Should the #ifdef MPOP be removed,
1009 * remove these #undefs.
1010 */
1011 # undef strlen
1012 # undef strcpy
1013 #endif /* _AIX */
1014
1015 static int
1016 sm_werror (void)
1017 {
1018 sm_reply.length =
1019 strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened"
1020 : sm_alarmed ? "write to socket timed out"
1021 #ifdef MPOP
1022 : sm_ispool ? "error writing to spool file"
1023 #endif
1024 : "error writing to socket"));
1025
1026 return (sm_reply.code = NOTOK);
1027 }
1028
1029
1030 static int
1031 smhear (void)
1032 {
1033 int i, code, cont, bc, rc, more;
1034 char *bp, *rp;
1035 char **ehlo, buffer[BUFSIZ];
1036
1037 if (doingEHLO) {
1038 static int at_least_once = 0;
1039
1040 if (at_least_once) {
1041 char *ep;
1042
1043 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1044 ep = *ehlo;
1045 free (ep);
1046 }
1047 } else {
1048 at_least_once = 1;
1049 }
1050
1051 ehlo = EHLOkeys;
1052 *ehlo = NULL;
1053 }
1054
1055 again: ;
1056
1057 sm_reply.length = 0;
1058 sm_reply.text[0] = 0;
1059 rp = sm_reply.text;
1060 rc = sizeof(sm_reply.text) - 1;
1061
1062 for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) {
1063 if (sm_debug) {
1064 printf ("<= %s\n", buffer);
1065 fflush (stdout);
1066 }
1067
1068 if (doingEHLO
1069 && strncmp (buffer, "250", sizeof("250") - 1) == 0
1070 && (buffer[3] == '-' || doingEHLO == 2)
1071 && buffer[4]) {
1072 if (doingEHLO == 2) {
1073 if ((*ehlo = malloc ((size_t) (strlen (buffer + 4) + 1)))) {
1074 strcpy (*ehlo++, buffer + 4);
1075 *ehlo = NULL;
1076 if (ehlo >= EHLOkeys + MAXEHLO)
1077 doingEHLO = 0;
1078 }
1079 else
1080 doingEHLO = 0;
1081 }
1082 else
1083 doingEHLO = 2;
1084 }
1085
1086 for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--)
1087 continue;
1088
1089 cont = FALSE;
1090 code = atoi (bp);
1091 bp += 3, bc -= 3;
1092 for (; bc > 0 && isspace (*bp); bp++, bc--)
1093 continue;
1094 if (bc > 0 && *bp == '-') {
1095 cont = TRUE;
1096 bp++, bc--;
1097 for (; bc > 0 && isspace (*bp); bp++, bc--)
1098 continue;
1099 }
1100
1101 if (more) {
1102 if (code != sm_reply.code || cont)
1103 continue;
1104 more = FALSE;
1105 } else {
1106 sm_reply.code = code;
1107 more = cont;
1108 if (bc <= 0) {
1109 strncpy (buffer, sm_noreply, sizeof(buffer));
1110 bp = buffer;
1111 bc = strlen (sm_noreply);
1112 }
1113 }
1114
1115 if ((i = min (bc, rc)) > 0) {
1116 strncpy (rp, bp, i);
1117 rp += i, rc -= i;
1118 if (more && rc > strlen (sm_moreply) + 1) {
1119 strcpy (sm_reply.text + rc, sm_moreply);
1120 rc += strlen (sm_moreply);
1121 }
1122 }
1123 if (more)
1124 continue;
1125 if (sm_reply.code < 100) {
1126 if (sm_verbose) {
1127 printf ("%s\n", sm_reply.text);
1128 fflush (stdout);
1129 }
1130 goto again;
1131 }
1132
1133 sm_reply.length = rp - sm_reply.text;
1134 return sm_reply.code;
1135 }
1136 return NOTOK;
1137 }
1138
1139
1140 static int
1141 sm_rrecord (char *buffer, int *len)
1142 {
1143 if (sm_rfp == NULL)
1144 return sm_rerror ();
1145
1146 buffer[*len = 0] = 0;
1147
1148 fgets (buffer, BUFSIZ, sm_rfp);
1149 *len = strlen (buffer);
1150 if (ferror (sm_rfp) || feof (sm_rfp))
1151 return sm_rerror ();
1152 if (buffer[*len - 1] != '\n')
1153 while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp))
1154 continue;
1155 else
1156 if (buffer[*len - 2] == '\r')
1157 *len -= 1;
1158 buffer[*len - 1] = 0;
1159
1160 return OK;
1161 }
1162
1163
1164 static int
1165 sm_rerror (void)
1166 {
1167 sm_reply.length =
1168 strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened"
1169 : sm_alarmed ? "read from socket timed out"
1170 : feof (sm_rfp) ? "premature end-of-file on socket"
1171 : "error reading from socket"));
1172
1173 return (sm_reply.code = NOTOK);
1174 }
1175
1176
1177 static RETSIGTYPE
1178 alrmser (int i)
1179 {
1180 #ifndef RELIABLE_SIGNALS
1181 SIGNAL (SIGALRM, alrmser);
1182 #endif
1183
1184 sm_alarmed++;
1185 if (sm_debug) {
1186 printf ("timed out...\n");
1187 fflush (stdout);
1188 }
1189 }
1190
1191
1192 char *
1193 rp_string (int code)
1194 {
1195 char *text;
1196 static char buffer[BUFSIZ];
1197
1198 switch (sm_reply.code != NOTOK ? code : NOTOK) {
1199 case RP_AOK:
1200 text = "AOK";
1201 break;
1202
1203 case RP_MOK:
1204 text = "MOK";
1205 break;
1206
1207 case RP_OK:
1208 text = "OK";
1209 break;
1210
1211 case RP_RPLY:
1212 text = "RPLY";
1213 break;
1214
1215 case RP_BHST:
1216 default:
1217 text = "BHST";
1218 snprintf (buffer, sizeof(buffer), "[%s] %s", text, sm_reply.text);
1219 return buffer;
1220
1221 case RP_PARM:
1222 text = "PARM";
1223 break;
1224
1225 case RP_NO:
1226 text = "NO";
1227 break;
1228
1229 case RP_USER:
1230 text = "USER";
1231 break;
1232
1233 case RP_NDEL:
1234 text = "NDEL";
1235 break;
1236 }
1237
1238 snprintf (buffer, sizeof(buffer), "[%s] %3d %s",
1239 text, sm_reply.code, sm_reply.text);
1240 return buffer;
1241 }
1242
1243
1244 #ifdef MPOP
1245
1246 static char *broken[MAXARGS + 1];
1247
1248 static char **
1249 smail_brkstring (char *strg, char *brksep, char *brkterm)
1250 {
1251 int bi;
1252 char c, *sp;
1253
1254 sp = strg;
1255
1256 for (bi = 0; bi < MAXARGS; bi++) {
1257 while (smail_brkany (c = *sp, brksep))
1258 *sp++ = 0;
1259 if (!c || smail_brkany (c, brkterm)) {
1260 *sp = 0;
1261 broken[bi] = 0;
1262 return broken;
1263 }
1264
1265 broken[bi] = sp;
1266 while ((c = *++sp) && !smail_brkany (c, brksep) && !smail_brkany (c, brkterm))
1267 continue;
1268 }
1269 broken[MAXARGS] = 0;
1270
1271 return broken;
1272 }
1273
1274
1275 /*
1276 * returns 1 if chr in strg, 0 otherwise
1277 */
1278 static int
1279 smail_brkany (char chr, char *strg)
1280 {
1281 char *sp;
1282
1283 if (strg)
1284 for (sp = strg; *sp; sp++)
1285 if (chr == *sp)
1286 return 1;
1287 return 0;
1288 }
1289
1290 /*
1291 * copy a string array and return pointer to end
1292 */
1293 char **
1294 smail_copyip (char **p, char **q, int len_q)
1295 {
1296 while (*p && --len_q > 0)
1297 *q++ = *p++;
1298
1299 *q = NULL;
1300
1301 return q;
1302 }
1303
1304 #endif /* MPOP */
1305
1306
1307 static char *
1308 EHLOset (char *s)
1309 {
1310 size_t len;
1311 char *ep, **ehlo;
1312
1313 len = strlen (s);
1314
1315 for (ehlo = EHLOkeys; *ehlo; ehlo++) {
1316 ep = *ehlo;
1317 if (strncmp (ep, s, len) == 0) {
1318 for (ep += len; *ep == ' '; ep++)
1319 continue;
1320 return ep;
1321 }
1322 }
1323
1324 return 0;
1325 }