|
|
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.