source: trunk/third/nmh/mts/smtp/smtp.c @ 12455

Revision 12455, 24.8 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * smtp.c -- nmh SMTP interface
4 *
5 * $Id: smtp.c,v 1.1.1.1 1999-02-07 18:14:12 danw Exp $
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
55static int sm_addrs = 0;
56static int sm_alarmed = 0;
57static int sm_debug = 0;
58static int sm_nl = TRUE;
59static int sm_verbose = 0;
60
61static FILE *sm_rfp = NULL;
62static FILE *sm_wfp = NULL;
63
64#ifdef MPOP
65static int sm_ispool = 0;
66static char sm_tmpfil[BUFSIZ];
67#endif /* MPOP */
68
69static char *sm_noreply = "No reply text given";
70static char *sm_moreply = "; ";
71
72struct smtp sm_reply;           /* global... */
73
74#ifdef MPOP
75extern int errno;
76#endif
77
78
79#define MAXEHLO 20
80
81static int doingEHLO;
82char *EHLOkeys[MAXEHLO + 1];
83
84/*
85 * static prototypes
86 */
87static int rclient (char *, char *, char *);
88static int sm_ierror (char *fmt, ...);
89static int smtalk (int time, char *fmt, ...);
90static int sm_wrecord (char *, int);
91static int sm_wstream (char *, int);
92static int sm_werror (void);
93static int smhear (void);
94static int sm_rrecord (char *, int *);
95static int sm_rerror (void);
96static RETSIGTYPE alrmser (int);
97static char *EHLOset (char *);
98
99#ifdef MPOP
100/*
101 * smtp.c's own static copy of several nmh library subroutines
102 */
103static char **smail_brkstring (char *, char *, char *);
104static int smail_brkany (char, char *);
105char **smail_copyip (char **, char **, int);
106#endif
107
108
109int
110sm_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        }
156all_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
209send_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
225static int
226rclient (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
270int
271sm_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
317int
318sm_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
354int
355sm_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
382int
383sm_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
396int
397sm_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
422int
423sm_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
481int
482sm_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        }
527losing0:
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"));
548losing1: ;
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"));
557losing2:
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;
566losing3:
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;
635bad_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
662ok_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;
673bad_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
760ok_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:
783no_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
830static int
831sm_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
846static int
847smtalk (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
950static int
951sm_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
964static int
965sm_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
1015static int
1016sm_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
1030static int
1031smhear (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
1055again: ;
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
1140static int
1141sm_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
1164static int
1165sm_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
1177static RETSIGTYPE
1178alrmser (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
1192char *
1193rp_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
1246static char *broken[MAXARGS + 1];
1247
1248static char **
1249smail_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 */
1278static int
1279smail_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 */
1293char **
1294smail_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
1307static char *
1308EHLOset (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}
Note: See TracBrowser for help on using the repository browser.