Annotation of researchv10no/cmd/upas/smtp/converse.c, revision 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.