Annotation of researchv10no/cmd/nupas/smtp/conversed.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char *sccsid = "@(#)converse.c  1.9 87/07/31";
                      3: #endif lint
                      4: /*  Copyright 1984 Massachusetts Institute of Technology
                      5: 
                      6: Permission to use, copy, modify, and distribute this program
                      7: for any purpose and without fee is hereby granted, provided
                      8: that this copyright and permission notice appear on all copies
                      9: and supporting documentation, the name of M.I.T. not be used
                     10: in advertising or publicity pertaining to distribution of the
                     11: program without specific prior permission, and notice be given
                     12: in supporting documentation that copying and distribution is
                     13: by permission of M.I.T.  M.I.T. makes no representations about
                     14: the suitability of this software for any purpose.  It is pro-
                     15: vided "as is" without express or implied warranty.             */
                     16: 
                     17: /*
                     18:  *  I've raped this code severely.  Bugs could be
                     19:  *  MIT's or mine. -- presotto
                     20:  *
                     21:  *  Me too.  -- ches
                     22:  */
                     23: 
                     24: /*
                     25:  * smtpd - World's most trivial SMTP server.  Only accepts the MAIL, FROM,
                     26:  * RCPT, and DATA commands.  Generates a data file for the mail
                     27:  * daemon and kicks the mail daemon off.
                     28:  */
                     29: 
                     30: #include <stdio.h>
                     31: #include <signal.h>
                     32: #include <ctype.h>
                     33: 
                     34: #include <fcntl.h>
                     35: #include <string.h>
                     36: #include <sysexits.h>
                     37: 
                     38: #include "mail.h"
                     39: #include "smtp.h"
                     40: #include "cmds.h"
                     41: #include "string.h"
                     42: 
                     43: /* fundamental constants */
                     44: #define TRUE 1
                     45: #define FALSE 0
                     46: #define SECONDS                1
                     47: #define MINUTES                60
                     48: #define HOURS          (60 * MINUTES)
                     49: 
                     50: /* tunable constants */
                     51: #define        SHORTTIME       (5 * MINUTES)   /* enough time for easy stuff */
                     52: #define        LONGTIME        (2 * HOURS)     /* max time, DATA to `.' */
                     53: 
                     54: 
                     55: static string *rcvrs;
                     56: 
                     57: FILE   *datafd;                        /* data file descriptor */
                     58: FILE   *fi;                            /* fd from remote host */
                     59: FILE   *fo;                            /* fd to remote host */
                     60: 
                     61: char   dataname[NAMSIZ], rcptto[BUFSIZ];               /* data file name */
                     62: 
                     63: typedef int event;
                     64: 
                     65: static void terminate();
                     66: 
                     67: extern char *convertaddr();
                     68: extern char *UPASROOT;
                     69: extern int death();
                     70: extern int alarmsend();
                     71: extern char *helohost;
                     72: extern char *thishost;
                     73: extern int queuing;
                     74: extern int norun;
                     75: extern char *spoolsubdir[];
                     76: 
                     77: int    n_rcpt = 0;
                     78: long   nbytes = 0;
                     79: int    virus = 0;
                     80: 
                     81: static char mailfrom[BUFSIZ];
                     82: static char *fromaddr;
                     83: 
                     84: 
                     85: #ifndef NOFILE
                     86: #define NOFILE 32
                     87: #endif /*NOFILE*/
                     88: 
                     89: SIGRETURN
                     90: alarmtr(s)
                     91:        int s;
                     92: {
                     93:        Syslog(LOG_INFO, "timed out");
                     94:        death(EX_TEMPFAIL);
                     95: }
                     96: 
                     97: /*
                     98:  * This is the routine which processes incoming smtp commands from the
                     99:  * user.  It goes to sleep awaiting network input.  When a complete
                    100:  * command is received, the tcp receiver task awakens us to process it.
                    101:  * Currently only the commands listed in the command table are accepted.
                    102:  * This routine never returns.
                    103:  */
                    104: converse(rfi, rfo)
                    105:        FILE *rfi, *rfo;
                    106: {
                    107:        char greeting[MAXSTR];
                    108: 
                    109:        fo = rfo;
                    110:        fi = rfi;
                    111: 
                    112:        (void) signal(SIGALRM, alarmtr);
                    113:        (void) alarm(SHORTTIME);        /* make sure we eventually go away */
                    114:        (void) sprintf(greeting, "220 %s SMTP\n", helohost);
                    115:        csend(LOG_DEBUG, greeting);
                    116: 
                    117:        do_helo(fi, fo);                /* wait for the hello */
                    118: 
                    119:        /*
                    120:         *  avoid annoying interuptions
                    121:         */
                    122:        signal(SIGHUP, SIG_IGN);
                    123:        signal(SIGPIPE, SIG_IGN);
                    124: 
                    125:        for (;;) {                      /* until QUIT */
                    126:                n_rcpt = 0;
                    127:                rcvrs = s_reset(rcvrs);
                    128:                *dataname = *rcptto = 0;
                    129:                fromaddr = 0;
                    130:                if (!do_mail(fi, fo))
                    131:                        continue;       /* wait for the mail command */
                    132:                while (do_rcpt(fi, fo)) /* do all the recipients */
                    133:                        n_rcpt++;
                    134:                (void) alarm(LONGTIME);
                    135:                do_data(fi, fo);        /* do the data */
                    136:        }
                    137: }
                    138: 
                    139: /*
                    140:  *  Wait for the user to send the HELO command.  Punt out if he sends
                    141:  *  QUIT or RSET.
                    142:  *
                    143:  *  The spooling directory depends on the calling host.  The host name
                    144:  *  is used to connect to the appropriate spool directory.
                    145:  */
                    146: do_helo(fi, fo)
                    147: FILE *fi, *fo;
                    148: {
                    149:        char    cmdbuf[MAXSTR];
                    150:        char    greeting[MAXSTR], *nlptr;
                    151:        int     buflen;
                    152:        char    *hp;
                    153:        char    *parse_hello();
                    154: 
                    155:        for (;;) {              /* until HELO, or QUIT */
                    156:                buflen = crecv(cmdbuf, sizeof cmdbuf, fi);      /* wait for command */
                    157:                switch (cmdparse(cmdbuf, buflen)) {
                    158:                case QUIT:
                    159:                        quit(fi, fo);
                    160:                case RSET:
                    161:                case NOOP:
                    162:                        csend(LOG_DEBUG, "250 OK\n");
                    163:                        continue;
                    164:                case HELO:
                    165:                        hp = parse_hello(cmdbuf, sizeof(cmdbuf));
                    166:                        Syslog(LOG_DEBUG, "HELO from %s", hp);
                    167:                        if(gotodir(hp)<0){      
                    168:                                csend(LOG_ALERT, "451 Transaction failed -- Could not access spool directory.\n");
                    169:                                death(EX_OSERR);
                    170:                        }
                    171:                        (void) sprintf(greeting, "250 %s\n", helohost);
                    172:                        csend(LOG_DEBUG, greeting);
                    173:                        return;
                    174:                case DEBG:
                    175:                        Syslog(LOG_ALERT, "DEBUG attempt");
                    176:                        csend(LOG_DEBUG, "200 OK\n");
                    177:                        virus = 1;
                    178:                        continue;
                    179:                case NONE:
                    180:                        bitch(cmdbuf, fo);
                    181:                        continue;
                    182:                default:
                    183:                        csend(LOG_DEBUG, "503 Expecting HELO\n");
                    184:                        continue;
                    185:                }
                    186:        }
                    187: }
                    188: 
                    189: /*
                    190:  * Wait for the user to send the MAIL command.  Punt out if he sends
                    191:  * QUIT.  Return false if he said RSET, so we can start over.
                    192:  */
                    193: do_mail(fi, fo)
                    194: FILE *fi, *fo;
                    195: {
                    196:        char    cmdbuf[MAXSTR];
                    197:        char    gripe[MAXSTR], *nlptr;
                    198:        int     buflen;
                    199: 
                    200:        for (;;) {              /* until MAIL, QUIT, or RSET */
                    201:                buflen = crecv(cmdbuf, sizeof cmdbuf, fi);      /* wait for command */
                    202:                switch (cmdparse(cmdbuf, buflen)) {
                    203:                case QUIT:
                    204:                        quit(fi, fo);
                    205:                case NOOP:
                    206:                        csend(LOG_DEBUG, "250 OK\n");
                    207:                        continue;
                    208:                case MAIL:
                    209:                        strcpy(mailfrom, cmdbuf);
                    210:                        csend(LOG_DEBUG, "250 OK\n");
                    211:                        return(TRUE);
                    212:                case DEBG:
                    213:                        Syslog(LOG_ALERT, "DEBUG attempt");
                    214:                        csend(LOG_WARNING, "200 OK\n");
                    215:                        virus = 1;
                    216:                        continue;
                    217:                case VRFY:
                    218:                        csend(LOG_INFO, "252 Cannot VRFY user\n");
                    219:                        continue;
                    220:                case NONE:
                    221:                        bitch(cmdbuf, fo);
                    222:                        continue;
                    223:                case RSET:
                    224:                        csend(LOG_DEBUG, "250 OK\n");
                    225:                        return(FALSE);
                    226:                default:
                    227:                        csend(LOG_DEBUG, "503 Expecting MAIL\n");
                    228:                        continue;
                    229:                }
                    230:        }
                    231: }
                    232: 
                    233: /*
                    234:  * Wait for the user to send the RCPT command.  Punt out if he sends
                    235:  * QUIT or RSET.  Returns TRUE if a RCPT command was received, FALSE
                    236:  * if a DATA command was received.
                    237:  */
                    238: do_rcpt(fi, fo)
                    239: FILE *fi, *fo;
                    240: {
                    241:        char    cmdbuf[MAXSTR];
                    242:        char    gripe[MAXSTR], *nlptr;
                    243:        int     buflen;
                    244:        int     i;
                    245: 
                    246:        for (;;) {              /* until RCPT, DATA, QUIT, or RSET */
                    247:                buflen = crecv(cmdbuf, sizeof cmdbuf, fi);      /* wait for command */
                    248:                switch (cmdparse(cmdbuf, buflen)) {
                    249:                case QUIT:
                    250:                        quit(fi, fo);
                    251:                case NOOP:
                    252:                        csend(LOG_DEBUG, "250 OK\n");
                    253:                        continue;
                    254:                case RCPT:
                    255:                        if (!parse_rcpt(cmdbuf, buflen)) {
                    256:                                csend(LOG_DEBUG, "501 Syntax error in recipient name\n");
                    257:                                continue;
                    258:                        }
                    259:                        csend(LOG_DEBUG, "250 OK\n");
                    260:                        return(TRUE);
                    261:                case DATA:
                    262:                        if (*s_to_c(rcvrs) == 0) {
                    263:                                csend(LOG_DEBUG, "503 Expecting RCPT\n");
                    264:                                continue;
                    265:                        }
                    266:                        if ((i=init_xfr()) < 0) {       /* set up data file */
                    267:                                char buf[100];
                    268:                                sprintf(buf, "451 Can't initialize files in spool directory  %s(%d)\n",
                    269:                                        dataname, i);
                    270:                                csend(LOG_ALERT, buf);
                    271:                                death(EX_CANTCREAT);
                    272:                        }
                    273:                        csend(LOG_DEBUG, "354 Start mail input; end with <CRLF>.<CRLF>\n");
                    274:                        return(FALSE);
                    275:                case VRFY:
                    276:                        csend(LOG_INFO, "252 Cannot VRFY user\n");
                    277:                        continue;
                    278:                case DEBG:
                    279:                        Syslog(LOG_ALERT, "DEBUG attempt");
                    280:                        csend(LOG_WARNING, "200 OK\n");
                    281:                        virus = 1;
                    282:                        continue;
                    283:                case RSET:  /* this code doesn't handle this here.  Feign ignorance. */
                    284:                case NONE:
                    285:                        bitch(cmdbuf, fo);
                    286:                        continue;
                    287:                default:
                    288:                        csend(LOG_DEBUG, "503 Expecting RCPT or DATA\n");
                    289:                        continue;
                    290:                }
                    291:        }
                    292: }
                    293: 
                    294: /*
                    295:  *  input a line at a time till a <cr>.<cr>.  return the count of the characters
                    296:  *  input.  if EOF is reached, return -1.  if <cr>.<cr> is reached, return 0.
                    297:  */
                    298: static int atend;              /* true when <cr>.<cr> is reached */
                    299: 
                    300: char *
                    301: smfgets(buf, len, fi)
                    302:        char *buf;
                    303:        int len;
                    304:        FILE *fi;
                    305: {
                    306:        int n;
                    307:        int i;
                    308: 
                    309:        if(atend)
                    310:                return NULL;
                    311:        n = tgets(buf, len, fi);
                    312:        if (n < 0)
                    313:                return NULL;
                    314:        if (buf[0] == '.') {
                    315:                if(buf[1] == '\n'){
                    316:                        atend = 1;
                    317:                        return NULL;
                    318:                } else if(buf[1] == '.'){
                    319:                        for(i=1; i<=n; i++)
                    320:                                buf[i-1] = buf[i];
                    321:                }
                    322:        }
                    323:        nbytes += n;
                    324:        return buf;
                    325: }
                    326: 
                    327: do_data(fi, fo)
                    328: FILE *fi, *fo;
                    329: {
                    330:        string *cc;
                    331:        int pid, wpid;
                    332:        char gripe[MAXSTR];
                    333:        char cmd[MAXSTR];
                    334:        char ctlfile[MAXSTR];
                    335:        int ac, i;
                    336:        char *cp;
                    337: 
                    338:        clearerr(fi);
                    339:        clearerr(datafd);
                    340: 
                    341:        /*
                    342:         *  read data message
                    343:         */
                    344:        atend = nbytes = 0;
                    345:        from822(thishost, smfgets, fi, datafd, fromaddr, helohost);
                    346:        fflush(datafd);
                    347:        if(ferror(datafd) || ferror(fi)){
                    348:                fclose(datafd);
                    349:                unlink(dataname);
                    350:                csend(LOG_ALERT, "451 Transaction failed -- error writing data file\n");
                    351:                death(EX_IOERR);
                    352:        }
                    353:        fclose(datafd);
                    354: 
                    355:        /*
                    356:         *  create a control file.  the two lines are
                    357:         *      <reply-address> <recipients>
                    358:         *      <recipients>
                    359:         */
                    360:        cc = s_new();
                    361:        if (fromaddr == (char *)0 || *fromaddr == '\0')
                    362:                fromaddr = "postmaster";
                    363:        s_append(cc, fromaddr);
                    364:        s_append(cc, " ");
                    365:        s_append(cc, s_to_c(rcvrs));
                    366:        s_append(cc, "\n");
                    367:        s_append(cc, s_to_c(rcvrs));
                    368:        s_append(cc, "\n");
                    369:        if(mkctlfile('X', dataname, s_to_c(cc))<0){
                    370:                unlink(dataname);
                    371:                csend(LOG_ALERT, "451 Transaction failed -- can't make control file\n");
                    372:                death(EX_CANTCREAT);
                    373:        }
                    374:        s_free(cc);
                    375:        csend(LOG_DEBUG, "250 OK\n");
                    376:        Syslog(LOG_INFO, "%s  sent %d bytes to  %s\n",
                    377:                fromaddr ? fromaddr : "postmaster", nbytes,
                    378:                s_to_c(rcvrs));
                    379:        
                    380: 
                    381:        /*
                    382:         *  reinitialize all the data pointers
                    383:         */
                    384:        rcvrs = s_reset(rcvrs);
                    385:        nbytes = 0;
                    386:        *dataname = *rcptto = 0;
                    387:        fromaddr = 0;
                    388: 
                    389: }
                    390: 
                    391: /*
                    392:  * Create the data file for the transfer.  Get unique
                    393:  * names and create the files.
                    394:  */
                    395: init_xfr()
                    396: {
                    397:        int     dfd;                    /* file desc. for data file */
                    398:        char    *cp;
                    399: 
                    400:        strcpy(dataname, "D.xxxxxxxxxxxx");
                    401:        if((dfd = mkdatafile(dataname)) < 0)
                    402:                return -1;
                    403:        datafd = fdopen(dfd, "w");      /* make stdio descriptor */
                    404:        if (datafd == NULL)
                    405:                return -2;
                    406: 
                    407:        /*
                    408:         *  find the sender name if any
                    409:         */
                    410:        if(*mailfrom){
                    411: 
                    412:                /* skip noise */
                    413:                for(cp=mailfrom+sizeof("MAIL FROM:")-1; *cp; cp++)
                    414:                        if(strchr(";<>{}()\n| \t", *cp)==NULL)
                    415:                                break;
                    416:                fromaddr = cp;
                    417: 
                    418:                /* find address */
                    419:                for(; *cp; cp++)
                    420:                        if(strchr(";<>{}()\n| \t", *cp)!=NULL){
                    421:                                *cp = '\0';
                    422:                                break;
                    423:                        }
                    424:        }
                    425:        if(fromaddr)
                    426:                fromaddr = convertaddr(fromaddr);
                    427:        
                    428:        return 1;
                    429: }
                    430: 
                    431: /*
                    432:  * Give up on the transfer.  Unlink the data file (if any),
                    433:  * close the tcp connection, and exit.
                    434:  */
                    435: quit(fi, fo)
                    436: FILE *fi, *fo;
                    437: {
                    438:        int i;
                    439:        char greeting[MAXSTR];
                    440: 
                    441:        (void) sprintf(greeting, "221 %s Terminating\n", helohost);
                    442:        csend(LOG_DEBUG, greeting);
                    443:        (void) fclose(fi);
                    444:        (void) fclose(fo);
                    445:        Syslog(LOG_DEBUG, "finished.\n");
                    446: 
                    447:        /*
                    448:         *  run the queue from this caller
                    449:         */
                    450:        for(i=0; i<NOFILE; i++)
                    451:                close(i);
                    452:        open("/dev/null", 0);
                    453:        open("/dev/null", 1);
                    454:        open("/dev/null", 1);
                    455:        if(!norun)
                    456:                smtpsched("Dsmtpsched", spoolsubdir);
                    457: 
                    458:        exit(0);
                    459: }
                    460: 
                    461: /*
                    462:  * Parse the command part off the specified buffer.  Return the strchr
                    463:  * of the command in the command table(or 0 if the command is not
                    464:  * recognized).
                    465:  * The commands and indices accepted are listed in the include file
                    466:  * "cmds.h".
                    467:  * If the len parameter is -1 (as returned by tgets), issue the QUIT command.
                    468:  * This non-protocol extension was added to cool the jets of sail.stanford.edu.
                    469:  */
                    470: cmdparse(buf, len)
                    471: char *buf;
                    472: int len;
                    473: {
                    474:        register char *cmdp, *bufp;     /* command, buffer ptrs. */
                    475:        register struct cmdtab  *ct;    /* cmd table ptr */
                    476:        register int i;                 /* strchr in cmd table */
                    477:        int     clen;                   /* length of this command */
                    478:        
                    479:        if (len == -1) {                /* EOF */
                    480:                buf = "QUIT";
                    481:                len = strlen(buf);
                    482:        }
                    483:        for (ct = &cmdtab[1], i = 1; ct->c_name != NULL; ct++, i++) {
                    484:                clen = ct->c_len;
                    485:                if (len < clen)         /* buffer shorter than command? */
                    486:                        continue;
                    487:                /* case-insensitive matching of command names */
                    488:                for (cmdp = ct->c_name, bufp = buf;
                    489:                     clen > 0 && *cmdp == (ISLOWER(*bufp) ? TOUPPER(*bufp) : *bufp);
                    490:                     cmdp++, bufp++, clen--)
                    491:                        ;
                    492:                if (clen == 0) {                /* success */
                    493:                        /* sendmail compatibility */
                    494:                        if (i == ONEX || i == VERB)
                    495:                                i = NOOP;
                    496:                        return i;
                    497:                }
                    498:        }
                    499:        return 0;
                    500: }
                    501: 
                    502: /*
                    503:  *  Parse a hello and return a pointer to name of the last two elements
                    504:  *  of the calling machine's domain name (or last 14 chars).
                    505:  */
                    506: char *
                    507: parse_hello(buf, len)
                    508:        char *buf;
                    509:        int len;
                    510: {
                    511:        char *bp = buf;
                    512:        char *lp;
                    513:        int dots;
                    514: 
                    515:        /* skip command */
                    516:        bp[len-1] = 0;
                    517:        for(; *bp && !isspace(*bp); bp++)
                    518:                ;
                    519:        /* skip white */
                    520:        for(; isspace(*bp); bp++)
                    521:                ;
                    522:        /* skip arg */
                    523:        lp = bp;
                    524:        for(; *bp && !isspace(*bp); bp++)
                    525:                ;
                    526:        /* null terminate */
                    527:        *bp = 0;
                    528: 
                    529:        return lp;
                    530: }
                    531: 
                    532: static char    *to;                    /* ptr. into request buffer */
                    533: 
                    534: /*
                    535:  * Parse the recipient spec in the buffer.  Start by stripping the
                    536:  * command off the front of the buffer.  Then call canon() to convert
                    537:  * the recpient name into a format acceptable to the mailer daemon
                    538:  * (ie. !-format).
                    539:  * Returns TRUE if parsed successfully, FALSE otherwise.
                    540:  */
                    541: /* ARGSUSED len */
                    542: parse_rcpt(buf, len)
                    543: char *buf;                             /* command buffer */
                    544: int len;                               /* size of buffer string */
                    545: {
                    546:        register char *from;            /* ptr to recipient name */
                    547:        char *end;
                    548:        char *rv;
                    549:        char *sysname_read();
                    550:        char *thissys;
                    551:        
                    552:        from = &buf[cmdtab[RCPT].c_len];
                    553:        while (*from == ' ' || *from == '\t')
                    554:                from++;
                    555:        if (*from == '<') {
                    556:                end = strchr(from++, '>');
                    557:                if (end == 0) {
                    558:                        return FALSE;
                    559:                }
                    560:                *end = 0;
                    561:        }
                    562: 
                    563:        /*
                    564:         *  convert to lower case (this is wrong but rfc822 is case
                    565:         *  insensitive)
                    566:         */
                    567:        for(rv = from; *rv; rv++)
                    568:                if(isupper(*rv))
                    569:                        *rv = tolower(*rv);
                    570: 
                    571:        /*
                    572:         * convert address to bang format.  Assume the first site
                    573:         * in the list is us and take it out.
                    574:         */
                    575:        rv=convertaddr(from);
                    576:        if(end=strchr(rv, '!')){
                    577:                thissys = sysname_read();
                    578:                *end = '\0';
                    579:                if(strcmp(rv, thissys)==0)
                    580:                        rv = end+1;
                    581:                else
                    582:                        *end = '!';
                    583:        }
                    584: 
                    585:        /*
                    586:         *  check for address syntax
                    587:         */
                    588:        if(shellchars(rv)){
                    589:                Syslog(LOG_ALERT, "shell characters in address: %s", rv);
                    590:                if(virus)
                    591:                        rv = "upas.security";
                    592:                else
                    593:                        return FALSE;
                    594:        }
                    595: 
                    596:        /*
                    597:         *  add to list of recipients
                    598:         */
                    599:        if(*s_to_c(rcvrs))
                    600:                s_append(rcvrs, " ");
                    601:        s_append(rcvrs, rv);
                    602:        return TRUE;
                    603: }
                    604: 
                    605: 
                    606: /* Time to live elapsed or io error. */
                    607: death(weapon)
                    608: {
                    609:        (void) unlink(dataname);
                    610:        exit(1);
                    611: }
                    612: 
                    613: alarmsend()
                    614: {
                    615:        csend(LOG_WARNING, "451 Our mailer appears to be hung.\n");
                    616:        death(EX_TEMPFAIL);
                    617: }
                    618: 
                    619: funnychars(str)
                    620: register char *str;
                    621: {
                    622:        for (;;)
                    623:                switch(*str++) {
                    624:                case '^':
                    625:                case '&':
                    626:                case '>':
                    627:                case '<':
                    628:                case '`':
                    629:                case '|':
                    630:                case ';':
                    631:                case '\'':
                    632:                        return TRUE;
                    633: 
                    634:                case 0:
                    635:                        return FALSE;
                    636:                }
                    637: }
                    638: 
                    639: bitch(buf, fo)
                    640: char *buf;
                    641: FILE *fo;
                    642: {
                    643:        char gripe[BUFSIZ], *nlptr;
                    644: 
                    645:        if ((nlptr = strchr(buf, '\n')) != 0)
                    646:                *nlptr = 0;
                    647:        (void) sprintf(gripe, "502 %s ... Not recognized\n", buf);
                    648:        csend(LOG_DEBUG, gripe);
                    649: }
                    650: 
                    651: bomb(err)
                    652: int err;
                    653: {
                    654:        death(err);
                    655: }
                    656: 
                    657: csend(loglevel, message)
                    658: int loglevel;
                    659: char *message;
                    660: {
                    661:        Syslog(loglevel, "<--- %s", message);
                    662:        (void) tputs(message, fo);
                    663: }
                    664: 
                    665: int
                    666: crecv(buf, len, fd)
                    667: char *buf;
                    668: int len, fd;
                    669: {
                    670:        int n = tgets(buf, len, fi);
                    671:        Syslog(LOG_DEBUG, "-------> %s", buf);
                    672:        return n;
                    673: }

unix.superglobalmegacorp.com

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