Annotation of coherent/a/tmp/smail/deliver.c, revision 1.1.1.1

1.1       root        1: /*
                      2: **  Deliver.c
                      3: **
                      4: **  Routines to effect delivery of mail for rmail/smail. 
                      5: **
                      6: */
                      7: 
                      8: #ifndef lint
                      9: static char    *sccsid="@(#)deliver.c  2.5 (smail) 9/15/87";
                     10: #endif
                     11: 
                     12: # include      <stdio.h>
                     13: # include      <sys/types.h>
                     14: # include      <sys/stat.h>
                     15: /* # include   <sys/utsname.h> */
                     16: # include      <ctype.h>
                     17: # include      <signal.h>
                     18: # include      "defs.h"
                     19: 
                     20: extern int  errno;     /* Error number set by certain system routines.  */
                     21: extern int  exitstat;          /* set if a forked mailer fails */
                     22: extern enum edebug debug;      /* how verbose we are           */ 
                     23: extern char hostname[];                /* our uucp hostname            */
                     24: extern char hostdomain[];      /* our host's domain            */
                     25: extern enum ehandle handle;    /* what we handle               */
                     26: extern enum erouting routing;  /* how we're routing addresses  */
                     27: extern char *uuxargs;          /* arguments given to uux       */
                     28: extern int  queuecost;         /* threshold for queueing mail  */
                     29: extern int  maxnoqueue;                /* max number of uucico's       */
                     30: extern char *spoolfile;                /* file name of spooled message */
                     31: extern FILE *spoolfp;          /* file ptr  to spooled message */
                     32: extern int spoolmaster;                /* set if creator of spoolfile  */
                     33: extern char nows[];            /* local time in ctime(3) format*/
                     34: extern char arpanows[];                /* local time in arpadate format*/
                     35: extern char _version[];                /* Version string from copyright.c      */
                     36: char stderrfile[20];           /* error file for stderr traping*/
                     37: char err_msg[2*MAXCLEN];       /* handy place to build error messages  */
                     38: 
                     39: char userlist[2*MAXCLEN];      /* used to build a list of users mail will
                     40:                                 * sent to.
                     41:                                 */
                     42: /*
                     43: **
                     44: **  deliver():  hand the letter to the proper mail programs.
                     45: **
                     46: **  Issues one command for each different host of <hostv>,
                     47: **  constructing the proper command for LOCAL or UUCP mail.
                     48: **  Note that LOCAL mail has blank host names.
                     49: **
                     50: **  The <userv> names for each host are arguments to the command.
                     51: ** 
                     52: **  Prepends a "From" line to the letter just before going 
                     53: **  out, with a "remote from <hostname>" if it is a UUCP letter.
                     54: **
                     55: */
                     56: 
                     57: deliver(argc, hostv, userv, formv, costv)
                     58: int argc;                              /* number of addresses          */
                     59: char *hostv[];                         /* host names                   */
                     60: char *userv[];                         /* user names                   */
                     61: enum eform formv[];                    /* form for each address        */
                     62: int costv[];                           /* cost vector                  */
                     63: {
                     64:        FILE *out;                      /* pipe to mailer               */
                     65:        FILE *popen();                  /* to fork a mailer             */
                     66: #ifdef RECORD
                     67:        void record();                  /* record all transactions      */
                     68: #endif
                     69: #ifdef LOG
                     70:        void log();
                     71: #endif
                     72:        char *mktemp();
                     73:        char *sform();
                     74:        char from[SMLBUF];              /* accumulated from argument    */
                     75:        char lcommand[SMLBUF];          /* local command issued         */
                     76:        char rcommand[SMLBUF];          /* remote command issued        */
                     77:        char scommand[SMLBUF];          /* retry  command issued        */
                     78:        char *command;                  /* actual command               */
                     79:        char buf[SMLBUF];               /* copying rest of the letter   */
                     80:        enum eform form;                /* holds form[i] for speed      */
                     81:        long size;                      /* number of bytes of message   */
                     82:        char *flags;                    /* flags for uux                */
                     83:        char *sflag;                    /* flag  for smail              */
                     84:        int i, j, status, retrying;
                     85:        char *c, *postmaster();
                     86:        int failcount = 0;
                     87:        int noqcnt = 0;                 /* number of uucico's started   */
                     88:        char *uux_noqueue = UUX_NOQUEUE;/* uucico starts immediately    */
                     89:        char *uux_queue   = UUX_QUEUE;  /* uucico job gets queued       */
                     90:        off_t message;
                     91:        struct stat st;
                     92: 
                     93: /*
                     94: ** rewind the spool file and read the collapsed From_ line
                     95: */
                     96:        (void) fseek(spoolfp, 0L, 0);
                     97:        (void) fgets(from, sizeof(from), spoolfp);
                     98:        if((c = index(from, '\n')) != 0) *c = '\0';
                     99:        message = ftell(spoolfp);
                    100: 
                    101: /*
                    102: **  We pass through the list of addresses.
                    103: */
                    104:        userlist[0] = '\0';     /* initialize userlist */
                    105:        stderrfile[0] = '\0';
                    106:        for(i = 0; i < argc; i++) {
                    107:                char *lend = lcommand;
                    108:                char *rend = rcommand;
                    109:                char *send = scommand;
                    110: 
                    111: /*
                    112: ** Prevent errors from previous passes.
                    113: */
                    114:                exitstat = 0;
                    115: 
                    116: 
                    117: /*
                    118: **  If we don't have sendmail, arrange to trap standard error
                    119: **  for inclusion in the message that is returned with failed mail.
                    120: */
                    121:                (void) unlink(stderrfile);
                    122:                (void) strcpy(stderrfile, "/tmp/stderrXXXXXX");
                    123:                (void) mktemp(stderrfile);
                    124:                (void) freopen(stderrfile, "w", stderr);
                    125:                if(debug != YES) {
                    126:                        (void) freopen(stderrfile, "w", stdout);
                    127:                }
                    128: 
                    129:                *lend = *rend = *send = '\0';
                    130: 
                    131: /*
                    132: **  If form == ERROR, the address was bad 
                    133: **  If form == SENT, it has been sent on a  previous pass.
                    134: */
                    135:                form = formv[i];
                    136:                if (form == SENT) {
                    137:                        continue;
                    138:                }
                    139: /*
                    140: **  Build the command based on whether this is local mail or uucp mail.
                    141: **  By default, don't allow more than 'maxnoqueue' uucico commands to
                    142: **  be started by a single invocation of 'smail'.
                    143: */
                    144:                if(uuxargs == NULL) {   /* flags not set on command line */
                    145:                        if(noqcnt < maxnoqueue && costv[i] <= queuecost) {
                    146:                                flags = uux_noqueue;
                    147:                        } else {
                    148:                                flags = uux_queue;
                    149:                        }
                    150:                } else {
                    151:                        flags = uuxargs;
                    152:                }
                    153: 
                    154:                retrying = 0;
                    155:                if(routing == JUSTDOMAIN) {
                    156:                        sflag = "-r";
                    157:                } else if(routing == ALWAYS) {
                    158:                        sflag = "-R";
                    159:                } else {
                    160:                        sflag = "";
                    161:                }
                    162: 
                    163:                (void) sprintf(lcommand, LMAIL(from, hostv[i]));
                    164:                (void) sprintf(rcommand, RMAIL(flags, from, hostv[i]));
                    165: 
                    166: /*
                    167: **  For each address with the same host name and form, append the user
                    168: **  name to the command line, and set form = ERROR so we skip this address
                    169: **  on later passes. 
                    170: */
                    171:                /* we initialized lend (rend) to point at the
                    172:                 * beginning of its buffer, so that at
                    173:                 * least one address will be used regardless
                    174:                 * of the length of lcommand (rcommand).
                    175:                 */
                    176:                for (j = i; j < argc; j++) {
                    177:                        if ((formv[j] != form)
                    178:                         || (strcmpic(hostv[i], hostv[j]) != 0)
                    179:                         || ((lend - lcommand) > MAXCLEN)
                    180:                         || ((rend - rcommand) > MAXCLEN)) {
                    181:                                continue;
                    182:                        }
                    183: 
                    184:                        /*
                    185:                        ** seek to the end of scommand
                    186:                        ** and add on a 'smail' command
                    187:                        ** multiple commands are separated by ';'
                    188:                        */
                    189: 
                    190:                        send += strlen(send);
                    191:                        if(send != scommand) {
                    192:                                *send++ = ';' ;
                    193:                        }
                    194: 
                    195:                        (void) sprintf(send, RETRY(sflag));
                    196:                        send += strlen(send);
                    197: 
                    198:                        lend += strlen(lend);
                    199:                        rend += strlen(rend);
                    200: 
                    201:                        if (form == LOCAL) {
                    202:                                (void) sprintf(lend, LARG(userv[j]));
                    203:                                (void) sprintf(send, LARG(userv[j]));
                    204:                                strcat(userlist,userv[j]);
                    205:                        } else {
                    206:                                (void) sprintf(lend, RLARG(hostv[i], userv[j]));
                    207:                                (void) sprintf(send, RLARG(hostv[i], userv[j]));
                    208:                        }
                    209: 
                    210:                        (void) sprintf(rend, RARG(userv[j]));
                    211:                        formv[j] = SENT;
                    212:                }
                    213: retry:
                    214: /*
                    215: ** rewind the spool file and read the collapsed From_ line
                    216: */
                    217:                (void) fseek(spoolfp, message, 0);
                    218: 
                    219:                /* if the address was in a bogus form (usually DOMAIN),
                    220:                ** then don't bother trying the uux.
                    221:                **
                    222:                ** Rather, go straight to the next smail routing level.
                    223:                */
                    224:                if(form == ERROR) {
                    225:                        static char errbuf[SMLBUF];
                    226:                        (void) sprintf(errbuf,
                    227:                                "address resolution ('%s' @ '%s') failed",
                    228:                                        userv[i], hostv[i]);
                    229:                        command = errbuf;
                    230:                        size    = 0;
                    231:                        goto form_error;
                    232:                }
                    233: 
                    234:                if (retrying) {
                    235:                        command = scommand;
                    236:                } else if (form == LOCAL) {
                    237:                        command = lcommand;
                    238:                } else {
                    239:                        command = rcommand;
                    240:                        if(flags == uux_noqueue) {
                    241:                                noqcnt++;
                    242:                        }
                    243:                }
                    244:                ADVISE("COMMAND: %s\n", command);
                    245: 
                    246: /*
                    247: ** Fork the mailer and set it up for writing so we can send the mail to it,
                    248: ** or for debugging divert the output to stdout.
                    249: */
                    250: 
                    251: /*
                    252: ** We may try to write on a broken pipe, if the uux'd host
                    253: ** is unknown to us.  Ignore this signal, since we can use the
                    254: ** return value of the pclose() as our indication of failure.
                    255: */
                    256:                (void) signal(SIGPIPE, SIG_IGN);
                    257: 
                    258:                if (debug == YES) {
                    259:                        out = stdout;
                    260:                } else {
                    261:                        failcount = 0;
                    262:                        do {
                    263:                                out = popen(command, "w");
                    264:                                if (out) break;
                    265:                                /*
                    266:                                 * Fork failed.  System probably overloaded.
                    267:                                 * Wait awhile and try again 10 times.
                    268:                                 * If it keeps failing, probably some
                    269:                                 * other problem, like no uux or smail.
                    270:                                 */
                    271:                                (void) sleep(60);
                    272:                                if (failcount == 1) {
                    273:                                        sprintf(err_msg,
                    274:                                "Deliver can not popen %s.  errno = %d",
                    275:                                                command, errno);
                    276:                                        error_log(err_msg);
                    277:                                } /* if failed exactly once */
                    278:                        } while (++failcount < 10);
                    279:                        if (failcount == 10) {
                    280:                                sprintf(err_msg,
                    281:                                "Deliver failed 10 times.  errno = %d",
                    282:                                        command, errno);
                    283:                                error_log(err_msg);
                    284:                        } /* if failed exactly once */  
                    285:                }
                    286:                if(out == NULL) {
                    287:                        exitstat = EX_UNAVAILABLE;
                    288:                        (void) printf("couldn't execute %s.\n", command);
                    289:                        continue;
                    290:                }
                    291: 
                    292:                size = 0;
                    293:                if(fstat(fileno(spoolfp), &st) >= 0) {
                    294:                        size = st.st_size - message;
                    295:                }
                    296: /*
                    297: **  Output our From_ line.
                    298: */
                    299:                if (form == LOCAL) {
                    300: #ifdef SENDMAIL
                    301:                        (void) sprintf(buf, LFROM(from, nows, hostname));
                    302:                        size += strlen(buf);
                    303:                        (void) fputs(buf, out);
                    304: #else
                    305:                        char *p;
                    306:                        if((p=index(from, '!')) != NULL) {
                    307:                                *p = NULL;
                    308:                                (void) sprintf(buf, RFROM(p+1, nows, from));
                    309:                                size += strlen(buf);
                    310:                                (void) fputs(buf, out);
                    311:                                *p = '!';
                    312:                        }
                    313: #endif
                    314:                } else {
                    315:                        (void) sprintf(buf, RFROM(from, nows, hostname));
                    316:                        size += strlen(buf);
                    317:                        (void) fputs(buf, out);
                    318:                }
                    319: 
                    320: /* END OF THIS LOOKS LIKE THE PLACE  */
                    321: #ifdef SENDMAIL
                    322: /*
                    323: **  If using sendmail, insert a Received: line only for mail
                    324: **  that is being passed to uux.  If not using sendmail, always
                    325: **  insert the received line, since sendmail isn't there to do it.
                    326: */
                    327:                if(command == rcommand && handle != ALL)
                    328: #endif
                    329:                {
                    330: #ifdef GATEWAY_NAME
                    331:                        (void) sprintf(buf,
                    332:                                "Received: by %s (%s - %s) id AA%05d; %s\n",
                    333:                                        hostdomain, VERSION,GATEWAY_NAME,
                    334:                                        getpid(), arpanows);
                    335: #else
                    336:                        (void) sprintf(buf,
                    337:                                "Received: by %s (%s) id AA%05d; %s\n",
                    338:                                        hostdomain, VERSION,
                    339:                                        getpid(), arpanows);
                    340: #endif
                    341:                        size += strlen(buf);
                    342:                        (void) fputs(buf, out);
                    343:                }
                    344: 
                    345: /*
                    346: **  Copy input.
                    347: */
                    348:                while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
                    349:                        (void) fputs(buf, out);
                    350:                }
                    351: /*
                    352: **  Get exit status and if non-zero, set global exitstat so when we exit
                    353: **  we can indicate an error.
                    354: */
                    355: form_error:
                    356:                if (debug != YES) {
                    357:                        if(form == ERROR) {
                    358:                                exitstat = EX_NOHOST;
                    359:                        } else {
                    360:                                status = pclose(out);
                    361:                                exitstat = status >> 8;
                    362:                        }
                    363:                        /*
                    364:                         * The 'retrying' check prevents a smail loop.
                    365:                         */
                    366:                        if(exitstat != 0) {
                    367:                                /*
                    368:                                ** the mail failed, probably because the host
                    369:                                ** being uux'ed isn't in L.sys or local user
                    370:                                ** is unknown.
                    371:                                */
                    372: 
                    373:                                if((retrying == 0)      /* first pass */
                    374:                                && (routing != REROUTE) /* have higher level */
                    375:                                && (form != LOCAL)) {   /* can't route local */
                    376:                                        /*
                    377:                                        ** Try again using a higher
                    378:                                        ** level of routing.
                    379:                                        */
                    380:                                        ADVISE("%s failed (%d)\ntrying %s\n",
                    381:                                                command, exitstat, scommand);
                    382:                                        exitstat = 0;
                    383:                                        retrying = 1;
                    384:                                        form = SENT;
                    385:                                        goto retry;
                    386:                                }
                    387: 
                    388:                                /*
                    389:                                ** if we have no other routing possibilities
                    390:                                ** see that the mail is returned to sender.
                    391:                                */
                    392: 
                    393:        /* Important NOTE: A very nasty race condition exists here. If
                    394:         * multiple child processes are trying to send mail to the same
                    395:         * user simultaneously, then 1 process will get the mailbox and
                    396:         * lock it, causing the other processes to fail. If a user invokes
                    397:         * several processes to send mail to himself locally, then each
                    398:         * process that fails once a mailbox is locked will force smail to
                    399:         * return the message back to the original sender, which will fail,
                    400:         * because the mailbox is already locked. This will force another
                    401:         * smail process to fire up to return the returned message, and we
                    402:         * will enter a recursive spawning of smail processes that will
                    403:         * eventually choke the kernel.
                    404:         *
                    405:         * I have added code to check the following:
                    406:         *      if a local mail send fails, we check to see if the person
                    407:         *      who sent the message exists in the local send-to-user
                    408:         *      list (userlist). If this is true, we do NOT return the
                    409:         *      the mail, but write a message to the log file to indicate
                    410:         *      that this occured.
                    411:         *
                    412:         * Bob H. 10/20/92
                    413:         */ 
                    414:                                if((routing == REROUTE)
                    415:                                || ((form == LOCAL) && (!strstr(userlist,from)))) {
                    416: 
                    417:                                        /*
                    418:                                        ** if this was our last chance,
                    419:                                        ** return the mail to the sender.
                    420:                                        */
                    421: 
                    422:                                        ADVISE("%s failed (%d)\n",
                    423:                                                command, exitstat);
                    424:                                        
                    425:                                        (void) fseek(spoolfp, message, 0);
                    426: #ifdef SENDMAIL
                    427:                                        /* if we have sendmail, then it
                    428:                                        ** was handed the mail, which failed.
                    429:                                        ** sendmail returns the failed mail
                    430:                                        ** for us, so we need not do it again.
                    431:                                        */
                    432:                                        if(form != LOCAL)
                    433: #endif
                    434:                                        {
                    435:                                                return_mail(from, command, form);
                    436:                                        }
                    437:                                        exitstat = 0;
                    438:                                }
                    439:                                if((form == LOCAL) && (strstr(userlist,from))){
                    440:                                        sprintf(err_msg,"Local mail to user %s failed. Because", from);
                    441:                                        error_log(err_msg);
                    442:                                        sprintf(err_msg,"this was the same person to send the message,");
                    443:                                        error_log(err_msg);
                    444:                                        sprintf(err_msg,"it will NOT be returned to avoid a race condition.");
                    445:                                        error_log(err_msg);
                    446:                                }
                    447:                        }
                    448: # ifdef LOG
                    449:                        else {
                    450:                                if(retrying == 0) log(command, from, size);
                    451:                        }
                    452: # endif
                    453:                }
                    454:        }
                    455: /*
                    456: **  Update logs and records.
                    457: */
                    458: # ifdef RECORD
                    459:        (void) fseek(spoolfp, message, 0);
                    460:        record(command, from, size);
                    461: # endif
                    462: 
                    463: /*
                    464: **  close spool file pointer.
                    465: **  if we created it, then unlink file.
                    466: */
                    467:        (void) fclose(spoolfp);
                    468:        if(spoolmaster) {
                    469:                (void) unlink(spoolfile);
                    470:        }
                    471:        (void) unlink(stderrfile);
                    472: }
                    473: 
                    474: /*
                    475: ** return mail to sender, as determined by From_ line.
                    476: */
                    477: return_mail(from, fcommand, form)
                    478: char *from, *fcommand;
                    479: enum eform form;
                    480: {
                    481:        char buf[SMLBUF];
                    482:        char domain[SMLBUF], user[SMLBUF];
                    483:        char *r;
                    484:        FILE *fp, *out, *popen();
                    485:        int i = 0;
                    486: 
                    487:        r = buf;
                    488: 
                    489:        (void) sprintf(r, "%s %s", SMAIL, VFLAG);
                    490:        r += strlen(r);
                    491: 
                    492:        if(islocal(from, domain, user)) {
                    493:                (void) sprintf(r, LARG(user));
                    494:        } else {
                    495:                (void) sprintf(r, RLARG(domain, user));
                    496:        }
                    497: 
                    498:        i = 0;
                    499: 
                    500:        do {
                    501:                out = popen(buf, "w");
                    502:                if (out) break;
                    503:                /*
                    504:                 * Fork failed.  System probably overloaded.
                    505:                 * Wait awhile and try again 10 times.
                    506:                 * If it keeps failing, probably some
                    507:                 * other problem, like no uux or smail.
                    508:                 */
                    509:                (void) sleep(60);
                    510:        } while (++i < 10);
                    511: 
                    512:        if(out == NULL) {
                    513:                (void) printf("couldn't execute %s.\n", buf);
                    514:                return;
                    515:        }
                    516: 
                    517:        (void) fprintf(out, "Date: %s\n", arpanows);
                    518:        (void) fprintf(out, "From: MAILER-DAEMON@%s\n", hostdomain);
                    519:        (void) fprintf(out, "Subject: failed mail\n");
                    520:        (void) fprintf(out, "To: %s\n", from);
                    521:        (void) fprintf(out, "\n");
                    522:        (void) fprintf(out, "Form: %s\n", sform(form));
                    523:        (void) fprintf(out, "Exit status: %d\n", exitstat);
                    524:        (void) fprintf(out, "=======     command failed      =======\n\n");
                    525:        (void) fprintf(out, " COMMAND: %s\n\n", fcommand);
                    526: 
                    527:        (void) fprintf(out, "======= standard error follows  =======\n");
                    528:        (void) fflush(stderr);
                    529:        if((fp = fopen(stderrfile, "r")) != NULL) {
                    530:                while(fgets(buf, sizeof(buf), fp) != NULL) {
                    531:                        (void) fputs(buf, out);
                    532:                }
                    533:        }
                    534:        (void) fclose(fp);
                    535:        (void) fprintf(out, "======= text of message follows =======\n");
                    536: /*
                    537: **  Copy input.
                    538: */
                    539:        (void) fprintf(out, "From %s\n", from);
                    540:        while(fgets(buf, sizeof(buf), spoolfp) != NULL) {
                    541:                (void) fputs(buf, out);
                    542:        }
                    543:        (void) pclose(out);
                    544: }

unix.superglobalmegacorp.com

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