/*
 * DREADOVER group:article
 *
 *	Read the overview record related to an article in a specific group.
 *	This command is typically used for debugging purposes only.
 *
 * (c)Copyright 1998, Matthew Dillon, All Rights Reserved.  Refer to
 *    the COPYRIGHT file in the base directory of this distribution
 *    for specific rights granted.
 */

#include <dreaderd/defs.h>

char * allocTmpCopy(const char *buf, int bufLen);
void DReadOver(char *data);
void Usage(void);
void OverDump(void);

int ForceOpt = 0;
int ViewData = 0;
int VerboseMode = 0;

char *
allocTmpCopy(const char *buf, int bufLen)
{
    static char *SaveAry[8];
    static int SaveCnt;
    char **pptr;

    SaveCnt = (SaveCnt + 1) % arysize(SaveAry);
    pptr = &SaveAry[SaveCnt];
    if (*pptr)
        free(*pptr);
    *pptr = malloc(bufLen + 1);
    memcpy(*pptr, buf, bufLen);
    (*pptr)[bufLen] = 0;
    return(*pptr);
}

int
main(int ac, char **av)
{
    int i;
    int Doneone = 0;

    LoadDiabloConfig(ac, av);

    if (ac < 2)
	Usage();

    for (i = 1; i < ac; ++i) {
	char *ptr = av[i];

	if (*ptr != '-' || strcmp(ptr, "-") == 0) {
	    if (*ptr != '-') {
		DReadOver(ptr);
	    } else {
		char buf[512];
		while (fgets(buf, sizeof(buf), stdin) != NULL)
		    DReadOver(buf);
	    }
	    Doneone = 1;
	    continue;
	}
	ptr += 2;
	switch(ptr[-1]) {
	case 'a':
	    OverDump();
	    Doneone = 1;
	    break;
	case 'C':
	    /* diablo.config path */
	    break;
	case 'd':
	    VerboseMode = 1;
	    break;
	case 'f':
	    ForceOpt = 1;
	    break;
	case 'V':
	    PrintVersion();
	    break;
	case 'v':
	    ViewData = 1;
	    break;
	default:
	    Usage();
	}
    }
    if (!Doneone)
	Usage();
    return(0);
}

void
Usage(void)
{
    fprintf(stderr, "Prints out overview info from the overview cache\n");
    fprintf(stderr, "  Usage: dreadover [-f] [-v] [-a] [group:artno[-artnoend]]\n");
    fprintf(stderr, "     -f       : Force retrieval if art no mismatch\n");
    fprintf(stderr, "     -v       : Also view the overview data\n");
    fprintf(stderr, "     -a       : List maxarts for all newsgroups\n");
    fprintf(stderr, "     group    : The newsgroup group name\n");
    fprintf(stderr, "     artno    : The starting article number\n");
    fprintf(stderr, "     artnoend : The ending article number\n");
    exit(1);
}

