Annotation of 43BSDTahoe/new/nntp/xmit/nntpxmit.c, revision 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.