#include "gup.h"


/*
 * Read the group file into memory.  This routine serves a dual purpose
 * of reading the active file too!  An exclusion list can be specified
 * when reading the active file...
 */

LIST	*
read_groups(fd, exclusion_list)

    int		fd;
    LIST	*exclusion_list;

{

    LIST	*list;
    GROUP	*gp;
    char	*name;
    int		not;
    int		exclude;
#ifdef STDIO_LOADFILE
    char	*cp;
    char	lbuf[MAX_LINE_SIZE];
#else
    struct stat	stat;
    int		length;
#endif

    list = create_list();

#ifdef STDIO_READGROUP
    while (fgets(lbuf, sizeof(lbuf)-1, fp)) {	/* Load them all up */

	lbuf[strlen(lbuf) - 1] = '\0';		/* Zip trailing \n */

/* Ignore leading and trailing spaces */

	for (name=lbuf; *name; name++) {
	    if (!isspace(*name)) break;
	}

	for (cp=name; *cp; cp++) {
	    if (isspace(*cp)) {
		*cp++ = '\0';
		break;
	    }
	}

	not = (*name == '!');
	if (not)
	    name++;

/* check that this group is not on the site's exclusion list */
	exclude = FALSE;
	TRAVERSE(exclusion_list, gp) {
	    if (wildmat(name, gp->name))
		exclude = !gp->not;
	}

	if (!exclude) {
	    gp = create_group(not, name);
	    add_group(list, gp);		/* Link into list */
	}
    }
#else
    if (fstat(fd, &stat) < 0) {
	char buf[128];

	sprintf(buf, "read_groups: could not stat file (%s)", strerror(errno));
	logit(L_BOTH, "ERROR", buf);
	return list;
    }

    /* grab ourselves a buffer */
    name = (char *)malloc((unsigned int) stat.st_size + 1);
    if (!name)
	gupout(1, "Could not malloc space for groups list");

    /* slurp it in */
    length = read(fd, name, (int) stat.st_size);
    if (length != stat.st_size)
	gupout(1, "Error reading groups file");

    /* terminate the end */
    name[length] = 0;

    /*
     * hurl through the newsgroups, assigning descriptions to active_list
     * groups as we go
     */
    while (*name) {
	char *eoln, *p;

	/*
	 * null-terminate the end of the line, to prevent anything
	 * screaming off through the entire file
	 */
	eoln = strchr(name, '\n');
	if (eoln)
	    *eoln = 0;
	else
	    logit(L_LOG, "WARNING", "premature end of groups file");

	/* locate end of group name */
	p = strchr(name, ' ');
	if (p) {
	    /* found it */
	    *p = 0;
	}

	not = (*name == '!');
	if (not)
	    name++;

	/* check that this group is not on the site's exclusion list */
	exclude = FALSE;
	TRAVERSE(exclusion_list, gp) {
	    if (wildmat(name, gp->name))
		exclude = !gp->u.not;
	}

	if (!exclude) {
	    gp = create_group(not, name);
	    add_group(list, gp);		/* Link into list */
	}

	/* advance to next line */
	name = eoln + 1;
    }
#endif

    return list;
}


/* Check to see if a specific group is in the subscribed list */

int
subscribed(sub_list, gname)

    LIST	*sub_list;
    char	*gname;

{
    int		unsub = TRUE;
    GROUP	*gp;

    TRAVERSE(sub_list, gp) {
	if ((unsub != gp->u.not) && wildmat(gname, gp->name))
	    unsub = gp->u.not;
    }

    return !unsub;
}


LIST	*
create_list()

{
    LIST	*l;

    l = (LIST *)malloc(sizeof(LIST));
    if (!l)
	gupout(1, "malloc of LIST failed");

    l->head = l->tail = NULL;
    l->length = 0;

    return l;
}


void
add_group(list, group)

    LIST	*list;
    GROUP	*group;

{
    if (!list->head)
	list->head = list->tail = group;
    else {
	list->tail->next = group;
	list->tail = group;
    }
    list->length++;
}


void
remove_group(list, group)

    LIST	*list;
    GROUP	*group;

{
    GROUP	*prev, *tmp;

    prev = NULL;
    for (tmp = list->head; tmp; tmp = tmp->next) {
	if (tmp == group)
	    break;
	prev = tmp;
    }

    if (!tmp) {
	logit(L_BOTH, "ERROR", "remove_group can't find group");
	return;
    }

    /* unlink */
    if (!prev)
	list->head = group->next;	/* the first item was deleted */
    else
	prev->next = group->next;

    if (!group->next)
	list->tail = prev;

    list->length--;

    /* don't free() the element, since TRAVERSE() will be doing naughty
       things then (if we're called from within a TRAVERSE, that is) */

    /* if this was a problem, which it isn't, we would put group onto
       a free-list for reclamation */
}


extern	GROUP	*
create_group(not_flag, name)

    int		not_flag;
    const char	*name;

{
    GROUP	*gp;

    gp = (GROUP *) malloc(sizeof(GROUP));

    if (!gp)
	gupout(1, "malloc of GROUP failed");

    gp->next = NULL;
    gp->u.not = not_flag;
    gp->name = xstrdup(name);
    gp->desc = "";

    return gp;
}


void
destroy_group(gp)

    GROUP	*gp;

{
    free((char *) gp);
}


char	*
xstrdup(str)

    const char	*str;

{

    char	*res;

    res = (char *)malloc((unsigned int) strlen(str) + 1);

    if (!res) {
	sprintf(msg, "xstrdup of %d failed", strlen(str));
	gupout(1, msg);
    }

    return strcpy(res, str);
}
