/*
 * LIB/ACTIVE.C	- dactive.kp active file support
 *
 * (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 "defs.h"

Prototype void InitDActive(const char *fileNamePat);
Prototype int InActive(const char *nglist);
Prototype int GenerateXRef(Buffer *b, const char *nglist, const char *npName, const char *ctl);
Prototype int UpdateActiveNX(char *xrefdata);
Prototype int CheckForModeratedGroups(const char *nglist);

KPDB *DActiveDB;

void 
InitDActive(const char *fileNamePat)
{
    DActiveDB = KPDBOpen(PatDbExpand(fileNamePat), O_RDWR);
    if (DActiveDB == NULL) {
	logit(LOG_CRIT, "InitDActive, open failed: %s", PatDbExpand(fileNamePat));
	exit(1);
    }
}

/*
 * Check to see if any of a list of comma-separated newsgroups exist in
 * the active file
 *
 *	Returns: 0 = no groups in active
 *		 1 = one or more groups in active
 */
int 
InActive(const char *nglist)
{
    const char *p = nglist;
    char group[MAXGNAME];
    int found = 0;

    while (*p) {
	int i;
	for (i = 0; p[i] && p[i] != ',' && p[i] != ' ' && p[i] != '\t'; ++i)
	    ;
	if (i == 0)
	    break;
	if (i < sizeof(group)) {
	    const char *rec;
	    int recLen;

	    bcopy(p, group, i);
	    group[i] = 0;
	    rec = KPDBReadRecord(DActiveDB, group, KP_LOCK, &recLen);
	    if (rec != NULL) {
		found = 1;
		break;
	    }
	}
	p += i;
	if (*p != ',')
	    break;
	++p;
    }
    return(found);
}

/*
 * GenerateXRef() - generate XRef: header for feeder.  Return the number
 *		    of groups that were included in the header.
 *
 *		    Note: if this is a control message, no XRef is generated
 *		    but we still return the group-match count.
 */

int 
GenerateXRef(Buffer *b, const char *nglist, const char *npName, const char *ctl)
{
    const char *p = nglist;
    char group[MAXGNAME];
    int count = 0;
    int doneHeader = 0;

    while (*p) {
	int i;
	for (i = 0; p[i] && p[i] != ',' && p[i] != ' ' && p[i] != '\t'; ++i)
	    ;
	if (i == 0)
	    break;
	if (i < sizeof(group)) {
	    const char *rec;
	    int recLen;

	    bcopy(p, group, i);
	    group[i] = 0;
	    rec = KPDBReadRecord(DActiveDB, group, KP_LOCK, &recLen);

	    /*
	     * Create ALL seen groups, if this define is enabled.  You will
	     * have to manually add a GD, M, and fix S as appropriate
	     * through some external process, if you use this.
	     */

	    if (! rec && DOpts.FeederAutoAddToActive) {
		if (ValidGroupName(group) < 0) {
		    /* logit(LOG_ERR, "group %s illegal", group); */
		} else {
		    char tsBuf[64];

		    KPDBWrite(DActiveDB, group, "NB", "1", KP_LOCK);
		    KPDBWrite(DActiveDB, group, "NE", "0", KP_LOCK_CONTINUE);
		    sprintf(tsBuf, "%08x", (int)time(NULL));
		    KPDBWrite(DActiveDB, group, "CTS", tsBuf, KP_LOCK_CONTINUE);
		    KPDBWrite(DActiveDB, group, "LMTS", tsBuf, KP_LOCK_CONTINUE);
		    KPDBWrite(DActiveDB, group, "S", "y", KP_UNLOCK);
	    	    rec = KPDBReadRecord(DActiveDB, group, KP_LOCK, &recLen);
		}
	    }

	    /*
	     * Control messages are special, Xref header is still required,
	     * but must only contain control.* groups. Therefore, for non
	     * control messages, process as normal. But, only the control
	     * group is put in the Xref for control messages.
	     */

	    if ((rec != NULL && !ctl[0]) || (rec != NULL && ctl[0] &&
					(strncmp("control",group,7) == 0)))
		{
		int f1len;
		int f2len;
		const char *f1 = KPDBGetField(rec, recLen, "NE", &f1len, NULL);
		const char *f2 = KPDBGetField(rec, recLen, "NX", &f2len, NULL);

		if (f1 || f2) {
		    int n;
		    char buf[16];

		    if (f2)
			n = (strtol(f2, NULL, 10) + 1) & 0x7FFFFFFF;
		    else
			n = (strtol(f1, NULL, 10) + 1) & 0x7FFFFFFF;

		    sprintf(buf, "%010d", n);
		    KPDBWrite(DActiveDB, group, "NX", buf, KP_UNLOCK);
		    if (!doneHeader) {
			bwrite(b, "Xref: ", 6);
			bwrite(b, npName, strlen(npName));
			doneHeader = 1;
		    }
		    bwrite(b, " ", 1);
		    bwrite(b, group, i);
		    bwrite(b, ":", 1);
		    sprintf(buf, "%d", n);
		    bwrite(b, buf, strlen(buf));
		    ++count;
		} else {
		    KPDBUnlock(DActiveDB, rec);
		}

	    /*
	     * Now catch the non control groups that were listed for a
	     * control message and unlock the active file.
	     */
	    } else if (rec != NULL && ctl[0]) {
                        ++count;
                        KPDBUnlock(DActiveDB, rec);
                    }
	}
	p += i;
	if (*p != ',')
	    break;
	++p;
    }
    if (doneHeader)
	bwrite(b, "\n", 1);
    return(count);
}

