|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.