1 /* xover.c */
2 
3 #include "common.h"
4 #include "overview.h"
5 #include "xover.h"
6 #ifndef lint
7 static char sccsid[] = "$Id: xover.c,v 1.2 1994/11/01 06:08:21 sob Exp sob $";
8 #endif
9 #if defined(XOVER) || defined(XROVER)
10 void
numlist(argc,argv,obj)11 numlist(argc, argv, obj)
12 	int		argc;
13 	char		*argv[];
14 	struct xobj	*obj;
15 {
16 	register int	low, high;
17 	int		artnum, artptr;
18 	FILE		*fp;
19 
20 	if (!canread) {
21 		printf("%d You only have permission to transfer, sorry.\r\n",
22 			ERR_ACCESS);
23 		(void) fflush(stdout);
24 		return;
25 	}
26 
27 	if (!ingroup) {
28 		printf("%d You are not currently in a newsgroup.\r\n",
29 			ERR_NCING);
30 		(void) fflush(stdout);
31 		return;
32 	}
33 	if (argc != 1 && argc != 2) {
34 		printf("%d Usage: %s [artrange]\r\n", ERR_CMDSYN, obj->cmd);
35 		(void) fflush(stdout);
36 		return;
37 	}
38 
39 	if (argc == 1) {
40 		if (art_ptr < 0 || art_ptr >= num_arts) {
41 			printf("%d No article is currently selected.\r\n",
42 				ERR_NOCRNT);
43 			(void) fflush(stdout);
44 			return;
45 		}
46 		high = low = art_array[art_ptr];
47 		artptr = art_ptr;
48 	} else {
49 		register char *cp = index(argv[1], '-');
50 		if (cp == NULL)
51 			low = high = atoi(argv[1]);
52 		else {
53 			*cp++ = '\0';
54 			low = atoi(argv[1]);
55 			high = atoi(cp);
56 			if (high < low) {
57 				if (num_arts > 0)
58 					high = art_array[num_arts-1];
59 				else
60 					high = low;
61 			}
62 		}
63 		artptr = 0;
64 	}
65 
66 	xfind(obj, low);
67 	fp = obj->fp;
68 
69 	/* Return the desired data.  This is written carefully to avoid
70 	 * over-long lines. */
71 	printf("%d %s data follows\r\n", OK_OVER, obj->name);
72 
73 	for (;artptr < num_arts; artptr++) {
74 		if ((artnum = art_array[artptr]) < low)
75 			continue;
76 		if (artnum > high)
77 			break;
78 
79 		if (obj->num > 0 && obj->num < artnum)
80 			xfind(obj, artnum);
81 		if (obj->num == artnum) {
82 			register int c;
83 			printf("%d", artnum);
84 			while ((c = getc(fp)) != EOF && c != '\n')
85 				putchar(c);
86 			if (fscanf(fp, "%d", &obj->num) != 1)
87 				obj->num = -1;
88 			printf("\r\n");
89 		} else {
90 			printf("%d", artnum);
91 			(obj->fake)(artnum);
92 		}
93 	}
94 	printf(".\r\n");
95 	(void) fflush(stdout);
96 }
97 #endif
98 
99 #ifdef XOVER
100 FILE *over_open(void);
101 void over_fake(int artnum);
102 struct xobj over = {0,-1,0,over_open,over_fake,"overview","XOVER"};
103 
104 void
doxover(argc,argv)105 doxover(argc, argv)
106 	int		argc;
107 	char		*argv[];
108 {
109 	numlist(argc, argv, &over);
110 }
111 
112 int
over_is_cheap(low,high)113 over_is_cheap(low, high)
114 int low, high;
115 {
116 	if (over.fp)
117 		return 1;
118 	if (over.open_tried)
119 		return 0;
120 	return high >= low;
121 }
122 
123 FILE *
over_open()124 over_open()
125 {
126 	FILE *fp;
127 #ifdef OVERVIEW_DIR
128 	char name_buff[MAXPATHLEN], *cp;
129 	sprintf(name_buff, "%s/", OVERVIEW_DIR);
130 	cp = name_buff + strlen(name_buff);
131 	strcpy(cp, group_name);
132 	while ((cp = index(cp, '.')) != (char *) NULL)
133 		*cp = '/';
134 	sprintf(name_buff+strlen(name_buff), "/%s", OVER_NAME);
135 	fp = fopen(name_buff, "r");
136 #else
137 	fp = fopen(OVER_NAME, "r");
138 #endif
139 	return fp;
140 }
141 
142 #define TOLOWER(c) (isupper(c) ? tolower(c) : (c))
143 
144 int
over_header(s)145 over_header(s)
146 const char *s;
147 {
148 	int i;
149 	char ch;
150 	ch = (isascii(*s)? TOLOWER(*s) : *s);
151 
152 	for (i = 1; i < OVER_FIELD_COUNT; i++) {
153 		if (ch == *over_field[i]) {
154 			if (strcasecmp(s, over_field[i]) == 0)
155 				return i;
156 #ifdef OVER_UNIQUE_1ST_LTRS
157 			/* optimization assumes no 2 keywords w/same 1st ltr */
158 			break;
159 #endif
160 		}
161 	}
162 	return -1;
163 }
164 
165 char *
over_grab_header(hdr,output)166 over_grab_header(hdr, output)
167 int hdr;
168 int output;
169 {
170 	int c;
171 	int i = hdr;
172 	char *buf = NULL;
173 
174 #ifdef OVER_GROUP_FIELD
175 	if (i > OVER_GROUP_FIELD)
176 		i = OVER_GROUP_FIELD;
177 #endif
178 	while (i--) {
179 		while ((c = getc(over.fp)) != '\t')
180 			if (c == EOF || c == '\n')
181 				goto no_contents;
182 	}
183 	c = getc(over.fp);
184 #ifdef OVER_GROUP_FIELD
185 	if (hdr >= OVER_GROUP_FIELD) {
186 		for (i = 0; c != EOF && c != '\n'; i++) {
187 			if (c == ':' && !over_field[hdr][i]) {
188 				do {
189 					c = getc(over.fp);
190 				} while (c == ' ');
191 				break;
192 			}
193 			if (TOLOWER(c) != over_field[hdr][i]) {
194 				while (c != '\t') {
195 					if (c == EOF || c == '\n')
196 						goto no_contents;
197 					c = getc(over.fp);
198 				}
199 				i = -1;
200 			}
201 			c = getc(over.fp);
202 		}
203 	}
204 #endif
205 	if (c == EOF || c == '\n' || c == '\t') {
206 no_contents:
207 		if (output)
208 			printf("(none)\r\n");
209 	} else if (output) {
210 		do {
211 			putchar(c);
212 			c = getc(over.fp);
213 		} while (c != EOF && c != '\n' && c != '\t');
214 		printf("\r\n");
215 	} else {
216 		register int	size = 1024;
217 		buf = malloc(size);
218 		if (buf) {
219 			register int	pos = 0;
220 			do {
221 				if (pos >= size-1) {
222 					size += 1024;
223 					buf = realloc(buf, size);
224 					if (!buf)
225 						break;
226 				}
227 				buf[pos++] = c;
228 				c = getc(over.fp);
229 			} while (c != EOF && c != '\n' && c != '\t');
230 			if (buf)
231 				buf[pos] = '\0';
232 		}
233 	}
234 	while (c != EOF && c != '\n')
235 		c = getc(over.fp);
236 	if (c == EOF || fscanf(over.fp, "%d", &over.num) != 1)
237 		over.num = -1;
238 	return buf;
239 }
240 
241 void
over_fake(artnum)242 over_fake(artnum)
243 int artnum;
244 {
245 	char		line[NNTP_STRLEN];
246 	register FILE	*fp;
247 	register char	*cp, *cp2;
248 	register int	hdr;
249 	char		*array[OVER_FIELD_COUNT];
250 
251 	(void) sprintf(line, "%d", artnum);
252 	fp = fopen(line, "r");
253 	if (fp == NULL)
254 		return;
255 
256 	for (hdr = OVER_FIELD_COUNT-1; hdr > 0; hdr--) {
257 		array[hdr] = 0;
258 	}
259 	cp = line;
260 	while (fgets(line, sizeof line, fp) != NULL) {
261 		if (cp && *line == '\n') {
262 			break;
263 		}
264 		cp2 = cp;
265 		cp = index(line, '\n');
266 		if (!cp2 || isspace(*line)) {
267 			if (hdr > 0 && array[hdr]) {
268 				register int len = strlen(array[hdr]);
269 				if (cp2) {
270 					for (cp2 = line+1; isspace(*cp2); cp2++)
271 						;
272 					*--cp2 = ' ';
273 				}
274 				else
275 					cp2 = line;
276 				if (cp)
277 					*cp = '\0';
278 				array[hdr] = realloc(array[hdr],
279 						     strlen(cp2) + len + 1);
280 				if (array[hdr])
281 					strcpy(array[hdr] + len, cp2);
282 			}
283 		} else if ((cp2 = index(line, ':')) != NULL) {
284 			*cp2 = '\0';
285 			if ((hdr = over_header(line)) > 0) {
286 				if (array[hdr])
287 					continue;  /* a duplicate header?!? */
288 				cp2 += 2;
289 				if (cp)
290 					*cp = '\0';
291 				array[hdr] = malloc(strlen(cp2) + 1);
292 				if (array[hdr])
293 					strcpy(array[hdr], cp2);
294 			}
295 		} else
296 			hdr = 0;
297 	}
298 
299 	for (hdr = 1; hdr < OVER_FIELD_COUNT; hdr++) {
300 		putchar('\t');
301 		if (array[hdr]) {
302 #if defined(OVER_XREFS) && defined(OVER_XREF_PREFIX)
303 			if (hdr == 8)
304 				printf("xref: ");
305 #endif
306 			printf("%s", array[hdr]);
307 			free(array[hdr]);
308 		} else if (hdr == 6) {		/* Fudge the byte header */
309 			struct stat s;
310 			fstat(fileno(fp), &s);
311 			printf("%ld", s.st_size);
312 		}
313 	}
314 	printf("\r\n");
315 
316 	(void) fclose(fp);
317 }
318 #endif
319 
320 #ifdef XROVER
321 FILE *rover_open();
322 void rover_fake();
323 struct xobj rover = {0,-1,0,rover_open,rover_fake,"reference","XROVER"};
324 
325 void
doxrover(argc,argv)326 doxrover(argc, argv)
327 	int		argc;
328 	char		*argv[];
329 {
330 	numlist(argc, argv, &rover);
331 }
332 
333 FILE *
rover_open()334 rover_open()
335 {
336 	FILE *fp;
337 #ifdef ROVER_DIR
338 	char name_buff[MAXPATHLEN], *cp;
339 	sprintf(name_buff, "%s/", ROVER_DIR);
340 	cp = name_buff + strlen(name_buff);
341 	strcpy(cp, group_name);
342 	while ((cp = index(cp, '.')) != (char *) NULL)
343 		*cp = '/';
344 	sprintf(name_buff+strlen(name_buff), "/%s", ROVER_NAME);
345 	fp = fopen(name_buff, "r");
346 #else
347 	fp = fopen(ROVER_NAME, "r");
348 #endif
349 	return fp;
350 }
351 
352 void
rover_fake(artnum)353 rover_fake(artnum)
354 	int artnum;
355 {
356 	char		line[NNTP_STRLEN];
357 	register FILE	*fp;
358 	register char	*cp, *cp2;
359 	char		*references = NULL;
360 
361 #ifdef XOVER
362 	if (over_is_cheap(artnum, artnum)) {
363 		int hdr = over_header("references");
364 		if (hdr >= 0 && xfind(&over, artnum)) {
365 			references = over_grab_header(hdr, 0);
366 			goto output_refs;
367 		}
368 	}
369 #endif
370 	(void) sprintf(line, "%d", artnum);
371 	fp = fopen(line, "r");
372 	if (fp == NULL)
373 		return;
374 
375 	cp = line;
376 	while (fgets(line, sizeof line, fp) != NULL) {
377 		if (cp && *line == '\n') {
378 			break;
379 		}
380 		cp2 = cp;
381 		cp = index(line, '\n');
382 		if (!cp2 || isspace(*line)) {
383 			if (references) {
384 				register int len = strlen(references);
385 				if (cp2) {
386 					for (cp2 = line+1; isspace(*cp2); cp2++)
387 						;
388 					*--cp2 = ' ';
389 				}
390 				else
391 					cp2 = line;
392 				if (cp)
393 					*cp = '\0';
394 				references = realloc(references,
395 						     strlen(cp2) + len + 1);
396 				if (references)
397 					strcpy(references + len, cp2);
398 			}
399 		} else if (references)
400 			break;
401 		else if ((cp2 = index(line, ':')) != NULL) {
402 			*cp2 = '\0';
403 			if (strcasecmp(line, "references") == 0) {
404 				cp2 += 2;
405 				if (cp)
406 					*cp = '\0';
407 				references = malloc(strlen(cp2) + 1);
408 				if (references)
409 					strcpy(references, cp2);
410 			}
411 		}
412 	}
413 
414 	(void) fclose(fp);
415 
416 #ifdef XOVER
417 output_refs:
418 #endif
419 	if (references) {
420 		cp2 = references + strlen(references) - 1;
421 		while ((cp = rindex(references, '<')) != NULL) {
422 			while (cp2 >= cp
423 			    && ((unsigned char)*cp2 <= ' ' || *cp2 == ','))
424 				cp2--;
425 			cp2[1] = '\0';
426 			/* Quit parsing references if this one is garbage. */
427 			if (!valid_message_id(cp, cp2))
428 				break;
429 			/* Dump all domains that end in '.' */
430 			if (cp2[-1] == '.')
431 				break;
432 			if (!gethistent(cp, 0) || group_artnum == 0)
433 				printf(" %s", cp);
434 			else {
435 				printf(" %ld", group_artnum);
436 				break;
437 			}
438 			*cp = '\0';
439 			cp2 = cp-1;
440 		}
441 		free(references);
442 	}
443 	printf("\r\n");
444 }
445 
446 /* Check if the string we've found looks like a valid message-id reference.
447 */
448 int
valid_message_id(start,end)449 valid_message_id(start, end)
450 register char *start, *end;
451 {
452 	char *mid;
453 
454 	if (start == end)
455 		return 0;
456 
457 	if (*end != '>') {
458 		/* Compensate for space cadets who include the header in their
459 		** subsitution of all '>'s into another citation character. */
460 		if (*end == '<' || *end == '-' || *end == '!' || *end == '%'
461 		 || *end == ')' || *end == '|' || *end == ':' || *end == '}'
462 		 || *end == '*' || *end == '+' || *end == '#' || *end == ']'
463 		 || *end == '@' || *end == '$')
464 			*end = '>';
465 	} else if (end[-1] == '>') {
466 		*(end--) = '\0';
467 	}
468 	/* Id must be "<...@...>" */
469 	if (*start != '<' || *end != '>' || (mid = index(start, '@')) == NULL
470 	 || mid == start+1 || mid+1 == end)
471 		return 0;
472 	return 1;
473 }
474 #endif
475 
476 #if defined(XOVER) || defined(XROVER)
477 int
xfind(obj,artnum)478 xfind(obj, artnum)
479 	struct xobj	*obj;
480 	int		artnum;
481 {
482 	FILE		*fp = obj->fp;
483 	int		file_num = obj->num;
484 	if (fp) {
485 		if (file_num < 0 || file_num > artnum) {
486 			fseek(fp, 0L, 0);
487 			file_num = 0;
488 		}
489 	} else {
490 		if (!obj->open_tried)
491 			obj->fp = fp = (obj->open)();
492 		obj->open_tried = 1;
493 		if (!fp) {
494 			obj->num = -1;
495 			return 0;
496 		}
497 		file_num = 0;
498 	}
499 	if (!file_num)
500 		fscanf(fp, "%d", &file_num);
501 	while (1) {
502 		register int c;
503 		if (feof(fp)) {
504 			file_num = -1;
505 			break;
506 		}
507 		if (file_num >= artnum) {
508 			break;
509 		}
510 		while ((c = getc(fp)) != EOF && c != '\n')
511 			continue;
512 		fscanf(fp, "%d", &file_num);
513 	}
514 	obj->num = file_num;
515 	return file_num == artnum;
516 }
517 
518 void
xclose(obj)519 xclose(obj)
520 struct xobj *obj;
521 {
522 	if (obj->fp) {
523 		fclose(obj->fp);
524 		obj->fp = NULL;
525 		obj->num = -1;
526 	}
527 	obj->open_tried = 0;
528 }
529 
530 void
close_xfiles()531 close_xfiles()
532 {
533 #ifdef XOVER
534 	xclose(&over);
535 #endif
536 #ifdef XROVER
537 	xclose(&rover);
538 #endif
539 }
540 #endif
541