/*
 * CheckForModeratedGroups() - return 1 if any of the newsgroups listed are
 *			       marked as moderated in our active file.
 */
int
CheckForModeratedGroups(const char *nglist)
{
    const char *p = nglist;
    char group[MAXGNAME];
    int foundModerated = 0;

    while (*p) {
	int i;
	for (i = 0; p[i] && p[i] != ',' && p[i] != ' ' && p[i] != '\t'; ++i)
	    ;
	if (i == 0)
	    break;

	if (i < sizeof(group)) {
	    const char *rec;
	    int recLen;

	    bcopy(p, group, i);
	    group[i] = 0;
	    rec = KPDBReadRecord(DActiveDB, group, 0, &recLen);

	    if (rec != NULL) {
		int sLen;
		const char *s = KPDBGetField(rec, recLen, "S", &sLen, NULL);

		if (s && ((s[0] == 'm') || (s[0] == 'M'))) {
		    foundModerated = 1;
		}
	    }
	}

	p += i;
	if (*p != ',')
	    break;
	++p;
    }

    return foundModerated;
}

/*
 * UpdateActiveNX - update the active file NX field based on Xref: data
 *  This is useful for slaving Xref: data, but also maintaining
 *  the NX field in case this machine needs to become the Xref: master.
 */
int
UpdateActiveNX(char *xrefdata)
{
    char *p, *artnum, group[MAXGNAME];

    /* Throw away the first part of the line */
    p=strtok(xrefdata, " \t\n");
    if (p == NULL)
	return(-1);

    /* Now get the group:artnum pairs one at a time */
    p=strtok(NULL, " \t\n");
    while (p != NULL) {
	strncpy(group, p, sizeof(group) - 1);
	group[sizeof(group) - 1] = '\0';
	artnum=strchr(group, ':');
	if (artnum != NULL) {
	    const char *rec;
	    int recLen;

	    group[artnum-group]='\0';
	    artnum++;	
		
	    if (DebugOpt)
		ddprintf("XREF UPDATE %s %s\n",group, artnum);

	    rec=KPDBReadRecord(DActiveDB, group, KP_LOCK, &recLen);
	    if (rec != NULL) {
		int n;
		char buf[16];

		n = (strtol(artnum, NULL, 10)) & 0x7FFFFFFF;
		sprintf(buf, "%010d", n);
		KPDBWrite(DActiveDB, group, "NX", buf, KP_UNLOCK);
	    } else {
		return(0);
	    }
	}
	p=strtok(NULL, " \t\n");
    }
    return(1);
}



syntax highlighted by Code2HTML, v. 0.9.1