void
DReadOver(char *data)
{
    const char *gfname;
    const char *slash;
    char *ptr, *p;
    int artNo = 0;
    int artNoStart = 0;
    int artNoEnd = 0;
    int fd1;
    int fd2;
    OverHead oh;
    struct stat st;
    int maxarts;
    char path[1024];

    if ((ptr = strrchr(data, ':')) != NULL) {
	*ptr++ = 0;
	artNo = strtol(ptr, NULL, 10);
	artNoStart = artNo;
	artNoEnd = artNoStart;
	if ((p = strrchr(ptr, '-')) != NULL)
		artNoEnd = strtol(p + 1, NULL, 10);
    }

    /*
     * Cycle through the overview entries
     */
    for (artNo = artNoStart; artNo <= artNoEnd; artNo++) {
	int pos;
	OverArt oa;

	/* Open the overview info file */

	gfname = GFName(data, GRPFTYPE_OVER, 0, 1, 0, &DOpts.ReaderGroupHashMethod);
	slash = strchr(gfname, '/');

	snprintf(path, sizeof(path), "%s/%s", PatExpand(GroupHomePat), gfname);
	printf("GROUPINFO:%s:%d\t%s", data, artNo, gfname);

	if ((fd1 = open(path, O_RDONLY)) < 0) {
	    printf("\t(array open fail)\n");
	    return;
	}

	if (read(fd1, &oh, sizeof(oh)) != sizeof(oh)) {
	    printf("\t(read header fail)\n");
	    close(fd1);
	    return;
	}

	if (oh.oh_Version != OH_VERSION ||
		    oh.oh_ByteOrder != OH_BYTEORDER) {
		printf("\t(wrong version or byte order)\n");
		close(fd1);
		return;
	}

	fstat(fd1, &st);
	maxarts = (st.st_size - oh.oh_HeadSize) / sizeof(OverArt);
	printf("\tmaxarts=%d", maxarts);

	pos = oh.oh_HeadSize + ((artNo & 0x7FFFFFFF) % maxarts) *
						sizeof(OverArt);
	printf("\tpos=%d", pos);
	lseek(fd1, pos, 0);
	if (read(fd1, &oa, sizeof(oa)) != sizeof(oa)) {
		printf("\t(unable to read OverArt)");
		close(fd1);
		return;
	}
	if (oa.oa_ArtNo <= 0) {
	    if (oa.oa_ArtNo == -1)
		printf("\t(Article cancelled)(%d)\n", oa.oa_ArtNo);
	    else if (oa.oa_ArtNo == -2)
		printf("\t(Article expired)(%d)\n", oa.oa_ArtNo);
	    else
		printf("\t(Article not found)(%d)\n", oa.oa_ArtNo);
	    close(fd1);
	    continue;
	}

	if (oa.oa_ArtNo != artNo) {
	    printf("\tartNoMismatch(got=%d  wanted=%d)\n", oa.oa_ArtNo, artNo);
	    if (!ForceOpt) {
		close(fd1);
		continue;
	    }
	}

        /*
	 * Open the overview data file
	 */

	gfname = GFName(data, GRPFTYPE_DATA, artNo & ~OD_HMASK, 1, 0,
						&DOpts.ReaderGroupHashMethod);
	snprintf(path, sizeof(path), "%s/%s",
				PatExpand(GroupHomePat), gfname);
	printf("\t%s", gfname);
	if ((fd2 = open(path, O_RDONLY)) < 0) {
		printf("\t(data open fail)\n");
		close(fd1);
		return;
	}

	printf("\tdataFilePos=%d\tsize=%d\treceived=%d\tbytes=%d\thash=%x.%x\n",
			oa.oa_SeekPos, oa.oa_Bytes, oa.oa_TimeRcvd,
			oa.oa_ArtSize, oa.oa_MsgHash.h1, oa.oa_MsgHash.h2);

	if (ViewData) {
	    static char *buf = NULL;
	    int buflen = 0;
	    int n = oa.oa_Bytes + 1;
	    int r;

	    if (n > buflen)
		buflen = n;
		buf = (char *)realloc(buf, buflen);
	    lseek(fd2, oa.oa_SeekPos, 0);
	    while ((r = read(fd2, buf, n)) > 0) {
		printf("%s", buf);
		n -= r;
	    }
	    close(fd2);
	}
	close(fd1);
	if (artNo <= artNoEnd)
	    printf("--------------------------------------------------------------------\n");
    }
    printf("\n");
}
/*
 * Dump the contents of the overview info files for all newsgroups in
 * active file.
 */
void
OverDump(void)
{
    char path[PATH_MAX];
    const char *gfname;
    char *slash;
    char *groupname;
    int recLen;
    int recOff;
    int fd1;
    OverHead oh;
    struct stat st;
    int maxarts;
    KPDB *KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR);

    if (KDBActive == NULL) {
	printf("Unable to open active file\n");
	exit(1);
    }
    for (recOff = KPDBScanFirst(KDBActive, 0, &recLen);
        recOff;
        recOff = KPDBScanNext(KDBActive, recOff, 0, &recLen)
    ) {
        int groupLen; 
        const char *rec;
        const char *group;
	int begno;

        rec = KPDBReadRecordAt(KDBActive, recOff, 0, NULL);
        group = KPDBGetField(rec, recLen, NULL, &groupLen, NULL);

        if (!group)
	    continue;

	groupname = allocTmpCopy(group, groupLen);

	begno = strtol(KPDBGetField(rec, recLen, "NB", NULL, "0"), NULL, 10);
	gfname = GFName(groupname, GRPFTYPE_OVER, 0, 1, 0,
						&DOpts.ReaderGroupHashMethod);
	slash = strchr(gfname, '/');

	snprintf(path, sizeof(path), "%s/%s", PatExpand(GroupHomePat), gfname);

	if ((fd1 = open(path, O_RDONLY)) < 0) {
	    if (VerboseMode)
		printf("%s (array open fail)\n", groupname);
	    continue;;
	}

	if (read(fd1, &oh, sizeof(oh)) != sizeof(oh)) {
	    if (VerboseMode)
		printf("%s (read header fail)\n", groupname);
	    close(fd1);
	    continue;;
	}

	if (oh.oh_Version != OH_VERSION ||
		    oh.oh_ByteOrder != OH_BYTEORDER) {
	    if (VerboseMode)
		printf("%s (wrong version or byte order)\n", groupname);
	    close(fd1);
	    continue;;
	}

	fstat(fd1, &st);
	maxarts = (st.st_size - oh.oh_HeadSize) / sizeof(OverArt);
	printf("%s:%d\n", groupname, maxarts);
	close(fd1);
    }
}


syntax highlighted by Code2HTML, v. 0.9.1