Annotation of researchv10no/cmd/upas/smtp/converse.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Do the necessary commands for a smtp transfer.  Start by waiting for the
                      3:  * connection to open, then send HELO, MAIL, RCPT, and DATA.  Check the
                      4:  * reply codes and give up if needed.
                      5:  * 
                      6:  * This code modified from the MIT UNIX TCP implementation:
                      7:  * Copyright 1984 Massachusetts Institute of Technology
                      8:  * 
                      9:  * Permission to use, copy, modify, and distribute this file
                     10:  * for any purpose and without fee is hereby granted, provided
                     11:  * that this copyright and permission notice appear on all copies
                     12:  * and supporting documentation, the name of M.I.T. not be used
                     13:  * in advertising or publicity pertaining to distribution of the
                     14:  * program without specific prior permission, and notice be given
                     15:  * in supporting documentation that copying and distribution is
                     16:  * by permission of M.I.T.  M.I.T. makes no representations about
                     17:  * the suitability of this software for any purpose.  It is provided
                     18:  * "as is" without express or implied warranty.
                     19:  */
                     20: 
                     21: #include <stdio.h>
                     22: #include <signal.h>
                     23: #include <sysexits.h>
                     24: #include "mail.h"
                     25: #include "smtp.h"
                     26: #include "string.h"
                     27: 
                     28: #define TRUE 1
                     29: #define FALSE 0
                     30: #define MINUTES * 60
                     31: #define HOURS * 60 MINUTES
                     32: #define DAYS * 24 HOURS
                     33: 
                     34: char *strcat(), *strcpy();
                     35: 
                     36: SIGRETURN ignore_signal();
                     37: SIGRETURN death();
                     38: char   *timemsg;
                     39: int    timelim;
                     40: int    timeerror;
                     41: long   nbytes;
                     42: extern int debug;
                     43: FILE   *fi;
                     44: FILE   *fo;
                     45: 
                     46: converse(unixformat, from, rcpts, domain, sfi, sfo, mlfd)
                     47: char   *from;                          /* from address */
                     48: namelist *rcpts;                       /* to addresses */
                     49: char   *domain;
                     50: FILE   *sfi;                           /* smtp input */
                     51: FILE   *sfo;                           /* smtp output */
                     52: FILE   *mlfd;                          /* mail file descriptor */
                     53: {
                     54:        extern char *helohost;
                     55:        char buf[MAXSTR];
                     56:        namelist *np;
                     57:        extern int kludgepause;
                     58: 
                     59:        fi = sfi;  fo = sfo;
                     60: 
                     61:        (void) signal(SIGALRM, death);
                     62: 
                     63:        setalarm(5 MINUTES, "initial handshake", EX_TEMPFAIL);
                     64:        expect(220, sfi, sfo, EX_PROTOCOL);                     /* expect a service ready msg */
                     65: 
                     66:        /*
                     67:         * This pause is needed when an smtp call gets redialed
                     68:         * (the research version of the Datakit splice.)  Because of
                     69:         * a race condition inherent in both features, -inet- must
                     70:         * not be too eager to send HELO until the connection is set up
                     71:         * completely.  Unfortunately, the other guy's 220 response
                     72:         * (above) can arrive before the redialed connection
                     73:         * is completely processed locally.  Hence, the brief delay.
                     74:         * We can't fix this without changing (read ``fixing'') Datakit
                     75:         * everywhere.  This kludge is slightly easier.
                     76:         */
                     77:        if (kludgepause)
                     78:                sleep(kludgepause);
                     79: 
                     80:        sprintf(buf, "HELO %s\n", helohost);
                     81:        csend(buf);
                     82:        expect(250, sfi, sfo, EX_PROTOCOL);                     /* expect an OK */
                     83: 
                     84:        strcpy(buf, "MAIL FROM:<");
                     85:        strcat(buf, from);
                     86:        strcat(buf, ">\n");
                     87:        csend(buf);
                     88:        setalarm(10 MINUTES, "response to MAIL FROM/RCPT TO", EX_TEMPFAIL);
                     89:        expect(250, sfi, sfo, EX_PROTOCOL);                     /* expect OK */
                     90: 
                     91:        for (np=rcpts; np!=NULL; np=np->next) {
                     92:                strcpy(buf, "RCPT TO:<");
                     93:                strcat(buf, np->name);
                     94:                strcat(buf, ">\n");
                     95:                csend(buf);
                     96:                expect(250, sfi, sfo, EX_NOUSER);               /* expect OK */
                     97:        }
                     98:        setalarm(10 MINUTES, "response to DATA", EX_TEMPFAIL);
                     99:        csend("DATA\n");
                    100:        expect(354, sfi, sfo, EX_PROTOCOL);
                    101:        setalarm(10 MINUTES, "sending mail data", EX_TEMPFAIL);
                    102:        do_data(unixformat, mlfd, sfo, from, rcpts, domain);
                    103:        setalarm(1 HOURS, "expecting delivery ack", EX_TEMPFAIL);
                    104:        expect(250, sfi, sfo, EX_PROTOCOL);
                    105: 
                    106:        setalarm(5 MINUTES, "response to QUIT", 0);
                    107:        csend("QUIT\n");
                    108:        expect(221, sfi, sfo, 0);                       /* who cares? (Some do)*/
                    109:        exit(0);
                    110: }
                    111: 
                    112: /*
                    113:  *  escape '.'s at the beginning of lines and turn newlines into
                    114:  *  /r/n's.
                    115:  */
                    116: static char smlastchar;
                    117: 
                    118: smfputs(str, fp)
                    119:        char *str;
                    120:        FILE *fp;
                    121: {
                    122:        register char *cp;
                    123: 
                    124:        /*
                    125:         *  escape a leading dot
                    126:         */
                    127:        if(smlastchar=='\n' && str[0]=='.') {
                    128:                nbytes++;
                    129:                fputc('.', fp);
                    130:        }
                    131: 
                    132:        /*
                    133:         *  output the line
                    134:         */
                    135:        for(cp=str; *cp; cp++){
                    136:                if(*cp=='\n') {
                    137:                        nbytes++;
                    138:                        putc('\r', fp);
                    139:                }
                    140:                nbytes++;
                    141:                putc(*cp, fp);
                    142:        }
                    143:        if(cp!=str)
                    144:                smlastchar = *(cp-1);
                    145: }
                    146: 
                    147: 
                    148: /*
                    149:  * Send the data from the specified mail file out on the current smtp
                    150:  * connection.  Do the appropriate netascii conversion and hidden '.'
                    151:  * padding.  Send the <CRLF>.<CRLF> at completion.
                    152:  */
                    153: do_data(unixformat, sfi, sfo, from, rcpts, domain)
                    154:        register FILE *sfi;             /* mail file descriptor */
                    155:        register FILE *sfo;             /* smtp files */
                    156:        char *from;
                    157:        namelist *rcpts;
                    158:        char *domain;
                    159: {
                    160:        static string *rcvr;
                    161:        char buf[4096];
                    162:        namelist *p;
                    163:        long nchars;
                    164: 
                    165:        /*
                    166:         *  turn rcpts into a , list of receivers
                    167:         */
                    168:        rcvr = s_reset(rcvr);
                    169:        for(p = rcpts; p; p = p->next){
                    170:                s_append(rcvr, p->name);
                    171:                if(p->next)
                    172:                        s_append(rcvr, ", ");
                    173:        }
                    174: 
                    175:        /*
                    176:         *  send data to output
                    177:         */
                    178:        setalarm(5 MINUTES, "start sending mail data", EX_TEMPFAIL);
                    179:        nbytes = 0;
                    180:        smlastchar = '\n';
                    181:        if(unixformat){
                    182:                nchars = 0;
                    183:                while(fgets(buf, sizeof(buf), sfi)!=NULL) {
                    184:                        smfputs(buf, sfo);
                    185:                        nchars += strlen(buf)+1;
                    186:                        if (nchars>1024) {
                    187:                                if (debug)
                    188:                                        fprintf(stderr, ".");
                    189:                                nchars -= 1024;
                    190:                                setalarm(5 MINUTES, "sending mail data", EX_TEMPFAIL);
                    191:                        }
                    192:                }
                    193:        } else {
                    194:                if(to822(smfputs, sfi, sfo, from, domain, s_to_c(rcvr))<0){
                    195:                        Syslog(LOG_INFO, "bad input file to %s\n",
                    196:                                s_to_c(rcvr));
                    197:                        bomb(EX_DATAERR);
                    198:                }
                    199:        }
                    200: 
                    201:        /*
                    202:         *  terminate the DATA command with \r\n.\r\n
                    203:         */
                    204:        if(smlastchar != '\n'){
                    205:                fputs("\r\n", sfo);
                    206:                nbytes += 2;
                    207:        }
                    208:        fputs(".\r\n", sfo);
                    209:        nbytes += 3;
                    210:        Syslog(LOG_INFO, "%s  sent %d bytes to  %s\n",
                    211:                from, nbytes, s_to_c(rcvr));
                    212: 
                    213:        /*
                    214:         *  see if we screwed up
                    215:         */
                    216:        setalarm(30 MINUTES, "finishing data", EX_TEMPFAIL);
                    217:        fflush(sfo);
                    218:        if (ferror(sfo)) {
                    219:                Syslog(LOG_INFO, "write error finishing data to %s",
                    220:                        s_to_c(rcvr));
                    221:                bomb(EX_IOERR);
                    222:        }
                    223: }
                    224: 
                    225: /*
                    226:  * Expect a reply message with the specified code.  If the specified code
                    227:  * is received return TRUE; otherwise print the error message out on the
                    228:  * standard output and give up.  Note that the reply can be a multiline
                    229:  * message.
                    230:  */
                    231: expect(code, sfi, sfo, error)
                    232: int    code;
                    233: FILE   *sfi, *sfo;
                    234: int    error;
                    235: {
                    236:        int retcd;
                    237:        char cmdbuf[BUFSIZ];
                    238:        char cbuf[6144];
                    239:        extern int debug;
                    240: 
                    241:        cbuf[0] = '\0';
                    242: 
                    243:        /* get whole reply */
                    244: more:
                    245:        while (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) {
                    246:                cmdbuf[131] = '\n';
                    247:                cmdbuf[132] = '\0';             /* not too long */
                    248:                Syslog(LOG_DEBUG, "---> %s", cmdbuf);
                    249:                if (cmdbuf[3] != '-')   /* continuation line? */
                    250:                        break;          /* no, last line */
                    251:                else if (strlen(cmdbuf) + strlen(cbuf) + 4 < sizeof(cbuf)) {
                    252:                        strcat(cbuf, "<<< ");
                    253:                        strcat(cbuf, cmdbuf);
                    254:                }
                    255:        }
                    256:        if (sscanf(cmdbuf, "%d", &retcd) != 1 ){
                    257:                int l=strlen(cmdbuf)-1;
                    258:                if (l>=0 && cmdbuf[l]=='\n')
                    259:                        cmdbuf[l]='\0';
                    260:                (void) fprintf(stderr, "non-numeric command reply (%s)\n", cmdbuf);
                    261:                if (error)
                    262:                        bomb(EX_PROTOCOL);
                    263:                else
                    264:                        return 1;
                    265:        }
                    266:        if (retcd == code) {
                    267:                return 1;
                    268:        }
                    269:        if (retcd/100 == code/100) {
                    270:                return 1;
                    271:        }
                    272:        Syslog(LOG_NOTICE, "Failed, expecting %d, got %d\n", code, retcd);
                    273:        /* print the error line */
                    274:        (void) fprintf(stderr, "%s<<< %s", cbuf, cmdbuf);
                    275:        csend("QUIT\n");
                    276:        if (error)
                    277:                if (retcd/100 == 4)
                    278:                        bomb(EX_TEMPFAIL); /* 4xx make temp fails, no matter what*/
                    279:                else
                    280:                        bomb(error);    /* map smtp errors to mailsys errors */
                    281:        return 1;
                    282: }
                    283: 
                    284: setalarm(limit, message, error)
                    285:        char *message;
                    286: {
                    287:        timelim = limit;
                    288:        timemsg = message;
                    289:        timeerror = error;
                    290:        alarm(limit);
                    291: }
                    292: 
                    293: /* Maximum time to live elapsed.  Die right now. */
                    294: SIGRETURN
                    295: death()
                    296: {
                    297:        Syslog(LOG_NOTICE, "Timer (%d sec) expired: %s.\n", timelim, timemsg);
                    298:        exit(timeerror);
                    299: }
                    300: 
                    301: SIGRETURN
                    302: ignore_signal(){}
                    303: 
                    304: csend(buf)
                    305: char *buf;
                    306: {
                    307:        Syslog(LOG_DEBUG, "<--- %s", buf);
                    308:        tputs(buf, fo);
                    309: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.