/* xover.c */

#include "common.h"
#include "overview.h"

#ifdef XOVER
FILE *over_fp;
int over_num = -1;

void
doxover(argc, argv)
	int		argc;
	char		*argv[];
{
	register int	low, high;
	int		artnum, artptr;

	if (!canread) {
		printf("%d You only have permission to transfer, sorry.\r\n",
			ERR_ACCESS);
		(void) fflush(stdout);
		return;
	}

	if (!ingroup) {
		printf("%d You are not currently in a newsgroup.\r\n",
			ERR_NCING);
		(void) fflush(stdout);
		return;
	}
	if (argc != 1 && argc != 2) {
		printf("%d Usage: XOVER [artrange]\r\n", ERR_CMDSYN);
		(void) fflush(stdout);
		return;
	}

	if (argc == 1) {
		if (art_ptr < 0 || art_ptr >= num_arts) {
			printf("%d No article is currently selected.\r\n",
				ERR_NOCRNT);
			(void) fflush(stdout);
			return;
		}
		high = low = art_array[art_ptr];
		artptr = art_ptr;
	} else {
		register char *cp = index(argv[1], '-');
		if (cp == NULL)
			low = high = atoi(argv[1]);
		else {
			*cp++ = '\0';
			low = atoi(argv[1]);
			high = atoi(cp);
			if (high < low)
				if (num_arts > 0)
					high = art_array[num_arts-1];
				else
					high = low;
		}
		artptr = 0;
	}

	over_find(low);
	if (!over_fp) {
		printf("%d No overview available.\r\n", ERR_FAULT);
		(void) fflush(stdout);
#ifdef SYSLOG
		syslog(LOG_ERR, "xover: fopen %s: %m", OVER_NAME);
#endif
		return;
	}

	/* Return the desired data.  This is written carefully to avoid
	 * over-long lines. */
	printf("%d overview data follows\r\n", OK_OVER);

	for (;artptr < num_arts; artptr++) {
		if ((artnum = art_array[artptr]) < low)
			continue;
		if (artnum > high)
			break;

		if (over_num > 0 && over_num < artnum)
			over_find(artnum);
		if (over_num == artnum) {
			register int c;
			printf("%d", artnum);
			while ((c = getc(over_fp)) != EOF && c != '\n')
				putchar(c);
			if (fscanf(over_fp, "%d", &over_num) != 1)
				over_num = -1;
		} else
			over_fake(artnum);
		printf("\r\n");
	}
	printf(".\r\n");
	(void) fflush(stdout);
}

static int over_open_tried = 0;

int
over_is_cheap(low, high)
int low, high;
{
	if (over_fp != NULL) {
		if (low >= over_num && low <= over_num + 300)
			return 1;
	} else if (over_open_tried)
		return 0;
	return high > low;
}

int
over_find(artnum)
int artnum;
{
	if (over_fp) {
		if (over_num < 0 || over_num > artnum) {
			fseek(over_fp, 0L, 0);
			over_num = 0;
		}
	} else {
		if (!over_open_tried)
			over_fp = fopen(OVER_NAME, "r");
		over_open_tried = 1;
		if (!over_fp) {
			over_num = -1;
			return 0;
		}
		over_num = 0;
	}
	if (!over_num)
		fscanf(over_fp, "%d", &over_num);
	while (1) {
		register int c;
		if (feof(over_fp)) {
			over_num = -1;
			break;
		}
		if (over_num >= artnum) {
			break;
		}
		while ((c = getc(over_fp)) != EOF && c != '\n')
			continue;
		fscanf(over_fp, "%d", &over_num);
	}
	return over_num == artnum;
}

int
over_header(s)
char *s;
{
	int i;
	char ch;
	ch = (isascii(*s) && isupper(*s)) ? tolower(*s) : *s;

	for (i = 1; i <= OVER_LAST_FIELD; i++) {
		if (ch == *over_field[i]) {
			if (strcasecmp(s, over_field[i]) == 0)
				return i;
#ifdef OVER_UNIQUE_1ST_LTRS
			/* optimization assumes no 2 keywords w/same 1st ltr */
			break;
#endif
		}
	}
	return -1;
}

void
over_print_header(hdr, artname)
int hdr;
char *artname;
{
	int c;

	printf("%s ", artname);
	while (hdr--) {
		register int c;
		while ((c = getc(over_fp)) != '\t')
			if (c == EOF || c == '\n')
				goto no_contents;
	}
	c = getc(over_fp);
	if (c == EOF || c == '\n' || c == '\t') {
no_contents:
		printf("(none)\r\n");
	} else {
		do {
			putchar(c);
			c = getc(over_fp);
		} while (c != EOF && c != '\n' && c != '\t');
		printf("\r\n");
	}
	while (c != EOF && c != '\n')
		c = getc(over_fp);
	if (c == EOF || fscanf(over_fp, "%d", &over_num) != 1)
		over_num = -1;
}

void
over_fake(artnum)
int artnum;
{
	char		line[NNTP_STRLEN];
	register FILE	*fp;
	register char	*cp;
	register int	hdr;
	char		*array[OVER_LAST_FIELD+1];
	char		*malloc(), *realloc();

	(void) sprintf(line, "%d", artnum);
	fp = fopen(line, "r");
	if (fp == NULL)
		return;

	for (hdr = OVER_LAST_FIELD; hdr > 0; hdr--) {
		array[hdr] = 0;
	}
	while (fgets(line, sizeof line, fp) != NULL) {
		if (*line == '\n' || *line == '\0') {
			break;
		}
		if (isspace(*line)) {
			if (hdr > 0 && array[hdr]) {
				register char *cp2;
				register len = strlen(array[hdr]);
				for (cp = line+1; isspace(*cp); cp++)
					;
				*--cp = ' ';
				if ((cp2 = index(cp, '\n')) == NULL)
					cp2 = cp + strlen(cp);
				*cp2 = '\0';
				array[hdr] = realloc(array[hdr], cp2-cp+len+1);
				if (array[hdr])
					strcpy(array[hdr] + len, cp);
			}
		} else if ((cp = index(line, ':')) != NULL) {
			*cp = '\0';
			if ((hdr = over_header(line)) > 0) {
				register char *cp2;
				if (array[hdr])
					continue;  /* a duplicate header?!? */
				cp += 2;
				if ((cp2 = index(cp, '\n')) == NULL)
					cp2 = cp + strlen(cp);
				*cp2 = '\0';
				array[hdr] = malloc(cp2 - cp + 1);
				if (array[hdr])
					strcpy(array[hdr], cp);
			}
		} else
			hdr = 0;
	}

	printf("%d", artnum);
	for (hdr = 1; hdr <= OVER_LAST_FIELD; hdr++) {
		putchar('\t');
		if (array[hdr]) {
#if defined(OVER_XREFS) && defined(OVER_XREF_PREFIX)
			if (hdr == 8)
				printf("xref: ");
#endif
			printf("%s", array[hdr]);
			free(array[hdr]);
		} else if (hdr == 6) {		/* Fudge the byte header */
			struct stat s;
			fstat(fileno(fp), &s);
			printf("%u", s.st_size);
		}
	}

	(void) fclose(fp);
}

void
over_close()
{
	if (over_fp) {
		fclose(over_fp);
		over_fp = NULL;
		over_num = -1;
	}
	over_open_tried = 0;
}
#endif
