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