/*
libutil -- stuff dealing with articles

Written by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
Copyright 1998, 1999.

See file COPYING for restrictions on the use of this software.
*/

#include "leafnode.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mastring.h"
#include "ln_log.h"

/**
 * find a header in an article and return it, without its name.
 */
char *
fgetheader(FILE * f, const char *header)
{
    char *hdr, *p;
    size_t hlen;

    if (!header || !*header || header[(hlen = strlen(header))-1] != ':') {
	syslog(LOG_CRIT, "internal error in %s:%d", __FILE__, __LINE__); /* RATS: ignore */
	abort(); /* header must end with a colon */
    }

    if (!f)
	return NULL;
    rewind(f);
    debug = 0;
    hdr = NULL;
    while ((p = getfoldedline(f, getaline)) && *p) {
	/* read only headers */
	char *q = p;
	if ((strncasecmp(q, header, hlen) == 0)) {
	    q += hlen;
	    while (q && *q && isspace((unsigned char)*q))
		q++;
	    hdr = critstrdup(q, "fgetheader");
	    free(p); p = NULL;
	    break;
	}
	free(p); p = NULL;
    }
    if (p) free(p);
    debug = debugmode;
    rewind(f);
    return hdr;
}

char *
getheader(const char *filename, const char *header)
{
    FILE *f;
    char *hdr;
    struct stat st;

    if ((f = fopen(filename, "r")) == NULL)
	return NULL;
    if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode)) {
	(void)fclose(f);
	return NULL;
    }
    hdr = fgetheader(f, header);
    fclose(f);
    return hdr;
}

/*
 * store articles in newsgroups which are already stored in
 * $SPOOLDIR/message.id/
 */
void
store(const char *filename,
      FILE * filehandle, const char *newsgroups, const char *msgid)
{
    char tmp[50]; /* RATS: ignore */
    static struct newsgroup *cg;
    static struct newsgroup *cg_active;
    /* Ken Shan: we must not try to reuse the cg pointer,
     * it becomes invalid as the "active" pointer is realloc()ed. */
    mastr *xrefincase = mastr_new(4096);
    const char *p;
    char *q;

    if (verbose > 2)
	printf(".storing %s: %s\n", msgid, newsgroups);

    p = newsgroups;
    while (p && *p) {
	q = strchr(p, ',');
	if (q)
	    *q++ = '\0';
	SKIPLWS(p);
	if (*p) {
	    if (!cg || cg_active != active || strcmp(cg->name, p)) {
		cg = findgroup(p);
		cg_active = active;
		if (cg) {
		    if (isinteresting(cg->name) || create_all_links) {
			if (!chdirgroup(p, FALSE))
			    cg->first = cg->last + 1;

			if (!chdirgroup(p, TRUE)) {
			    ln_log(LNLOG_SERR, LNLOG_CTOP, 
				    "cannot create group directory for %s",
				    cg->name);
			    cg = NULL;
			}
		    } else {
			cg = NULL;
		    }
		}
	    }

	    /* cg may have become NULL if we don't want to store */
	    if (cg) {
		int r;

		if (cg->first < 1)
		    cg->first = 1;

		if (cg->last < cg->first)
		    cg->last = cg->first++;

		if (!chdirgroup(p, FALSE)) {
		    /* error */
		    p = q;
		    continue;
		}
		do {
		    sprintf(tmp, "%lu", ++cg->last);
		    errno = 0;
		} while ((r = link(filename, tmp)) < 0 && errno == EEXIST);
		if (r == 0 && verbose > 2)
		    printf("..as article %lu in %s\n", cg->last, cg->name);
		if (r < 0)
		    syslog(LOG_ERR, "error linking %s into %s: %m",
			   filename, p);
		else {
		    mastr_vcat(xrefincase, " ", cg->name, ":", tmp, NULL);
		}
	    } else {
		if (verbose > 2)
		    printf("..discarding unknown group %s\n", p);
	    }
	}
	p = q;
    }
    fprintf(filehandle, "Xref: %s%s\n", fqdn, mastr_str(xrefincase));
    mastr_delete(xrefincase);
}

#ifdef TEST
int verbose = 0;
int debug = 0;

int main(int argc, char **argv[]) {
    char *t;

    if (argc != 3) {
	fprintf(stderr, "usage: %s file header:\n", argv[0]);
	exit(1);
    }

    t = getheader(argv[1], argv[2]);
    printf("header %s in %s is:\n%s\n", argv[2], argv[1], t ? t : "(NULL)");
    exit(0);
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1