Annotation of 40BSD/cmd/delivermail/deliver.c, revision 1.1.1.1

1.1       root        1: # include <stdio.h>
                      2: # include <pwd.h>
                      3: # include <signal.h>
                      4: # include "dlvrmail.h"
                      5: # ifdef LOG
                      6: # include <log.h>
                      7: # endif LOG
                      8: 
                      9: static char SccsId[] = "@(#)deliver.c  1.11    10/27/80";
                     10: 
                     11: /*
                     12: **  DELIVER -- Deliver a message to a particular address.
                     13: **
                     14: **     Algorithm:
                     15: **             Compute receiving network (i.e., mailer), host, & user.
                     16: **             If local, see if this is really a program name.
                     17: **             Build argument for the mailer.
                     18: **             Create pipe through edit fcn if appropriate.
                     19: **             Fork.
                     20: **                     Child: call mailer
                     21: **             Parent: call editfcn if specified.
                     22: **             Wait for mailer to finish.
                     23: **             Interpret exit status.
                     24: **
                     25: **     Parameters:
                     26: **             to -- the address to deliver the message to.
                     27: **             editfcn -- if non-NULL, we want to call this function
                     28: **                     to output the letter (instead of just out-
                     29: **                     putting it raw).
                     30: **
                     31: **     Returns:
                     32: **             zero -- successfully delivered.
                     33: **             else -- some failure, see ExitStat for more info.
                     34: **
                     35: **     Side Effects:
                     36: **             The standard input is passed off to someone.
                     37: **
                     38: **     WARNING:
                     39: **             The standard input is shared amongst all children,
                     40: **             including the file pointer.  It is critical that the
                     41: **             parent waits for the child to finish before forking
                     42: **             another child.
                     43: **
                     44: **     Called By:
                     45: **             main
                     46: **             savemail
                     47: **
                     48: **     Files:
                     49: **             standard input -- must be opened to the message to
                     50: **                     deliver.
                     51: */
                     52: 
                     53: deliver(to, editfcn)
                     54:        addrq *to;
                     55:        int (*editfcn)();
                     56: {
                     57:        register struct mailer *m;
                     58:        char *host;
                     59:        char *user;
                     60:        extern struct passwd *getpwnam();
                     61:        char **pvp;
                     62:        extern char **buildargv();
                     63:        auto int st;
                     64:        register int i;
                     65:        register char *p;
                     66:        int pid;
                     67:        int pvect[2];
                     68:        extern FILE *fdopen();
                     69:        extern int errno;
                     70:        FILE *mfile;
                     71:        extern putheader();
                     72:        extern pipesig();
                     73: 
                     74:        /*
                     75:        **  Compute receiving mailer, host, and to addreses.
                     76:        **      Do some initialization first.  To is the to address
                     77:        **      for error messages.
                     78:        */
                     79: 
                     80:        To = to->q_paddr;
                     81:        m = to->q_mailer;
                     82:        user = to->q_user;
                     83:        host = to->q_host;
                     84:        Errors = 0;
                     85:        errno = 0;
                     86: # ifdef DEBUG
                     87:        if (Debug)
                     88:                printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user);
                     89: # endif DEBUG
                     90: 
                     91:        /*
                     92:        **  Remove quote bits from user/host.
                     93:        */
                     94: 
                     95:        for (p = user; (*p++ &= 0177) != '\0'; )
                     96:                continue;
                     97:        if (host != NULL)
                     98:                for (p = host; (*p++ &= 0177) != '\0'; )
                     99:                        continue;
                    100:        
                    101:        /*
                    102:        **  Strip quote bits from names if the mailer wants it.
                    103:        */
                    104: 
                    105:        if (flagset(M_STRIPQ, m->m_flags))
                    106:        {
                    107:                stripquotes(user);
                    108:                stripquotes(host);
                    109:        }
                    110: 
                    111:        /*
                    112:        **  See if this user name is "special".
                    113:        **      If the user is a program, diddle with the mailer spec.
                    114:        **      If the user name has a slash in it, assume that this
                    115:        **              is a file -- send it off without further ado.
                    116:        **              Note that this means that editfcn's will not
                    117:        **              be applied to the message.
                    118:        */
                    119: 
                    120:        if (m == &Mailer[0])
                    121:        {
                    122:                if (*user == '|')
                    123:                {
                    124:                        user++;
                    125:                        m = &Mailer[1];
                    126:                }
                    127:                else
                    128:                {
                    129:                        if (index(user, '/') != NULL)
                    130:                        {
                    131:                                i = mailfile(user);
                    132:                                giveresponse(i, TRUE, m);
                    133:                                return (i);
                    134:                        }
                    135:                }
                    136:        }
                    137: 
                    138:        /*
                    139:        **  See if the user exists.
                    140:        **      Strictly, this is only needed to print a pretty
                    141:        **      error message.
                    142:        **
                    143:        **      >>>>>>>>>> This clause assumes that the local mailer
                    144:        **      >> NOTE >> cannot do any further aliasing; that
                    145:        **      >>>>>>>>>> function is subsumed by delivermail.
                    146:        */
                    147: 
                    148:        if (m == &Mailer[0])
                    149:        {
                    150:                if (getpwnam(user) == NULL)
                    151:                {
                    152:                        giveresponse(EX_NOUSER, TRUE, m);
                    153:                        return (EX_NOUSER);
                    154:                }
                    155:        }
                    156: 
                    157:        /*
                    158:        **  If the mailer wants a From line, insert a new editfcn.
                    159:        */
                    160: 
                    161:        if (flagset(M_HDR, m->m_flags) && editfcn == NULL)
                    162:                editfcn = putheader;
                    163: 
                    164:        /*
                    165:        **  Call the mailer.
                    166:        **      The argument vector gets built, pipes through 'editfcn'
                    167:        **      are created as necessary, and we fork & exec as
                    168:        **      appropriate.  In the parent, we call 'editfcn'.
                    169:        */
                    170: 
                    171:        pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr);
                    172:        if (pvp == NULL)
                    173:        {
                    174:                usrerr("name too long");
                    175:                return (-1);
                    176:        }
                    177:        rewind(stdin);
                    178: 
                    179:        /* create a pipe if we will need one */
                    180:        if (editfcn != NULL && pipe(pvect) < 0)
                    181:        {
                    182:                syserr("pipe");
                    183:                return (-1);
                    184:        }
                    185: # ifdef VFORK
                    186:        pid = vfork();
                    187: # else
                    188:        pid = fork();
                    189: # endif
                    190:        if (pid < 0)
                    191:        {
                    192:                syserr("Cannot fork");
                    193:                if (editfcn != NULL)
                    194:                {
                    195:                        close(pvect[0]);
                    196:                        close(pvect[1]);
                    197:                }
                    198:                return (-1);
                    199:        }
                    200:        else if (pid == 0)
                    201:        {
                    202:                /* child -- set up input & exec mailer */
                    203:                /* make diagnostic output be standard output */
                    204:                close(2);
                    205:                dup(1);
                    206:                signal(SIGINT, SIG_IGN);
                    207:                if (editfcn != NULL)
                    208:                {
                    209:                        close(0);
                    210:                        if (dup(pvect[0]) < 0)
                    211:                        {
                    212:                                syserr("Cannot dup to zero!");
                    213:                                _exit(EX_OSERR);
                    214:                        }
                    215:                        close(pvect[0]);
                    216:                        close(pvect[1]);
                    217:                }
                    218:                if (!flagset(M_RESTR, m->m_flags))
                    219:                        setuid(getuid());
                    220: # ifdef LOG
                    221:                initlog(NULL, 0, LOG_CLOSE);
                    222: # endif LOG
                    223: # ifndef VFORK
                    224:                /*
                    225:                 * We have to be careful with vfork - we can't mung up the
                    226:                 * memory but we don't want the mailer to inherit any extra
                    227:                 * open files.  Chances are the mailer won't
                    228:                 * care about an extra file, but then again you never know.
                    229:                 * Actually, we would like to close(fileno(pwf)), but it's
                    230:                 * declared static so we can't.  But if we fclose(pwf), which
                    231:                 * is what endpwent does, it closes it in the parent too and
                    232:                 * the next getpwnam will be slower.  If you have a weird mailer
                    233:                 * that chokes on the extra file you should do the endpwent().
                    234:                 */
                    235:                endpwent();
                    236: # endif
                    237:                execv(m->m_mailer, pvp);
                    238:                /* syserr fails because log is closed */
                    239:                /* syserr("Cannot exec %s", m->m_mailer); */
                    240:                _exit(EX_UNAVAILABLE);
                    241:        }
                    242: 
                    243:        /* arrange to write out header message if error */
                    244:        if (editfcn != NULL)
                    245:        {
                    246:                close(pvect[0]);
                    247:                signal(SIGPIPE, pipesig);
                    248:                mfile = fdopen(pvect[1], "w");
                    249:                (*editfcn)(mfile);
                    250:                fclose(mfile);
                    251:        }
                    252: 
                    253:        /*
                    254:        **  Wait for child to die and report status.
                    255:        **      We should never get fatal errors (e.g., segmentation
                    256:        **      violation), so we report those specially.  For other
                    257:        **      errors, we choose a status message (into statmsg),
                    258:        **      and if it represents an error, we print it.
                    259:        */
                    260: 
                    261:        while ((i = wait(&st)) > 0 && i != pid)
                    262:                continue;
                    263:        if (i < 0)
                    264:        {
                    265:                syserr("wait");
                    266:                return (-1);
                    267:        }
                    268:        if ((st & 0377) != 0)
                    269:        {
                    270:                syserr("%s: stat %o", pvp[0], st);
                    271:                ExitStat = EX_UNAVAILABLE;
                    272:                return (-1);
                    273:        }
                    274:        i = (st >> 8) & 0377;
                    275:        giveresponse(i, FALSE, m);
                    276:        return (i);
                    277: }
                    278: /*
                    279: **  GIVERESPONSE -- Interpret an error response from a mailer
                    280: **
                    281: **     Parameters:
                    282: **             stat -- the status code from the mailer (high byte
                    283: **                     only; core dumps must have been taken care of
                    284: **                     already).
                    285: **             force -- if set, force an error message output, even
                    286: **                     if the mailer seems to like to print its own
                    287: **                     messages.
                    288: **             m -- the mailer descriptor for this mailer.
                    289: **
                    290: **     Returns:
                    291: **             none.
                    292: **
                    293: **     Side Effects:
                    294: **             Errors may be incremented.
                    295: **             ExitStat may be set.
                    296: **
                    297: **     Called By:
                    298: **             deliver
                    299: */
                    300: 
                    301: giveresponse(stat, force, m)
                    302:        int stat;
                    303:        int force;
                    304:        register struct mailer *m;
                    305: {
                    306:        register char *statmsg;
                    307:        extern char *SysExMsg[];
                    308:        register int i;
                    309:        extern int N_SysEx;
                    310:        extern long MsgSize;
                    311:        char buf[30];
                    312: 
                    313:        i = stat - EX__BASE;
                    314:        if (i < 0 || i > N_SysEx)
                    315:                statmsg = NULL;
                    316:        else
                    317:                statmsg = SysExMsg[i];
                    318:        if (stat == 0)
                    319:                statmsg = "ok";
                    320:        else
                    321:        {
                    322:                Errors++;
                    323:                if (statmsg == NULL && m->m_badstat != 0)
                    324:                {
                    325:                        stat = m->m_badstat;
                    326:                        i = stat - EX__BASE;
                    327: # ifdef DEBUG
                    328:                        if (i < 0 || i >= N_SysEx)
                    329:                                syserr("Bad m_badstat %d", stat);
                    330:                        else
                    331: # endif DEBUG
                    332:                        statmsg = SysExMsg[i];
                    333:                }
                    334:                if (statmsg == NULL)
                    335:                        usrerr("unknown mailer response %d", stat);
                    336:                else if (force || !flagset(M_QUIET, m->m_flags))
                    337:                        usrerr("%s", statmsg);
                    338:        }
                    339: 
                    340:        /*
                    341:        **  Final cleanup.
                    342:        **      Log a record of the transaction.  Compute the new
                    343:        **      ExitStat -- if we already had an error, stick with
                    344:        **      that.
                    345:        */
                    346: 
                    347:        if (statmsg == NULL)
                    348:        {
                    349:                sprintf(buf, "error %d", stat);
                    350:                statmsg = buf;
                    351:        }
                    352: 
                    353: # ifdef LOG
                    354:        logmsg(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
                    355: # endif LOG
                    356:        setstat(stat);
                    357:        return (stat);
                    358: }
                    359: /*
                    360: **  PUTHEADER -- insert the From header into some mail
                    361: **
                    362: **     For mailers such as 'msgs' that want the header inserted
                    363: **     into the mail, this edit filter inserts the From line and
                    364: **     then passes the rest of the message through.
                    365: **
                    366: **     Parameters:
                    367: **             fp -- the file pointer for the output.
                    368: **
                    369: **     Returns:
                    370: **             none
                    371: **
                    372: **     Side Effects:
                    373: **             Puts a "From" line in UNIX format, and then
                    374: **                     outputs the rest of the message.
                    375: **
                    376: **     Called By:
                    377: **             deliver
                    378: */
                    379: 
                    380: putheader(fp)
                    381:        register FILE *fp;
                    382: {
                    383:        char buf[MAXLINE + 1];
                    384:        long tim;
                    385:        extern char *ctime();
                    386: 
                    387:        time(&tim);
                    388:        fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim));
                    389:        while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp))
                    390:                fputs(buf, fp);
                    391:        if (ferror(fp))
                    392:        {
                    393:                syserr("putheader: write error");
                    394:                setstat(EX_IOERR);
                    395:        }
                    396: }
                    397: /*
                    398: **  PIPESIG -- Handle broken pipe signals
                    399: **
                    400: **     This just logs an error.
                    401: **
                    402: **     Parameters:
                    403: **             none
                    404: **
                    405: **     Returns:
                    406: **             none
                    407: **
                    408: **     Side Effects:
                    409: **             logs an error message.
                    410: */
                    411: 
                    412: pipesig()
                    413: {
                    414:        syserr("Broken pipe");
                    415:        signal(SIGPIPE, SIG_IGN);
                    416: }
                    417: /*
                    418: **  SENDTO -- Designate a send list.
                    419: **
                    420: **     The parameter is a comma-separated list of people to send to.
                    421: **     This routine arranges to send to all of them.
                    422: **
                    423: **     Parameters:
                    424: **             list -- the send list.
                    425: **             copyf -- the copy flag; passed to parse.
                    426: **
                    427: **     Returns:
                    428: **             none
                    429: **
                    430: **     Side Effects:
                    431: **             none.
                    432: **
                    433: **     Called By:
                    434: **             main
                    435: **             alias
                    436: */
                    437: 
                    438: sendto(list, copyf)
                    439:        char *list;
                    440:        int copyf;
                    441: {
                    442:        register char *p;
                    443:        register char *q;
                    444:        register char c;
                    445:        addrq *a;
                    446:        extern addrq *parse();
                    447:        bool more;
                    448: 
                    449:        /* more keeps track of what the previous delimiter was */
                    450:        more = TRUE;
                    451:        for (p = list; more; )
                    452:        {
                    453:                /* find the end of this address */
                    454:                q = p;
                    455:                while ((c = *p++) != '\0' && c != ',' && c != '\n')
                    456:                        continue;
                    457:                more = c != '\0';
                    458:                *--p = '\0';
                    459:                if (more)
                    460:                        p++;
                    461: 
                    462:                /* parse the address */
                    463:                if ((a = parse(q, (addrq *) NULL, copyf)) == NULL)
                    464:                        continue;
                    465: 
                    466:                /* arrange to send to this person */
                    467:                recipient(a, &SendQ);
                    468:        }
                    469:        To = NULL;
                    470: }
                    471: /*
                    472: **  RECIPIENT -- Designate a message recipient
                    473: **
                    474: **     Saves the named person for future mailing.
                    475: **
                    476: **     Designates a person as a recipient.  This routine
                    477: **     does the initial parsing, and checks to see if
                    478: **     this person has already received the mail.
                    479: **     It also supresses local network names and turns them into
                    480: **     local names.
                    481: **
                    482: **     Parameters:
                    483: **             a -- the (preparsed) address header for the recipient.
                    484: **             targetq -- the queue to add the name to.
                    485: **
                    486: **     Returns:
                    487: **             none.
                    488: **
                    489: **     Side Effects:
                    490: **             none.
                    491: **
                    492: **     Called By:
                    493: **             sendto
                    494: **             main
                    495: */
                    496: 
                    497: recipient(a, targetq)
                    498:        register addrq *a;
                    499:        addrq *targetq;
                    500: {
                    501:        register addrq *q;
                    502:        register struct mailer *m;
                    503:        register char **pvp;
                    504:        extern char *xalloc();
                    505:        extern bool forward();
                    506:        extern int errno;
                    507:        extern bool sameaddr();
                    508: 
                    509:        To = a->q_paddr;
                    510:        m = a->q_mailer;
                    511:        errno = 0;
                    512: # ifdef DEBUG
                    513:        if (Debug)
                    514:                printf("recipient(%s)\n", To);
                    515: # endif DEBUG
                    516: 
                    517:        /*
                    518:        **  Look up this person in the recipient list.  If they
                    519:        **  are there already, return, otherwise continue.
                    520:        */
                    521: 
                    522:        if (!ForceMail)
                    523:        {
                    524:                for (q = &SendQ; (q = nxtinq(q)) != NULL; )
                    525:                        if (sameaddr(q, a, FALSE))
                    526:                        {
                    527: # ifdef DEBUG
                    528:                                if (Debug)
                    529:                                        printf("(%s in SendQ)\n", a->q_paddr);
                    530: # endif DEBUG
                    531:                                return;
                    532:                        }
                    533:                for (q = &AliasQ; (q = nxtinq(q)) != NULL; )
                    534:                        if (sameaddr(q, a, FALSE))
                    535:                        {
                    536: # ifdef DEBUG
                    537:                                if (Debug)
                    538:                                        printf("(%s in AliasQ)\n", a->q_paddr);
                    539: # endif DEBUG
                    540:                                return;
                    541:                        }
                    542:        }
                    543: 
                    544:        /*
                    545:        **  See if the user wants hir mail forwarded.
                    546:        **      `Forward' must do the forwarding recursively.
                    547:        */
                    548: 
                    549:        if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a))
                    550:                return;
                    551: 
                    552:        /*
                    553:        **  Put the user onto the target queue.
                    554:        */
                    555: 
                    556:        if (targetq != NULL)
                    557:        {
                    558:                putonq(a, targetq);
                    559:        }
                    560: 
                    561:        return;
                    562: }
                    563: /*
                    564: **  BUILDARGV -- Build an argument vector for a mail server.
                    565: **
                    566: **     Using a template defined in config.c, an argv is built.
                    567: **     The format of the template is already a vector.  The
                    568: **     items of this vector are copied, unless a dollar sign
                    569: **     is encountered.  In this case, the next character
                    570: **     specifies something else to copy in.  These can be
                    571: **             $f      The from address.
                    572: **             $h      The host.
                    573: **             $u      The user.
                    574: **             $c      The hop count.
                    575: **     The vector is built in a local buffer.  A pointer to
                    576: **     the static argv is returned.
                    577: **
                    578: **     Parameters:
                    579: **             tmplt -- a template for an argument vector.
                    580: **             flags -- the flags for this server.
                    581: **             host -- the host name to send to.
                    582: **             user -- the user name to send to.
                    583: **             from -- the person this mail is from.
                    584: **
                    585: **     Returns:
                    586: **             A pointer to an argv.
                    587: **
                    588: **     Side Effects:
                    589: **             none
                    590: **
                    591: **     WARNING:
                    592: **             Since the argv is staticly allocated, any subsequent
                    593: **             calls will clobber the old argv.
                    594: **
                    595: **     Called By:
                    596: **             deliver
                    597: */
                    598: 
                    599: char **
                    600: buildargv(tmplt, flags, host, user, from)
                    601:        char **tmplt;
                    602:        int flags;
                    603:        char *host;
                    604:        char *user;
                    605:        char *from;
                    606: {
                    607:        register char *p;
                    608:        register char *q;
                    609:        static char *pv[MAXPV+1];
                    610:        char **pvp;
                    611:        char **mvp;
                    612:        static char buf[512];
                    613:        register char *bp;
                    614:        char pbuf[30];
                    615: 
                    616:        /*
                    617:        **  Do initial argv setup.
                    618:        **      Insert the mailer name.  Notice that $x expansion is
                    619:        **      NOT done on the mailer name.  Then, if the mailer has
                    620:        **      a picky -f flag, we insert it as appropriate.  This
                    621:        **      code does not check for 'pv' overflow; this places a
                    622:        **      manifest lower limit of 4 for MAXPV.
                    623:        */
                    624: 
                    625:        pvp = pv;
                    626:        bp = buf;
                    627: 
                    628:        *pvp++ = tmplt[0];
                    629: 
                    630:        /* insert -f or -r flag as appropriate */
                    631:        if (flagset(M_FOPT|M_ROPT, flags) && FromFlag)
                    632:        {
                    633:                if (flagset(M_FOPT, flags))
                    634:                        *pvp++ = "-f";
                    635:                else
                    636:                        *pvp++ = "-r";
                    637:                *pvp++ = From.q_paddr;
                    638:        }
                    639: 
                    640:        /*
                    641:        **  Build the rest of argv.
                    642:        **      For each prototype parameter, the prototype is
                    643:        **      scanned character at a time.  If a dollar-sign is
                    644:        **      found, 'q' is set to the appropriate expansion,
                    645:        **      otherwise it is null.  Then either the string
                    646:        **      pointed to by q, or the original character, is
                    647:        **      interpolated into the buffer.  Buffer overflow is
                    648:        **      checked.
                    649:        */
                    650: 
                    651:        for (mvp = tmplt; (p = *++mvp) != NULL; )
                    652:        {
                    653:                if (pvp >= &pv[MAXPV])
                    654:                {
                    655:                        syserr("Too many parameters to %s", pv[0]);
                    656:                        return (NULL);
                    657:                }
                    658:                *pvp++ = bp;
                    659:                for (; *p != '\0'; p++)
                    660:                {
                    661:                        /* q will be the interpolated quantity */
                    662:                        q = NULL;
                    663:                        if (*p == '$')
                    664:                        {
                    665:                                switch (*++p)
                    666:                                {
                    667:                                  case 'f':     /* from person */
                    668:                                        q = from;
                    669:                                        break;
                    670: 
                    671:                                  case 'u':     /* user */
                    672:                                        q = user;
                    673:                                        break;
                    674: 
                    675:                                  case 'h':     /* host */
                    676:                                        q = host;
                    677:                                        break;
                    678: 
                    679:                                  case 'c':     /* hop count */
                    680:                                        sprintf(pbuf, "%d", HopCount);
                    681:                                        q = pbuf;
                    682:                                        break;
                    683:                                }
                    684:                        }
                    685: 
                    686:                        /*
                    687:                        **  Interpolate q or output one character
                    688:                        **      Strip quote bits as we proceed.....
                    689:                        */
                    690: 
                    691:                        if (q != NULL)
                    692:                        {
                    693:                                while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0')
                    694:                                        continue;
                    695:                                bp--;
                    696:                        }
                    697:                        else if (bp < &buf[sizeof buf - 1])
                    698:                                *bp++ = *p;
                    699:                }
                    700:                *bp++ = '\0';
                    701:                if (bp >= &buf[sizeof buf - 1])
                    702:                        return (NULL);
                    703:        }
                    704:        *pvp = NULL;
                    705: 
                    706: # ifdef DEBUG
                    707:        if (Debug)
                    708:        {
                    709:                printf("Interpolated argv is:\n");
                    710:                for (mvp = pv; *mvp != NULL; mvp++)
                    711:                        printf("\t%s\n", *mvp);
                    712:        }
                    713: # endif DEBUG
                    714: 
                    715:        return (pv);
                    716: }
                    717: /*
                    718: **  MAILFILE -- Send a message to a file.
                    719: **
                    720: **     Parameters:
                    721: **             filename -- the name of the file to send to.
                    722: **
                    723: **     Returns:
                    724: **             The exit code associated with the operation.
                    725: **
                    726: **     Side Effects:
                    727: **             none.
                    728: **
                    729: **     Called By:
                    730: **             deliver
                    731: */
                    732: 
                    733: mailfile(filename)
                    734:        char *filename;
                    735: {
                    736:        char buf[MAXLINE];
                    737:        register FILE *f;
                    738:        auto long tim;
                    739:        extern char *ctime();
                    740: 
                    741:        f = fopen(filename, "a");
                    742:        if (f == NULL)
                    743:                return (EX_CANTCREAT);
                    744:        
                    745:        /* output the timestamp */
                    746:        time(&tim);
                    747:        fprintf(f, "From %s %s", From.q_paddr, ctime(&tim));
                    748:        rewind(stdin);
                    749:        while (fgets(buf, sizeof buf, stdin) != NULL)
                    750:        {
                    751:                fputs(buf, f);
                    752:                if (ferror(f))
                    753:                {
                    754:                        fclose(f);
                    755:                        return (EX_IOERR);
                    756:                }
                    757:        }
                    758:        fputs("\n", f);
                    759:        fclose(f);
                    760:        return (EX_OK);
                    761: }

unix.superglobalmegacorp.com

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