4.4BSD/usr/src/contrib/news/trn3/head.c

Compare this file to the similar file:
Show the results in this format:

/* $Id: head.c,v 3.0 1992/02/23 21:25:39 davison Trn $
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "artio.h"
#include "cache.h"
#include "ng.h"
#include "ngdata.h"
#include "util.h"
#include "hash.h"
#include "rthread.h"
#include "rt-process.h"
#include "rt-util.h"
#include "final.h"
#include "nntp.h"
#include "INTERN.h"
#include "head.h"

bool first_one;		/* is this the 1st occurance of this header line? */

static char htypeix[26] =
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void
head_init()
{
    register int i;

    for (i=HEAD_FIRST+1; i<HEAD_LAST; i++)
	htypeix[*htype[i].ht_name - 'a'] = i;

    headbuf_size = LBUFLEN * 8;
    headbuf = safemalloc(headbuf_size);
}

#ifdef DEBUG
void
dumpheader(where)
char *where;
{
    register int i;

    printf("header: %d %s", parsed_art, where);

    for (i=0; i<HEAD_LAST; i++) {
	printf("%15s %4d %4d %03o\n",htype[i].ht_name,
	    htype[i].ht_minpos,
	    htype[i].ht_maxpos,
	    htype[i].ht_flags) FLUSH;
    }
}
#endif

int
set_line_type(bufptr,colon)
char *bufptr;
register char *colon;
{
    char lc[LONGKEY+3];
    register char *t, *f;
    register int i, len;

    if (colon-bufptr > LONGKEY+2)
	return SOME_LINE;

    for (t=lc,f=bufptr; f<colon; f++, t++) {
	if (isspace(*f))
	/* guard against space before : */
	    break;
	*t = isupper(*f) ? tolower(*f) : *f;
    }
    *t = '\0';
    f = lc;				/* get lc into register */
    len = t - f;

    /* now scan the headtype table, backwards so we don't have to supply an
     * extra terminating value, using first letter as index, and length as
     * optimization to avoid calling subroutine strEQ unnecessarily.  Hauls.
     */
    
    if (islower(*f)) {
	for (i = htypeix[*f - 'a']; *htype[i].ht_name == *f; --i) {
	    if (len == htype[i].ht_length && strEQ(f, htype[i].ht_name)) {
		return i;
	    }
	}
    }
    return SOME_LINE;
}

void
start_header(artnum)
ART_NUM artnum;
{
    register int i;

#ifdef DEBUG
    if (debug & DEB_HEADER)
	dumpheader("start_header\n");
#endif
    for (i=0; i<HEAD_LAST; i++) {
	htype[i].ht_minpos = -1;
	htype[i].ht_maxpos = 0;
    }
    in_header = SOME_LINE;
    first_one = FALSE;
    parsed_art = artnum;
}

void
end_header_line()
{
    if (first_one) {		/* did we just pass 1st occurance? */
	first_one = FALSE;
	/* remember where line left off */
	htype[in_header].ht_maxpos = artpos;
	if (htype[in_header].ht_flags & HT_CACHED) {
	    ARTICLE *ap = article_ptr(parsed_art);
	    if (!get_cached_line(ap, in_header, TRUE)) {
		int start = htype[in_header].ht_minpos
			  + htype[in_header].ht_length + 1;
		MEM_SIZE size;
		char *s;
		while (headbuf[start] == ' ' || headbuf[start] == '\t')
		    start++;
		size = artpos - start + 1 - 1;	/* pre-strip newline */
		if (in_header == SUBJ_LINE)
		    set_subj_line(ap,headbuf+start,size-1);
		else {
		    s = safemalloc(size);
		    *s = '\0';
		    safecat(s,headbuf+start,size);
		    set_cached_line(ap,in_header,s);
		}
	    }
	}
    }
}

