|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)newnews.c 1.16 (Berkeley) 7/17/87";
3: #endif
4:
5: #include "common.h"
6: #include "time.h"
7:
8: #ifdef LOG
9: int nn_told = 0;
10: int nn_took = 0;
11: #endif
12:
13:
14: /*
15: * NEWNEWS newsgroups date time ["GMT"] [<distributions>]
16: *
17: * Return the message-id's of any news articles past
18: * a certain date and time, within the specified distributions.
19: *
20: */
21:
22: newnews(argc, argv)
23: register int argc;
24: char *argv[];
25: {
26: register char *cp, *ngp;
27: char *key;
28: char datebuf[32];
29: char line[MAX_STRLEN];
30: char **distlist, **histlist;
31: static char **nglist;
32: int distcount, ngcount, histcount;
33: int all;
34: FILE *fp;
35: long date;
36: long dtol();
37: char *ltod();
38:
39: if (argc < 4) {
40: printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>].\r\n",
41: ERR_CMDSYN);
42: (void) fflush(stdout);
43: return;
44: }
45:
46: #ifdef LOG
47: sprintf(line, "%s newnews %s %s %s %s %s",
48: hostname,
49: argv[1],
50: argv[2],
51: argv[3],
52: (argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
53: (argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
54: syslog(LOG_INFO, line);
55: #endif
56:
57: all = streql(argv[1], "*");
58: if (!all) {
59: ngcount = get_nglist(&nglist, argv[1]);
60: if (ngcount == 0) {
61: printf("%d Bogus newsgroup specifier: %s\r\n",
62: ERR_CMDSYN, argv[1]);
63: (void) fflush(stdout);
64: return;
65: }
66: }
67:
68: /* YYMMDD HHMMSS */
69: if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
70: printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
71: ERR_CMDSYN);
72: (void) fflush(stdout);
73: return;
74: }
75:
76: (void) strcpy(datebuf, argv[2]);
77: (void) strcat(datebuf, argv[3]);
78:
79: argc -= 4;
80: argv += 4;
81:
82: /*
83: * Flame on. The history file is not stored in GMT, but
84: * in local time. So we have to convert GMT to local time
85: * if we're given GMT, otherwise we need only chop off the
86: * the seconds. Such braindamage.
87: */
88:
89: key = datebuf; /* Unless they specify GMT */
90:
91: if (argc > 0) {
92: if (streql(*argv, "GMT")) { /* Which we handle here */
93: date = dtol(datebuf);
94: if (date < 0) {
95: printf("%d Invalid date specification.\r\n",
96: ERR_CMDSYN);
97: (void) fflush(stdout);
98: return;
99: }
100: date = gmt_to_local(date);
101: key = ltod(date);
102: ++argv;
103: --argc;
104: }
105: }
106:
107: /* So, key now points to the local time, but we need to zap secs */
108:
109: key[10] = '\0';
110:
111: distcount = 0;
112: if (argc > 0) {
113: distcount = get_distlist(&distlist, *argv);
114: if (distcount < 0) {
115: printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
116: *argv);
117: (void) fflush(stdout);
118: return;
119: }
120: }
121:
122: fp = fopen(historyfile, "r");
123: if (fp == NULL) {
124: #ifdef SYSLOG
125: syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
126: #endif
127: printf("%d Cannot open history file.\r\n", ERR_FAULT);
128: (void) fflush(stdout);
129: return;
130: }
131:
132: printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
133:
134: if (seekuntil(fp, key, line, sizeof (line)) < 0) {
135: printf(".\r\n");
136: (void) fflush(stdout);
137: (void) fclose(fp);
138: return;
139: }
140:
141: /*
142: * History file looks like:
143: *
144: * <[email protected]> 01/22/86 09:19 net.micro.att/899 ucb.general/2545
145: * ^--tab ^--tab ^--space ^sp\0
146: * Sometimes the newsgroups are missing; we try to be robust and
147: * ignore such bogosity. We tackle this by our usual parse routine,
148: * and break the list of articles in the history file into an argv
149: * array with one newsgroup per entry.
150: */
151:
152: do {
153: if ((cp = index(line, '\t')) == NULL)
154: continue;
155:
156: if ((ngp = index(cp+1, '\t')) == NULL) /* 2nd tab */
157: continue;
158: ++ngp; /* Points at newsgroup list */
159: if (*ngp == '\n')
160: continue;
161: histcount = get_histlist(&histlist, ngp);
162: if (histcount == 0)
163: continue;
164:
165: /*
166: * For each newsgroup on this line in the history
167: * file, check it against the newsgroup names we're given.
168: * If it matches, then see if we're hacking distributions.
169: * If so, open the file and match the distribution line.
170: */
171:
172: if (!all)
173: if (!ngmatch(restreql, 0, nglist, ngcount,
174: histlist, histcount))
175: continue;
176:
177: if (distcount)
178: if (!distmatch(distlist, distcount, histlist, histcount))
179: continue;
180:
181: *cp = '\0';
182: putline(line);
183: #ifdef LOG
184: nn_told++;
185: #endif
186: } while (fgets(line, sizeof(line), fp) != NULL);
187:
188: putchar('.');
189: putchar('\r');
190: putchar('\n');
191: (void) fflush(stdout);
192: (void) fclose(fp);
193: }
194:
195:
196: /*
197: * seekuntil -- seek through the history file looking for
198: * a line with date "key". Get that line, and return.
199: *
200: * Parameters: "fp" is the active file.
201: * "key" is the date, in form YYMMDDHHMM (no SS)
202: * "line" is storage for the first line we find.
203: *
204: * Returns: -1 on error, 0 otherwise.
205: *
206: * Side effects: Seeks in history file, modifies line.
207: */
208:
209: seekuntil(fp, key, line, linesize)
210: FILE *fp;
211: char *key;
212: char *line;
213: int linesize;
214: {
215: char datetime[32];
216: register int c;
217: register long top, bot, mid;
218:
219: bot = 0;
220: (void) fseek(fp, 0L, 2);
221: top = ftell(fp);
222: for(;;) {
223: mid = (top+bot)/2;
224: (void) fseek(fp, mid, 0);
225: do {
226: c = getc(fp);
227: mid++;
228: } while (c != EOF && c!='\n');
229: if (!getword(fp, datetime, line, linesize)) {
230: return (-1);
231: }
232: switch (compare(key, datetime)) {
233: case -2:
234: case -1:
235: case 0:
236: if (top <= mid)
237: break;
238: top = mid;
239: continue;
240: case 1:
241: case 2:
242: bot = mid;
243: continue;
244: }
245: break;
246: }
247: (void) fseek(fp, bot, 0);
248: while(ftell(fp) < top) {
249: if (!getword(fp, datetime, line, linesize)) {
250: return (-1);
251: }
252: switch(compare(key, datetime)) {
253: case -2:
254: case -1:
255: case 0:
256: break;
257: case 1:
258: case 2:
259: continue;
260: }
261: break;
262: }
263:
264: return (0);
265: }
266:
267:
268: compare(s, t)
269: register char *s, *t;
270: {
271: for (; *s == *t; s++, t++)
272: if (*s == 0)
273: return(0);
274: return (*s == 0 ? -1:
275: *t == 0 ? 1:
276: *s < *t ? -2:
277: 2);
278: }
279:
280:
281: getword(fp, w, line, linesize)
282: FILE *fp;
283: register char *w;
284: char *line;
285: int linesize;
286: {
287: register char *cp;
288:
289: if (fgets(line, linesize, fp) == NULL)
290: return (0);
291: if (cp = index(line, '\t')) {
292: /*
293: * The following gross hack is present because the history file date
294: * format is braindamaged. They like "mm/dd/yy hh:mm", which is useless
295: * for relative comparisons of dates using something like atoi() or
296: * strcmp. So, this changes their format into yymmddhhmm. Sigh.
297: *
298: * 12345678901234 ("x" for cp[x])
299: * mm/dd/yy hh:mm (their lousy representation)
300: * yymmddhhmm (our good one)
301: * 0123456789 ("x" for w[x])
302: */
303: *cp = '\0';
304: (void) strncpy(w, cp+1, 15);
305: w[0] = cp[7]; /* Years */
306: w[1] = cp[8];
307: w[2] = cp[1]; /* Months */
308: w[3] = cp[2];
309: w[4] = cp[4]; /* Days */
310: w[5] = cp[5];
311: w[6] = cp[10]; /* Hours */
312: w[7] = cp[11];
313: w[8] = cp[13]; /* Minutes */
314: w[9] = cp[14];
315: w[10] = '\0';
316: } else
317: w[0] = '\0';
318: return (1);
319: }
320:
321:
322: /*
323: * distmatch -- see if a file matches a set of distributions.
324: * We have to do this by (yech!) opening the file, finding
325: * the Distribution: line, if it has one, and seeing if the
326: * things match.
327: *
328: * Parameters: "distlist" is the distribution list
329: * we want.
330: * "distcount" is the count of distributions in it.
331: * "grouplist" is the list of groups (articles)
332: * for this line of the history file. Note that
333: * this isn't quite a filename.
334: * "groupcount" is the count of groups in it.
335: *
336: * Returns: 1 if the article is in the given distribution.
337: * 0 otherwise.
338: */
339:
340: distmatch(distlist, distcount, grouplist, groupcount)
341: char *distlist[];
342: int distcount;
343: char *grouplist[];
344: int groupcount;
345: {
346: register char c;
347: register char *cp;
348: register FILE *fp;
349: register int i, j;
350: char buf[MAX_STRLEN];
351:
352: (void) strcpy(buf, spooldir);
353: (void) strcat(buf, "/");
354: (void) strcat(buf, grouplist[0]);
355:
356: for (cp = buf; *cp; cp++)
357: if (*cp == '.')
358: *cp = '/';
359:
360: fp = fopen(buf, "r");
361: if (fp == NULL) {
362: #ifdef SYSLOG
363: syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
364: #endif
365: return (0);
366: }
367:
368: while (fgets(buf, sizeof (buf), fp) != NULL) {
369: if ((c = buf[0]) == '\n') /* End of header */
370: break;
371: if (c != 'd' && c != 'D')
372: continue;
373: cp = index(cp + 1, '\n');
374: if (cp)
375: *cp = '\0';
376: cp = index(buf, ':');
377: if (cp == NULL)
378: continue;
379: *cp = '\0';
380: if (streql(buf, "distribution")) {
381: for (i = 0; i < distcount; ++i) {
382: if (streql(cp + 2, distlist[i])) {
383: (void) fclose(fp);
384: return (1);
385: }
386: }
387: (void) fclose(fp);
388: return (0);
389: }
390: }
391:
392: (void) fclose(fp);
393:
394: /*
395: * We've finished the header with no distribution field.
396: * So we'll assume that the distribution is the characters
397: * up to the first dot in the newsgroup name.
398: */
399:
400: for (i = 0; i < groupcount; i++) {
401: cp = index(grouplist[i], '.');
402: if (cp)
403: *cp = '\0';
404: for (j = 0; j < distcount; j++)
405: if (streql(grouplist[i], distlist[j]))
406: return (1);
407: }
408:
409: return (0);
410: }
411:
412:
413: /*
414: * get_histlist -- return a nicely set up array of newsgroups
415: * (actually, net.foo.bar/article_num) along with a count.
416: *
417: * Parameters: "array" is storage for our array,
418: * set to point at some static data.
419: * "list" is the history file newsgroup list.
420: *
421: * Returns: Number of group specs found.
422: *
423: * Side effects: Changes static data area.
424: */
425:
426: get_histlist(array, list)
427: char ***array;
428: char *list;
429: {
430: register int histcount;
431: register char *cp;
432: static char **hist_list = (char **) NULL;
433:
434: cp = index(list, '\n');
435: if (cp)
436: *cp-- = '\0';
437: histcount = parsit(list, &hist_list);
438: *array = hist_list;
439: return (histcount);
440: }
441:
442:
443: /*
444: * get_nglist -- return a nicely set up array of newsgroups
445: * along with a count, when given an NNTP-spec newsgroup list
446: * in the form ng1,ng2,ng...
447: *
448: * Parameters: "array" is storage for our array,
449: * set to point at some static data.
450: * "list" is the NNTP newsgroup list.
451: *
452: * Returns: Number of group specs found.
453: *
454: * Side effects: Changes static data area.
455: */
456:
457: get_nglist(array, list)
458: char ***array;
459: char *list;
460: {
461: register char *cp;
462: register int ngcount;
463:
464: for (cp = list; *cp != '\0'; ++cp)
465: if (*cp == ',')
466: *cp = ' ';
467:
468: ngcount = parsit(list, array);
469:
470: return (ngcount);
471: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.