Annotation of 43BSD/contrib/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: 
                     33: #include <stdio.h>
                     34: #include <sys/types.h>
                     35: #include <sys/file.h>
                     36: #include <syslog.h>
                     37: #include <sysexits.h>
                     38: #include "defs.h"
                     39: #include "header.h"
                     40: #include "response_codes.h"
                     41: #include "nntpxmit.h"
                     42: 
                     43: char   *pname;
                     44: char   Debug = FALSE;
                     45: char   Do_Stats = TRUE;
                     46: char   *USAGE = "USAGE: nntpxmit [-s] hostname:file [hostname:file ...]";
                     47: FILE   *getfp();
                     48: 
                     49: struct Stats {
                     50:        u_long  offered;
                     51:        u_long  accepted;
                     52:        u_long  rejected;
                     53:        u_long  failed;
                     54: } Stats = {0L, 0L, 0L, 0L};
                     55: 
                     56: extern int     errno;
                     57: extern char    *rindex();
                     58: extern char    *index();
                     59: extern char    *errmsg();
                     60: 
                     61: main(ac,av)
                     62: int    ac;
                     63: char   *av[];
                     64: {
                     65:        register int    i;
                     66:        char    *host, *file;
                     67: 
                     68:        pname = ((pname = rindex(av[0],'/')) ? pname + 1 : av[0]);
                     69:        
                     70:        if (ac < 2) {
                     71:                fprintf(stderr,"%s: %s\n", pname, USAGE);
                     72:                exit(EX_USAGE);
                     73:        }
                     74: 
                     75:        /* note that 4.2 BSD openlog has only two args */
                     76:        (void) openlog(pname, LOG_PID, LOG_LOCAL7);
                     77: 
                     78:        for(i = 1; i < ac; i++) {
                     79:                if (av[i][0] == '-') {
                     80:                        switch(av[i][1]) {
                     81:                        case 's':
                     82:                                Do_Stats = FALSE;
                     83:                                break;
                     84:                        case 'd':
                     85:                                Debug++;
                     86:                                break;
                     87:                        default:
                     88:                                fprintf(stderr,"%s: no such option: -%c\n",
                     89:                                        pname, av[i][1]);
                     90:                                fprintf(stderr,"%s: %s\n", pname, USAGE);
                     91:                                exit(EX_USAGE);
                     92:                        }
                     93:                        continue;
                     94:                }
                     95: 
                     96:                /*
                     97:                ** OK, it wasn't an option, therefore it must be a
                     98:                ** hostname, filename pair.
                     99:                */
                    100:                host = av[i];
                    101:                if ((file = index(host, ':')) != (char *)NULL) {
                    102:                        *file++ = '\0';
                    103:                } else {
                    104:                        fprintf(stderr,"%s: illegal hostname:file pair: <%s>\n",
                    105:                                pname, host);
                    106:                        continue;
                    107:                }
                    108: 
                    109:                bzero(&Stats, sizeof(Stats));
                    110:                if (sendnews(host, file) && Do_Stats) {
                    111:                        syslog(LOG_INFO,
                    112:                                "%s stats %d offered %d accepted %d rejected %d failed\n",
                    113:                                host, Stats.offered, Stats.accepted, Stats.rejected, Stats.failed);
                    114:                }
                    115:        }
                    116:        exit(EX_OK);
                    117: }
                    118: 
                    119: /*
                    120: ** Given a hostname to connect to, and a file of filenames (which contain
                    121: ** netnews articles), send those articles to the named host using NNTP.
                    122: */
                    123: sendnews(host, file)
                    124: char   *host, *file;
                    125: {
                    126:        register int    code;
                    127:        register FILE   *filefile = fopen(file, "r");
                    128:        register FILE   *fp;
                    129:        char    buf[BUFSIZ];
                    130: 
                    131:        /*
                    132:        ** if no news to send, return
                    133:        */
                    134:        if (filefile == (FILE *)NULL) {
                    135:                dprintf(stderr, "%s: %s: %s\n", pname, file, errmsg(errno));
                    136:                return(FALSE);
                    137:        }
                    138: 
                    139:        if (hello(host) == FAIL) {
                    140:                fclose(filefile);
                    141:                return(FALSE);
                    142:        }
                    143: 
                    144:        while((fp = getfp(filefile)) != (FILE *)NULL) {
                    145:                switch(code = ihave(fp)) {
                    146:                case CONT_XFER:
                    147:                        if (!sendfile(fp)) {
                    148:                                fprintf(stderr, "%s: %s: article transmission failed.\n", pname, host);
                    149:                                if (Do_Stats) Stats.failed++;
                    150:                                fclose(filefile);
                    151:                                fclose(fp);
                    152:                                goodbye(DONT_WAIT);
                    153:                                return(TRUE);
                    154:                        }
                    155:                        fclose(fp);
                    156:                        /*
                    157:                        ** Here I read the reply from the remote about the
                    158:                        ** transferred article, and I throw it away. I
                    159:                        ** should probably try and record the article
                    160:                        ** filename and append it back to the batchfile
                    161:                        ** again in the name of reliability, but that's
                    162:                        ** messy, and it's easier to assume that the guy
                    163:                        ** will have redundant feeds.
                    164:                        */
                    165:                        code = readreply(buf, sizeof(buf));
                    166:                        if (Do_Stats && code != OK_XFERED) Stats.failed++;
                    167:                        break;
                    168:                case ERR_GOTIT:
                    169:                        fclose(fp);
                    170:                        break;
                    171:                default:
                    172:                        fprintf(stderr,"%s: %s gave an improper response to IHAVE: %d\n", pname, host, code);
                    173:                        fclose(filefile);
                    174:                        fclose(fp);
                    175:                        goodbye(DONT_WAIT);
                    176:                        return(TRUE);
                    177:                }
                    178:        }
                    179:        fclose(filefile);
                    180:        if (unlink(file) < 0) {
                    181:                fprintf(stderr,"%s: unable to unlink(%s): %s\n", pname, file, errmsg(errno));
                    182:        }
                    183:        goodbye(WAIT);
                    184:        return(TRUE);
                    185: }
                    186: 
                    187: /*
                    188: ** Read the header of a netnews article, snatch the message-id therefrom,
                    189: ** and ask the remote if they have that one already.
                    190: */
                    191: ihave(fp)
                    192: FILE   *fp;
                    193: {
                    194:        struct hbuf     header;
                    195:        char    scr[LBUFLEN];
                    196: 
                    197:        bzero(&header, sizeof(header));
                    198:        if (rfc822read(&header, fp, scr)) {
                    199:                register int    code;
                    200:                char    buf[BUFSIZ];
                    201: 
                    202:                /*
                    203:                ** If an article shows up without a message-id,
                    204:                ** we scream bloody murder. That's one in
                    205:                ** the `can't ever happen' category.
                    206:                */
                    207:                if (header.ident[0] == '\0') {
                    208:                        fprintf(stderr, "%s: article w/o message-id!\n", pname);
                    209:                        return(ERR_GOTIT);
                    210:                }
                    211:                sprintf(buf, "IHAVE %s", header.ident);
                    212:                if (Do_Stats) Stats.offered++;
                    213: 
                    214:                switch(code = converse(buf, sizeof(buf))) {
                    215:                case CONT_XFER:
                    216:                        if (Do_Stats) Stats.accepted++;
                    217:                        rewind(fp);
                    218:                        return(code);
                    219:                default:
                    220:                        if (Do_Stats) Stats.rejected++;
                    221:                        return(code);
                    222:                }
                    223:        }
                    224:        /*
                    225:        ** something botched locally with the article
                    226:        ** so we don't send it, but we don't break off
                    227:        ** communications with the remote either.
                    228:        */
                    229:        return(ERR_GOTIT);
                    230: }
                    231: 
                    232: /*
                    233: ** Given that fp points to an open file containing filenames,
                    234: ** open and return a file pointer to the next filename in the file.
                    235: ** Don't you love indirection?
                    236: */
                    237: FILE *
                    238: getfp(fp)
                    239: FILE   *fp;
                    240: {
                    241:        register FILE   *newfp = NULL;
                    242:        register char   *cp;
                    243:        char    filename[BUFSIZ];
                    244: 
                    245:        while(newfp == NULL) {
                    246:                if (fgets(filename, sizeof(filename), fp) == NULL)
                    247:                        return(NULL);           /* EOF, tell caller */
                    248:                
                    249:                /* zap \n char */
                    250:                if (*(cp = &filename[strlen(filename) - 1]) == '\n')
                    251:                        *cp = '\0';
                    252: 
                    253:                if ((newfp = fopen(filename, "r")) == NULL)
                    254:                        perror(filename);       /* tell 'em why it failed */
                    255:        }
                    256:        dprintf(stderr, "FILE: %s\n", filename);        /* DEBUG */
                    257:        return(newfp);
                    258: }

unix.superglobalmegacorp.com

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