bool
parseline(art_buf,newhide,oldhide)
char *art_buf;
int newhide, oldhide;
{
    if (*art_buf == ' ' || *art_buf == '\t') {
					/* header continuation line? */
	return oldhide;
    } else {				/* maybe another header line */
	char *s;
	end_header_line();
	s = index(art_buf,':');
	if (s == Nullch)	/* is it the end of the header? */
	    in_header = PAST_HEADER;
	else {	/* it is a new header line */
	    in_header = set_line_type(art_buf,s);
	    first_one = (htype[in_header].ht_minpos < 0);
	    if (first_one) {
		htype[in_header].ht_minpos = artpos;
		if (in_header == DATE_LINE) {
		    register ARTICLE *ap = article_ptr(parsed_art);
		    if (!ap->date)
			ap->date = parsedate(art_buf+6);
		}
	    }
#ifdef DEBUG
	    if (debug & DEB_HEADER)
		dumpheader(art_buf);
#endif
	    if (htype[in_header].ht_flags & HT_HIDE)
		return newhide;
	}
    }
    return FALSE;			/* don't hide this line */
}

void
end_header()
{
    register ARTICLE *ap = article_ptr(parsed_art);

    end_header_line();
    in_header = PAST_HEADER;	/* just to be sure */

    if (!ap->subj) {
	uncache_article(ap,FALSE);
	return;
    }

#ifndef DBM_XREFS
    if (htype[XREF_LINE].ht_minpos < 0)
	article_ptr(parsed_art)->xrefs = nullstr;
#endif
#ifdef USE_NNTP
    htype[PAST_HEADER].ht_minpos = artpos;    /* remember where body starts */
#else
    htype[PAST_HEADER].ht_minpos = ftell(artfp);
#endif

    if (ThreadedGroup && !(ap->flags & AF_THREADED)) {
	if (valid_article(ap)) {
	    ARTICLE *artp_hold = artp;
	    references = fetchlines(parsed_art, REFS_LINE);
	    thread_article(ap);
	    free(references);
	    artp = artp_hold;
	}
    } else if (!(ap->flags & AF_CACHED))
	cache_article(ap);
    check_poster(ap);
}

/* read the header into memory and parse it if we haven't already */

bool
parseheader(artnum)
ART_NUM artnum;
{
    register char *bp;
    register int len;

    if (parsed_art == artnum)
	return TRUE;
    if (artnum > lastart)
	return FALSE;
    spin(20);
#ifdef USE_NNTP
    if (!nntp_header(artnum)) {
	uncache_article(article_ptr(artnum),FALSE);
	return FALSE;
    }
#else
    if (!artopen(artnum))
	return FALSE;
#endif
    start_header(artnum);
    artpos = 0;
    bp = headbuf;
    while (in_header) {
	if (headbuf_size < artpos + LBUFLEN) {
	    headbuf_size += LBUFLEN * 4;
	    headbuf = saferealloc(headbuf,headbuf_size);
	}
#ifdef USE_NNTP
	nntp_gets(bp,LBUFLEN);
	if (*bp == '.') {
	    if (!bp[1]) {
		*bp++ = '\n';		/* tag the end with an empty line */
		artpos++;
		break;
	    }
	    strcpy(bp,bp+1);
	}
	len = strlen(bp);
	bp[len++] = '\n';
	bp[len] = '\0';
#else
	if (fgets(bp,LBUFLEN,artfp) == Nullch)
	    break;
	len = strlen(bp);
#endif
	parseline(bp,FALSE,FALSE);
	artpos += len;
	bp += len;
    }
    *bp = '\0';   /* this probably isn't needed */
    end_header();
    return TRUE;
}

/* get a header line from an article */

char *
fetchlines(artnum,which_line)
ART_NUM artnum;				/* article to get line from */
int which_line;				/* type of line desired */
{
    char *s, *t;
    register ART_POS firstpos;
    register ART_POS lastpos;
    int size;

    s = fetchcache(artnum,which_line);
    if (s)
	return savestr(s);
    if ((firstpos = htype[which_line].ht_minpos) < 0)
	return savestr(nullstr);

    firstpos += htype[which_line].ht_length + 1;
    lastpos = htype[which_line].ht_maxpos;
    size = lastpos - firstpos;
#ifdef DEBUG
    if (debug && (size < 1 || size > 1000)) {
	printf("Firstpos = %ld, lastpos = %ld\n",(long)firstpos,(long)lastpos);
	gets(cmd_buf);
    }
#endif
    s = safemalloc((MEM_SIZE)size);
    t = headbuf + firstpos;
    while (*t == ' ' || *t == '\t') t++;
    *s = '\0';
    safecat(s,t,size);
    return s;
}

