|
|
1.1 root 1: /*
2: * nntpxfer
3: *
4: * Connects to the specified nntp server, and transfers all new news
5: * since the last successful invocation.
6: *
7: * last successful invocation date and time are stored in a file at
8: * /usr/spool/news/nntp.<hostname> as
9: * groups YYMMDD HHMMSS distributions\n
10: * in case you need to edit it. You can also override this on
11: * the command line in the same format, in which case the file won't
12: * be updated.
13: *
14: * Brian Kantor, UCSD 1986
15: * (some bug fixes by [email protected])
16: */
17:
18: #define DEBUG
19:
20: /* you'd think that 4096 articles at one go is enough.... */
21: #define MAXARTS 4096
22:
23: #include <sys/types.h>
24: #include <sys/dir.h>
25: #include <sys/socket.h>
26: #include <sys/stat.h>
27: #include <sys/ioctl.h>
28: #include <sys/file.h>
29: #include <sys/time.h>
30: #include <sys/wait.h>
31: #include <sys/resource.h>
32:
33: #include <net/if.h>
34: #include <netinet/in.h>
35:
36: #include <stdio.h>
37: #include <errno.h>
38: #include <ctype.h>
39: #include <netdb.h>
40: #include <signal.h>
41: #include <dbm.h>
42:
43: #define INEWS "/usr/lib/news/inews -p"
44: #define HIST "/usr/lib/news/history"
45:
46: char *malloc();
47: char *strcpy();
48: char *strcat();
49: long time();
50: u_long inet_addr();
51:
52: extern int errno;
53: char *artlist[MAXARTS];
54: int server; /* stream socket to the nntp server */
55: int newart, dupart, misart;
56:
57: main(argc, argv)
58: int argc;
59: char *argv[];
60: {
61: FILE *dtfile; /* where last xfer date/time stored */
62: char buf[BUFSIZ];
63: char lastdate[16];
64: char distributions[BUFSIZ];
65: char dtname[128];
66: char newsgroups[BUFSIZ];
67: char lasttime[16];
68: int connected = 0; /* 1 = connected */
69: int i;
70: int omitupdate = 0; /* 1 = don't update datetime */
71: long clock;
72: long newdate, newtime;
73: struct hostent *hp;
74: struct servent *sp;
75: struct sockaddr_in sin;
76: struct tm *now;
77:
78: /* OPTIONS
79: argv[1] MUST be the host name
80: argv[2-4] MAY be "newsgroups YYMMDD HHMMSS"
81: argv[5] MAY be distributions
82: (otherwise use 2-4/5 from the file
83: "/usr/spool/news/nntp.hostname")
84: */
85:
86: if (argc != 2 && argc != 5 && argc != 6)
87: {
88: (void) printf("Usage: %s host [groups YYMMDD HHMMSS [<dist>]]\n",
89: argv[0]);
90: exit(1);
91: }
92:
93: if (argc > 2)
94: {
95: omitupdate++;
96: (void) strcpy(newsgroups, argv[2]);
97: (void) strcpy(lastdate, argv[3]);
98: (void) strcpy(lasttime, argv[4]);
99: (void) strcpy(distributions, "");
100: if (argc > 5)
101: (void) strcpy(distributions, argv[5]);
102: }
103: else
104: {
105: (void) strcpy(dtname, "/usr/spool/news/nntp.");
106: (void) strcat(dtname, argv[1]);
107: dtfile = fopen(dtname, "r");
108: if (dtfile == NULL)
109: {
110: (void) printf("%s not found; using * 860101 000000 \n",
111: dtname);
112: (void) strcpy(newsgroups, "*");
113: (void) strcpy(lastdate, "860101");
114: (void) strcpy(lasttime, "000000");
115: (void) strcpy(distributions, "");
116: }
117: else
118: {
119: if (fscanf(dtfile, "%s %s %s %s",
120: newsgroups, lastdate, lasttime, distributions) < 3)
121: {
122: (void) printf("%s invalid; using * 860101 000000\n",
123: dtname);
124: (void) strcpy(newsgroups, "*");
125: (void) strcpy(lastdate, "860101");
126: (void) strcpy(lasttime, "000000");
127: (void) strcpy(distributions, "");
128: }
129: (void) fclose(dtfile);
130: }
131: clock = time((long *)0);
132: now = gmtime(&clock);
133: newdate = (now->tm_year * 10000) +
134: ((now->tm_mon + 1) * 100) + now->tm_mday;
135: newtime = (now->tm_hour * 10000) +
136: (now->tm_min * 100) + now->tm_sec;
137: }
138:
139: #ifdef DEBUG
140: (void) printf("newsgroups = '%s'\n", newsgroups);
141: (void) printf("date = '%s'\n", lastdate);
142: (void) printf("time = '%s'\n", lasttime);
143: (void) printf("distributions = '%s'\n", distributions);
144: (void) printf("now is = %06d %06d\n", newdate, newtime);
145: #endif
146:
147: if (dbminit(HIST) < 0)
148: {
149: perror("couldn't open history file");
150: exit(1);
151: }
152:
153: sin.sin_addr.s_addr = inet_addr(argv[1]);
154: if (sin.sin_addr.s_addr != -1)
155: {
156: sin.sin_family = AF_INET;
157: }
158: else
159: {
160: hp = gethostbyname(argv[1]);
161: if (hp == NULL)
162: {
163: (void) printf("%s: unknown host\n", argv[1]);
164: exit(1);
165: }
166:
167: sin.sin_family = hp->h_addrtype;
168: #ifdef BSD43
169: bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
170: hp->h_length);
171: #else BSD43
172: bcopy(hp->h_addr, (caddr_t)&sin.sin_addr,
173: hp->h_length);
174: #endif BSD43
175: }
176:
177: sp = getservbyname("nntp", "tcp");
178: if (sp == NULL)
179: {
180: perror("nntp/tcp");
181: exit(1);
182: }
183:
184: sin.sin_port = sp->s_port;
185:
186: do {
187: server = socket(AF_INET, SOCK_STREAM, 0);
188: if (server < 0)
189: {
190: perror("nntpxfer: socket");
191: exit(1);
192: }
193:
194: if (connect(server, (struct sockaddr *)&sin, sizeof (sin)) < 0)
195: {
196: #ifdef BSD43
197: if (hp && hp->h_addr_list[1])
198: {
199: hp->h_addr_list++;
200: bcopy(hp->h_addr_list[0],
201: (caddr_t)&sin.sin_addr, hp->h_length);
202: (void) close(server);
203: continue;
204: }
205: #endif BSD43
206: perror("nntpxfer: connect");
207: exit(1);
208: }
209: connected++;
210: }
211: while (connected == 0);
212:
213: #ifdef DEBUG
214: (void) printf("connected to nntp server at %s\n", argv[1]);
215: #endif
216: /*
217: * ok, at this point we're connected to the nntp daemon
218: * at the distant host.
219: */
220:
221: /* get the greeting herald */
222: (void) sockread(buf);
223: #ifdef DEBUG
224: (void) printf("%s\n", buf);
225: #endif
226: if (buf[0] != '2') /* uh-oh, something's wrong! */
227: {
228: (void) printf("protocol error: got '%s'\n", buf);
229: (void) close(server);
230: exit(1);
231: }
232:
233:
234: /* first, tell them we're a slave process to get priority */
235: sockwrite("SLAVE");
236: (void) sockread(buf);
237: #ifdef DEBUG
238: (void) printf("%s\n", buf);
239: #endif
240: if (buf[0] != '2') /* uh-oh, something's wrong! */
241: {
242: (void) printf("protocol error: got '%s'\n", buf);
243: (void) close(server);
244: exit(1);
245: }
246:
247: /* now, ask for a list of new articles */
248: if (strlen(distributions))
249: (void) sprintf(buf,"NEWNEWS %s %s %s GMT <%s>",
250: newsgroups, lastdate, lasttime, distributions);
251: else
252: (void) sprintf(buf,"NEWNEWS %s %s %s GMT",
253: newsgroups, lastdate, lasttime);
254: sockwrite(buf);
255: (void) sockread(buf);
256: #ifdef DEBUG
257: (void) printf("%s\n", buf);
258: #endif
259: if (buf[0] != '2') /* uh-oh, something's wrong! */
260: {
261: (void) printf("protocol error: got '%s'\n", buf);
262: (void) close(server);
263: exit(1);
264: }
265: /* and here comes the list, terminated with a "." */
266: #ifdef DEBUG
267: (void) printf("data\n");
268: #endif
269: while (1)
270: {
271: (void) sockread(buf);
272: if (!strcmp(buf,"."))
273: break;
274: if (wewant(buf))
275: {
276: if (newart > MAXARTS)
277: {
278: omitupdate++;
279: continue;
280: }
281: artlist[newart] = malloc((unsigned)(strlen(buf)+1));
282: (void) strcpy(artlist[newart], buf);
283: newart++;
284: }
285: else
286: dupart++;
287: }
288: #ifdef DEBUG
289: (void) printf(".\n%d new, %d dup articles\n", newart, dupart);
290: #endif
291:
292: /* now that we know which articles we want, retrieve them */
293: for (i=1; i < newart; i++)
294: (void) artfetch(artlist[i]);
295:
296: #ifdef DEBUG
297: (void) printf("%d missing articles\n", misart);
298: #endif
299: /* we're all done, so tell them goodbye */
300: sockwrite("QUIT");
301: (void) sockread(buf);
302: #ifdef DEBUG
303: (void) printf("%s\n", buf);
304: #endif
305: if (buf[0] != '2') /* uh-oh, something's wrong! */
306: {
307: (void) printf("error: got '%s'\n", buf);
308: (void) close(server);
309: exit(1);
310: }
311: (void) close(server);
312:
313: /* do we want to update the timestamp file? */
314: if (!omitupdate)
315: {
316: (void) sprintf(buf, "%s %06d %06d %s\n",
317: newsgroups, newdate, newtime, distributions);
318: #ifdef DEBUG
319: (void) printf("updating %s:\n\t%s\n", dtname, buf);
320: #endif
321: dtfile = fopen(dtname, "w");
322: if (dtfile == NULL)
323: {
324: perror(dtname);
325: exit(1);
326: }
327: (void) fputs(buf,dtfile);
328: (void) fclose(dtfile);
329: }
330: exit(0);
331: }
332:
333: artfetch(articleid)
334: char *articleid;
335: {
336: int lines = 0;
337: char buf[BUFSIZ];
338: FILE *inews;
339:
340: /* now, ask for the article */
341: (void) sprintf(buf,"ARTICLE %s", articleid);
342: sockwrite(buf);
343: (void) sockread(buf);
344: #ifdef DEBUG
345: (void) printf("%s\n", buf);
346: #endif
347: if (buf[0] == '4') /* missing article, just skipit */
348: {
349: misart++;
350: return(0);
351: }
352:
353: if (buf[0] != '2') /* uh-oh, something's wrong! */
354: {
355: (void) printf("protocol error: got '%s'\n", buf);
356: (void) close(server);
357: exit(1);
358: }
359: #ifdef DEBUG
360: (void) printf("command: %s\n", INEWS);
361: #endif
362: if ( (inews = popen(INEWS, "w")) == NULL)
363: {
364: perror(INEWS);
365: exit(1);
366: }
367:
368: /* and here comes the article, terminated with a "." */
369: #ifdef DEBUG
370: (void) printf("data\n");
371: #endif
372: while (1)
373: {
374: (void) sockread(buf);
375: if (buf[0] == '.' && buf[1] == '\0')
376: break;
377: lines++;
378: (void) strcat(buf,"\n");
379: (void) fputs(((buf[0] == '.') ? buf + 1 : buf),
380: inews);
381: }
382: #ifdef DEBUG
383: (void) printf(".\n%d lines\n", lines);
384: #endif
385: (void) fflush(inews);
386: (void) pclose(inews);
387: return(0);
388: }
389:
390: int
391: sockread(buf)
392: char *buf;
393: {
394: char c;
395: int j = 0;
396: #ifdef BSD43
397: fd_set rf;
398: #else BSD43
399: int rf;
400: #endif BSD43
401: struct timeval tv;
402: int r;
403: char *p = buf;
404:
405: while ( 1 )
406: {
407: tv.tv_sec = 1800; /* 15 minutes */
408: tv.tv_usec = 0L;
409: #ifdef BSD43
410: FD_ZERO(&rf);
411: FD_SET(server, &rf);
412: #else BSD43
413: rf = 1 << server;
414: #endif BSD43
415: r = select(20, (fd_set *)&rf, (fd_set *)0, (fd_set *)&rf, &tv);
416:
417: if (r < 0)
418: {
419: if (errno == EINTR)
420: continue;
421: perror("getsock select");
422: exit(1);
423: }
424: if (r == 0)
425: {
426: printf("read timed out.\n");
427: exit(1);
428: }
429:
430: if (read(server, &c, 1) <= 0)
431: break;
432:
433: /* mask off any chance parity bits */
434: *p = c & 0x7f;
435:
436: /* look for end of line (== LF) */
437: if (c == 0x0a)
438: {
439: if (j > 0 && *(p-1) == 0x0d)
440: *(p-1) = '\0';
441: else
442: *p = '\0';
443: return(strlen(buf));
444: }
445: j++; p++;
446: }
447: perror("sockread");
448: (void) close(server);
449: exit(1);
450: /* NOTREACHED */
451: }
452:
453: sockwrite(buf)
454: char *buf;
455: {
456: register int sz;
457: char buf2[BUFSIZ];
458: #ifdef DEBUG
459: (void) printf(">>> %s\n", buf);
460: #endif
461: (void) strcpy(buf2,buf);
462: (void) strcat(buf2,"\r\n");
463: sz = strlen(buf2);
464: if (write(server,buf2,sz) != sz)
465: {
466: (void) printf("write error on server socket\n");
467: (void) close(server);
468: exit(1);
469: }
470: }
471:
472: int
473: wewant(articleid)
474: char *articleid;
475: {
476: datum k, d;
477: char id[BUFSIZ];
478: char *p;
479:
480: /* remove any case sensitivity */
481: (void) strcpy(id, articleid);
482: p = id;
483: while (*p)
484: {
485: if (isupper(*p))
486: *p = tolower(*p);
487: p++;
488: }
489:
490: k.dptr = id;
491: k.dsize = strlen(articleid) + 1;
492:
493: d = fetch(k);
494:
495: if (d.dptr)
496: {
497: #ifdef DEBUG
498: (void) printf("dup: '%s'\n", articleid);
499: #endif
500: return(0);
501: }
502:
503: #ifdef DEBUG
504: (void) printf("new: '%s'\n", articleid);
505: #endif
506: return(1);
507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.