Annotation of 43BSDTahoe/new/nntp/xmit/nntpxmit.c, revision 1.1.1.1

1.1       root        1: /*
                      2: ** nntpxmit - transmit netnews articles across the internet with nntp
                      3: **
                      4: ** This program is for transmitting netnews between sites that offer the
                      5: ** NNTP service, internet style.  Ideally, there are two forms of
                      6: ** transmission that can be used in this environment, since the
                      7: ** communication is interactive (and relatively immediate, when compared
                      8: ** with UUCP).  They are:  passive poll (what have you gotten lately?) and
                      9: ** active send (I have `x', do you want it?).  The USENET as a whole
                     10: ** uniformly uses active send, and where the communication is batched
                     11: ** (e.g. UUCP, or electronic mail) the software sends without even asking,
                     12: ** unless it can determine that the article has already been to some site.
                     13: **
                     14: ** It turns out that when you implement passive poll, you have to be
                     15: ** *very* careful about what you (the server) tell the client, because
                     16: ** something that you might wish to restrict distribution of (either
                     17: ** internal newsgroups, or material posted in the international groups in
                     18: ** local distributions) will otherwise leak out.  It is the case that if
                     19: ** the server doesn't tell the client that article `x' is there, the
                     20: ** client won't ask for it.  If the server tells about an article which
                     21: ** would otherwise stay within some restricted distribution, the onus is
                     22: ** then on the client to figure out that the article is not appropriate to
                     23: ** post on its local system.  Of course, at that point, we have already
                     24: ** wasted the network bandwidth in transferring the article...
                     25: **
                     26: ** This is a roundabout way of saying that this program only implements
                     27: ** active send.  There will have to be once-over done on the NNTP spec
                     28: ** before passive poll goes in, because of the problems that I have cited.
                     29: **
                     30: ** Erik E. Fair        <ucbvax!fair>, Oct 14, 1985
                     31: **
                     32: ** Changed to exit on unusual errors in opening articles, and now produces
                     33: ** CPU usage statistics to syslog.
                     34: **
                     35: ** Erik E. Fair <ucbvax!fair>, April 26, 1986
                     36: */
                     37: 
                     38: #include <stdio.h>
                     39: #include <errno.h>
                     40: #include <sys/types.h>
                     41: #include <sys/times.h>
                     42: #include <sys/file.h>
                     43: #include <syslog.h>
                     44: #include <sysexits.h>
                     45: #include "defs.h"
                     46: #include "header.h"
                     47: #include "response_codes.h"
                     48: #include "nntpxmit.h"
                     49: 
                     50: char   *Pname;
                     51: char   Debug = FALSE;
                     52: char   Do_Stats = TRUE;
                     53: char   *USAGE = "USAGE: nntpxmit [-s] hostname:file [hostname:file ...]";
                     54: FILE   *getfp();
                     55: 
                     56: struct Stats {
                     57:        u_long  offered;
                     58:        u_long  accepted;
                     59:        u_long  rejected;
                     60:        u_long  failed;
                     61: } Stats = {0L, 0L, 0L, 0L};
                     62: 
                     63: struct tms     Prev_times, Cur_times;
                     64: time_t         Tbegin, Tend;
                     65: 
                     66: extern int     errno;
                     67: extern char    *rindex();
                     68: extern char    *index();
                     69: extern char    *errmsg();
                     70: extern char    *sp_strip();
                     71: extern int     msgid_ok();
                     72: 
                     73: main(ac,av)
                     74: int    ac;
                     75: char   *av[];
                     76: {
                     77:        register int    i;
                     78:        char    *host, *file;
                     79: 
                     80:        (void) time(&Tbegin);
                     81: 
                     82:        Pname = ((Pname = rindex(av[0],'/')) ? Pname + 1 : av[0]);
                     83:        
                     84:        if (ac < 2) {
                     85:                fprintf(stderr,"%s: %s\n", Pname, USAGE);
                     86:                exit(EX_USAGE);
                     87:        }
                     88: 
                     89:        /* note that 4.2 BSD openlog has only two args */
                     90: #ifdef LOG_LOCAL7
                     91:        (void) openlog(Pname, LOG_PID, LOG_LOCAL7);
                     92: #else
                     93:        (void) openlog(Pname, LOG_PID);
                     94: #endif
                     95: 
                     96:        for(i = 1; i < ac; i++) {
                     97:                if (av[i][0] == '-') {
                     98:                        switch(av[i][1]) {
                     99:                        case 's':
                    100:                                Do_Stats = FALSE;
                    101:                                break;
                    102:                        case 'd':
                    103:                                Debug++;
                    104:                                break;
                    105:                        default:
                    106:                                fprintf(stderr,"%s: no such option: -%c\n",
                    107:                                        Pname, av[i][1]);
                    108:                                fprintf(stderr,"%s: %s\n", Pname, USAGE);
                    109:                                exit(EX_USAGE);
                    110:                        }
                    111:                        continue;
                    112:                }
                    113: 
                    114:                /*
                    115:                ** OK, it wasn't an option, therefore it must be a
                    116:                ** hostname, filename pair.
                    117:                */
                    118:                host = av[i];
                    119:                if ((file = index(host, ':')) != (char *)NULL) {
                    120:                        *file++ = '\0';
                    121:                } else {
                    122:                        fprintf(stderr,"%s: illegal hostname:file pair: <%s>\n",
                    123:                                Pname, host);
                    124:                        continue;
                    125:                }
                    126: 
                    127:                bzero(&Stats, sizeof(Stats));
                    128:                if (sendnews(host, file) && Do_Stats) {
                    129:                        struct tms      delta;
                    130:                        time_t          elapsed;
                    131:                        syslog(LOG_INFO,
                    132:                                "%s stats %lu offered %lu accepted %lu rejected %lu failed\n",
                    133:                                host, Stats.offered, Stats.accepted, Stats.rejected, Stats.failed);
                    134: 
                    135:                        click(&delta, &elapsed);
                    136: 
                    137:                        syslog(LOG_INFO, "%s xmit user %lu system %lu elapsed %lu\n",
                    138:                                host, delta.tms_utime, delta.tms_stime, elapsed);
                    139:                }
                    140:        }
                    141:        exit(EX_OK);
                    142: }
                    143: 
                    144: /*
                    145: ** Calculate how much time we've used.
                    146: **
                    147: ** The HZ constant is from times(3C) man page, and is probably wrong
                    148: ** for anything other than a VAX.
                    149: **
                    150: ** Why `click'? Well, imagine that I've got a stopwatch in my hand...
                    151: */
                    152: #define        HZ      60L
                    153: 
                    154: click(cpu, elapsed)
                    155: register struct tms    *cpu;
                    156: time_t *elapsed;
                    157: {
                    158:        (void) times(&Cur_times);
                    159:        (void) time(&Tend);
                    160: 
                    161:        /* delta T */
                    162:        *elapsed = Tend - Tbegin;
                    163:        cpu->tms_utime = Cur_times.tms_utime - Prev_times.tms_utime;
                    164:        cpu->tms_stime = Cur_times.tms_stime - Prev_times.tms_stime;
                    165:        cpu->tms_cutime = Cur_times.tms_cutime - Prev_times.tms_cutime;
                    166:        cpu->tms_cstime = Cur_times.tms_cstime - Prev_times.tms_cstime;
                    167: 
                    168:        /* reset reference point */
                    169:        Tbegin = Tend;  
                    170:        Prev_times = Cur_times;
                    171: 
                    172:        /* aggregate the children with the parent */
                    173:        cpu->tms_utime += cpu->tms_cutime;
                    174:        cpu->tms_stime += cpu->tms_cstime;
                    175: 
                    176:        /* adjust these to seconds */
                    177:        cpu->tms_utime /= HZ;
                    178:        cpu->tms_stime /= HZ;
                    179: }
                    180: 
                    181: /*
                    182: ** Given a hostname to connect to, and a file of filenames (which contain
                    183: ** netnews articles), send those articles to the named host using NNTP.
                    184: */
                    185: sendnews(host, file)
                    186: char   *host, *file;
                    187: {
                    188:        register int    code;
                    189:        register FILE   *filefile = fopen(file, "r");
                    190:        register FILE   *fp;
                    191:        char    buf[BUFSIZ];
                    192:        char    article[BUFSIZ];
                    193: 
                    194:        /*
                    195:        ** if no news to send, return
                    196:        */
                    197:        if (filefile == (FILE *)NULL) {
                    198:                dprintf(stderr, "%s: %s: %s\n", Pname, file, errmsg(errno));
                    199:                return(FALSE);
                    200:        }
                    201: 
                    202:        if (hello(host) == FAIL) {
                    203:                fclose(filefile);
                    204:                return(FALSE);
                    205:        }
                    206: 
                    207:        while((fp = getfp(filefile, article, sizeof(article))) != (FILE *)NULL) {
                    208:                switch(code = ihave(fp, article)) {
                    209:                case CONT_XFER:
                    210:                        if (!sendfile(fp)) {
                    211:                                fprintf(stderr, "%s: %s: article transmission failed while sending %s\n", Pname, host, article);
                    212:                                Stats.failed++;
                    213:                                fclose(filefile);
                    214:                                fclose(fp);
                    215:                                goodbye(DONT_WAIT);
                    216:                                return(TRUE);
                    217:                        }
                    218:                        fclose(fp);
                    219:                        /*
                    220:                        ** Here I read the reply from the remote about the
                    221:                        ** transferred article, and I throw it away. I
                    222:                        ** should probably try and record the article
                    223:                        ** filename and append it back to the batchfile
                    224:                        ** again in the name of reliability, but that's
                    225:                        ** messy, and it's easier to assume that the guy
                    226:                        ** will have redundant feeds.
                    227:                        */
                    228:                        code = readreply(buf, sizeof(buf));
                    229:                        if (code != OK_XFERED) Stats.failed++;
                    230:                        break;
                    231:                case ERR_GOTIT:
                    232:                        fclose(fp);
                    233:                        break;
                    234:                default:
                    235:                        fprintf(stderr,"%s: %s gave an improper response to IHAVE: %d\n", Pname, host, code);
                    236:                        fprintf(stderr,"%s: while sending article %s\n", Pname, article);
                    237:                        fclose(filefile);
                    238:                        fclose(fp);
                    239:                        goodbye(DONT_WAIT);
                    240:                        return(TRUE);
                    241:                }
                    242:        }
                    243:        fclose(filefile);
                    244:        if (unlink(file) < 0) {
                    245:                fprintf(stderr,"%s: unlink(%s): %s\n", Pname, file, errmsg(errno));
                    246:        }
                    247:        goodbye(WAIT);
                    248:        return(TRUE);
                    249: }
                    250: 
                    251: /*
                    252: ** Read the header of a netnews article, snatch the message-id therefrom,
                    253: ** and ask the remote if they have that one already.
                    254: */
                    255: ihave(fp, article)
                    256: FILE   *fp;
                    257: char   *article;
                    258: {
                    259:        register int    code;
                    260:        struct hbuf     header;
                    261:        char    scr[LBUFLEN];
                    262:        char    buf[BUFSIZ];
                    263: 
                    264:        bzero(&header, sizeof(header));
                    265:        if (!rfc822read(&header, fp, scr)) {
                    266:                /*
                    267:                ** something botched locally with the article
                    268:                ** so we don't send it, but we don't break off
                    269:                ** communications with the remote either.
                    270:                */
                    271:                return(ERR_GOTIT);
                    272:        }
                    273: 
                    274:        /*
                    275:        ** If an article shows up without a message-id,
                    276:        ** or with a bogus message-id,
                    277:        ** we scream bloody murder. That's one in
                    278:        ** the `can't ever happen' category.
                    279:        */
                    280:        if (header.ident[0] == '\0') {
                    281:                fprintf(stderr, "%s: %s missing message-id!\n", Pname, article);
                    282:                return(ERR_GOTIT);
                    283:        } else {
                    284:                (void) strcpy(scr, sp_strip(header.ident));
                    285:        }
                    286: 
                    287:        if (!msgid_ok(scr)) {
                    288:                fprintf(stderr, "%s: %s message-id syntax error!\n", Pname, article);
                    289:                return(ERR_GOTIT);
                    290:        }
                    291: 
                    292:        sprintf(buf, "IHAVE %s", scr);
                    293:        Stats.offered++;
                    294: 
                    295:        switch(code = converse(buf, sizeof(buf))) {
                    296:        case CONT_XFER:
                    297:                Stats.accepted++;
                    298:                rewind(fp);
                    299:                return(code);
                    300:        default:
                    301:                Stats.rejected++;
                    302:                return(code);
                    303:        }
                    304: }
                    305: 
                    306: /*
                    307: ** Given that fp points to an open file containing filenames,
                    308: ** open and return a file pointer to the next filename in the file.
                    309: ** Don't you love indirection?
                    310: **
                    311: ** Returns a valid FILE pointer or NULL if end of file.
                    312: */
                    313: 
                    314: FILE *
                    315: getfp(fp, filename, fnlen)
                    316: register FILE  *fp;
                    317: char   *filename;
                    318: register unsigned      fnlen;
                    319: {
                    320:        register FILE   *newfp = (FILE *)NULL;
                    321:        register char   *cp;
                    322: 
                    323:        while(newfp == (FILE *)NULL) {
                    324:                if (fgets(filename, fnlen, fp) == (char *)NULL)
                    325:                        return((FILE *)NULL);           /* EOF, tell caller */
                    326: 
                    327:                filename[fnlen - 1] = '\0';     /* make sure */
                    328: 
                    329:                if (*(cp = &filename[strlen(filename) - 1]) == '\n')
                    330:                        *cp = '\0';
                    331: 
                    332:                if ((newfp = fopen(filename, "r")) == (FILE *)NULL) {
                    333:                        register int    save = errno;
                    334: 
                    335:                        fprintf(stderr, "%s: fopen(%s, \"r\"): %s\n", Pname, filename, errmsg(errno));
                    336:                        /*
                    337:                        ** The only permissible error is `file non-existant'
                    338:                        ** anything else indicates something is seriously
                    339:                        ** wrong, and we should go away to let the shell
                    340:                        ** script clean up.
                    341:                        */
                    342:                        if (save != ENOENT)
                    343:                                exit(EX_OSERR);
                    344:                }
                    345:        }
                    346:        return(newfp);
                    347: }

unix.superglobalmegacorp.com

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