/* prefetch a header line from one or more articles */

#ifdef USE_NNTP
char *
prefetchlines(artnum,which_line,copy)	/* NNTP version */
ART_NUM artnum;				/* article to get line from */
int which_line;				/* type of line desired */
bool_int copy;				/* do you want it savestr()ed? */
{
    register ARTICLE *ap;
    register char *s, *t;
    int size;
    register ART_NUM num, priornum, lastnum;
    bool cached = (htype[which_line].ht_flags & HT_CACHED);

    /* find_article() returns a Nullart if the artnum value is invalid */
    if (!(ap = find_article(artnum)) || (ap->flags & AF_MISSING))
	s = nullstr;
    else if (cached)
	s = get_cached_line(ap, which_line, untrim_cache);
    else
	s = Nullch;
    if (s) {
	if (copy)
	    s = savestr(s);
	return s;
    }

    spin(20);
    if (copy)
	s = safemalloc((MEM_SIZE)(size = LBUFLEN));
    else {
	s = cmd_buf;
	size = sizeof cmd_buf;
    }
    *s = '\0';
    priornum = artnum-1;
    lastnum = artnum + PREFETCH_SIZE - 1;
    if (lastnum > lastart)
	lastnum = lastart;
    if (cached)
	sprintf(ser_line,"XHDR %s %ld-%ld",htype[which_line].ht_name,
		artnum,lastnum);
    else
	sprintf(ser_line,"XHDR %s %ld",htype[which_line].ht_name,artnum);
    nntp_command(ser_line);
    if (nntp_check(TRUE) == NNTP_CLASS_OK) {
	for (;;) {
	    nntp_gets(ser_line, sizeof ser_line);
# ifdef DEBUG
	    if (debug & DEB_NNTP)
		printf("<%s\n", ser_line) FLUSH;
# endif
	    if (ser_line[0] == '.')
		break;
	    if ((t = index(ser_line, '\r')) != Nullch)
		*t = '\0';
	    if (!(t = index(ser_line, ' ')))
		continue;
	    t++;
	    num = atol(ser_line);
	    if (num < artnum || num > lastnum)
		continue;
	    while (++priornum < num)
		uncache_article(ap++,FALSE);
	    if (which_line == SUBJ_LINE)
		set_subj_line(ap++, t, strlen(t));
	    else if (cached)
		set_cached_line(ap++, which_line, savestr(t));
	    if (num == artnum)
		safecat(s,t,size);
	}
    } else {
	fprintf(stderr,"\nUnexpected close of server socket.\n");
	finalize(1);
    }
    while (priornum++ < lastnum)
	uncache_article(ap++,FALSE);
    if (copy)
	s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
    return s;
}

#else  /* !USE_NNTP */
char *
prefetchlines(artnum,which_line,copy)
ART_NUM artnum;				/* article to get line from */
int which_line;				/* type of line desired */
bool_int copy;				/* do you want it savestr()ed? */
{
    char *s, *t;
    register ART_POS firstpos;
    register ART_POS lastpos;
    int size;

    if (copy)
	return fetchlines(artnum,which_line);

    s = fetchcache(artnum,which_line);
    if (s)
	return s;
    if ((firstpos = htype[which_line].ht_minpos) < 0)
	return nullstr;

    firstpos += htype[which_line].ht_length + 1;
    lastpos = htype[which_line].ht_maxpos;
    size = lastpos - firstpos;
    t = headbuf + firstpos;
    while (*t == ' ' || *t == '\t') t++;
    *cmd_buf = '\0';
    safecat(cmd_buf,t,CBUFLEN);		/* hope this is okay--we're */
    return cmd_buf;			/* really scraping for space here */
}
#endif /* !USE_NNTP */