ftp.nice.ch/pub/next/unix/network/news/nn.6.4.16.s.tar.gz#/nn/articles.c

This is articles.c in view mode; [Download] [Up]

/*
 *	(c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
 *
 *	Basic article access and management
 */

#include "config.h"
#include "db.h"
#include "articles.h"
#include "regexp.h"

export int  seq_cross_filtering = 1;
export int  select_leave_next = 0; 	/* ask to select left over art. */


/*
 * memory management
 */

static thunk
    dummy_str_t = {
	NULL,
	NULL,
	0L
    },
    dummy_art_t = {
	NULL,
	NULL,
	0L
    };


static thunk *first_str_t = &dummy_str_t;
static thunk *current_str_t = &dummy_str_t;
static thunk *first_art_t = &dummy_art_t;
static thunk *current_art_t = &dummy_art_t;
static long  cur_str_size = 0, cur_art_size = 0;
static char *next_str;
static article_header *next_art;
static article_header **art_array = NULL;

static article_number max_articles = 0, mem_offset = 0;

/*
 * allocate one article header
 */

#ifndef ART_THUNK_SIZE
#define ART_THUNK_SIZE	127
#endif

static new_thunk(t, ptr, size)
thunk *t;
char *ptr;
long size;
{
    thunk *new;

    new = newobj(thunk, 1);

    new->next_thunk = t->next_thunk;
    t->next_thunk = new;

    new->this_thunk = ptr;
    new->thunk_size = size;
}


article_header *alloc_art()
{
    if (cur_art_size == 0) {
	if (current_art_t->next_thunk == NULL)
	    new_thunk(current_art_t,
		      (char *)newobj(article_header, ART_THUNK_SIZE),
		      (long)ART_THUNK_SIZE);

	current_art_t = current_art_t->next_thunk;
	next_art = (article_header *)current_art_t->this_thunk;
	cur_art_size = current_art_t->thunk_size;
    }

    cur_art_size--;
    return next_art++;
}

/*
 * allocate a string of length 'len'
 */

#ifndef STR_THUNK_SIZE
#define STR_THUNK_SIZE	((1<<14) - 32)	/* leave room for malloc header */
#endif

char *alloc_str(len)
int len;
{
    char *ret;

    if (cur_str_size <= len) {	/* must be room for len+1 bytes */
	if (current_str_t->next_thunk == NULL)
	    new_thunk(current_str_t,
		      newstr(STR_THUNK_SIZE), (long)STR_THUNK_SIZE);

	current_str_t = current_str_t->next_thunk;
	next_str = current_str_t->this_thunk;
	cur_str_size = current_str_t->thunk_size;
    }

    ret = next_str;
    cur_str_size -= len + 1;
    next_str += len;
    *next_str++ = NUL;	/* string is null terminated */

    return ret;
}

/*
 * "free" the allocated memory
 */

free_memory()
{
    current_str_t = first_str_t;
    current_art_t = first_art_t;
    cur_str_size  = 0;
    cur_art_size  = 0;
    n_articles	  = 0;
}


/*
 * mark/release memory
 */


mark_str(str_marker)
string_marker *str_marker;
{
    str_marker->sm_cur_t = current_str_t;
    str_marker->sm_size  = cur_str_size;
    str_marker->sm_next  = next_str;
}

release_str(str_marker)
string_marker *str_marker;
{
    current_str_t = str_marker->sm_cur_t;
    cur_str_size  = str_marker->sm_size;
    next_str      = str_marker->sm_next;
}


mark_memory(mem_marker)
memory_marker *mem_marker;
{
    mark_str(&(mem_marker->mm_string));

    mem_marker->mm_cur_t = current_art_t;
    mem_marker->mm_size  = cur_art_size;
    mem_marker->mm_next  = next_art;

    mem_marker->mm_nart	 = n_articles;
    mem_offset += n_articles;

    n_articles = 0;
    articles = art_array + mem_offset;
}

release_memory(mem_marker)
memory_marker *mem_marker;
{
    release_str(&(mem_marker->mm_string));

    current_art_t = mem_marker->mm_cur_t;
    cur_art_size  = mem_marker->mm_size;
    next_art      = mem_marker->mm_next;

    n_articles = mem_marker->mm_nart;

    mem_offset -= n_articles;
    articles = art_array + mem_offset;
}

/*
 * merge all memory chunks into one.
 */

merge_memory()
{
    n_articles += mem_offset;
    mem_offset = 0;
    articles = art_array;
}


/*
 * save article header in 'articles' array
 * 'articles' is enlarged if too small
 */

#define	FIRST_ART_ARRAY_SIZE	500	/* malloc header */
#define	NEXT_ART_ARRAY_SIZE	512

add_article(art)
article_header *art;
{
    if ((n_articles + mem_offset) == max_articles) {
	/* must increase size of 'articles' */

	if (max_articles == 0) {
	    /* allocate initial 'articles' array */
	    max_articles = FIRST_ART_ARRAY_SIZE;
	} else {
	    max_articles += NEXT_ART_ARRAY_SIZE;
	}
	art_array = resizeobj(art_array, article_header *, max_articles);
	articles = art_array + mem_offset;
    }

    articles[n_articles] = art;
    n_articles++;
}


access_group(gh, first_article, last_article, flags, mask)
register group_header *gh;
article_number first_article, last_article;
register flag_type flags;
char *mask;
{
    group_header *cpgh;
    FILE *data;
    off_t data_offset;
    register article_header *ah;
    cross_post_number cross_post;
    int skip_digest, n;
    attr_type leave_attr, test_article();
    memory_marker mem_marker;
    static regexp *rexp = NULL;
    static char subptext[80];

    if (first_article < gh->first_db_article)
	first_article = gh->first_db_article;

    if (last_article > gh->last_db_article)
	last_article = gh->last_db_article;

    if (last_article == 0 || first_article > last_article) return 0;

    data = open_data_file(gh, 'd', OPEN_READ);
    if (data == NULL) return -10;

    if ((data_offset = get_data_offset(gh, first_article)) == (off_t)(-1))
	return -11;


    if (mask == NULL) {
	if (rexp != NULL) {
	    freeobj(rexp);
	    rexp = NULL;
	}
    } else {
	if (*mask == '/') {
	    mask++;
	    if (rexp != NULL) {
		if (strncmp(mask, subptext, 80) != 0) {
		    freeobj(rexp);
		    rexp = NULL;
		}
	    }
	    if (rexp == NULL) {
		strncpy(subptext, mask, 80);
		rexp = regcomp(mask);
		if (rexp == NULL) return -1;
	    }
	    /* notice mask is still non-NULL */
	}
    }

    if ((flags & (ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES)))
	leave_attr = 0;
    else if (select_leave_next)
	leave_attr = A_READ;	/* will prompt */
    else
	leave_attr = A_LEAVE_NEXT;

    if (!(flags & ACC_SPEW_MODE))
	use_newsrc(gh, (flags & ACC_MERGED_NEWSRC) ? 2 :
		       (flags & ACC_ORIG_NEWSRC) ? 1 : 0);

    if ((flags & ACC_EXTRA_ARTICLES) == 0)
	mark_memory(&mem_marker);

    ah = alloc_art();

    skip_digest = 0;

    fseek(data, data_offset, 0);

    while (ftell(data) < gh->data_write_offset) {
	if (db_read_art(data) <= 0) {
	    fclose(data);
	    if ((flags & ACC_EXTRA_ARTICLES) == 0)
		release_memory(&mem_marker);
	    return -2;
	}

	if (db_hdr.dh_lpos == (off_t)0)
	    continue;	/* article not accessible */

	if (db_hdr.dh_number > gh->last_db_article
	    || db_hdr.dh_number < gh->first_db_article)
	    goto data_error;

	if (skip_digest && db_data.dh_type == DH_SUB_DIGEST)
	    continue;

	skip_digest = 0;

	if (db_hdr.dh_cross_postings && !(flags & ACC_ALSO_CROSS_POSTINGS)) {
	    for (n = 0; n < db_hdr.dh_cross_postings; n++) {
		cross_post = NETW_CROSS_INT(db_data.dh_cross[n]);
		if (cross_post < 0 || cross_post >= master.number_of_groups)
		    continue;
		cpgh = ACTIVE_GROUP(cross_post);
		if (cpgh == gh) {
		    if (seq_cross_filtering) continue;
		    n = db_hdr.dh_cross_postings;
		    break;
		}
		if (!(flags & ACC_ALSO_UNSUB_GROUPS))
		    if (cpgh->group_flag & G_UNSUBSCRIBED) continue;

		if (!seq_cross_filtering) break;
		if (cpgh->preseq_index > 0 &&
		    cpgh->preseq_index < gh->preseq_index) break;
	    }

	    if (n < db_hdr.dh_cross_postings) {
		if (db_data.dh_type == DH_DIGEST_HEADER) skip_digest++;
		continue;
	    }
	}

	ah->flag = 0;

	switch (db_data.dh_type) {
	 case DH_DIGEST_HEADER:
	    if (flags & ACC_DONT_SPLIT_DIGESTS)
		skip_digest++;
	    else
		if ((flags & ACC_ALSO_FULL_DIGEST) == 0)
		    continue;	/* don't want the full digest when split */
	    ah->flag |= A_FULL_DIGEST;
	    break;
	 case DH_SUB_DIGEST:
	    ah->flag |= A_DIGEST;
	    break;
	}

	ah->a_number = db_hdr.dh_number;
	if (ah->a_number > last_article) break;

	if (flags & ACC_SPEW_MODE) {
	    fold_string(db_data.dh_subject);
	    printf("%x:%s\n", (int)(gh->group_num), db_data.dh_subject);
	    continue;
	}

	ah->hpos = db_hdr.dh_hpos;
	ah->fpos = ah->hpos + (off_t)(db_hdr.dh_fpos);
	ah->lpos = db_hdr.dh_lpos;

	ah->attr = test_article(ah);

	if (flags & ACC_MERGED_NEWSRC) {
	    if (ah->attr == A_KILL) continue;
	} else
	if (ah->attr != A_READ && (flags & ACC_ONLY_READ_ARTICLES))
	    continue;

	if (rexp != NULL) {
	    if (flags & ACC_ON_SUBJECT)
		if (regexec_cf(rexp, db_data.dh_subject)) goto match_ok;
	    if (flags & ACC_ON_SENDER)
		if (regexec_cf(rexp, db_data.dh_sender)) goto match_ok;
	    continue;
	} else
	if (mask != NULL) {
	    if (flags & ACC_ON_SUBJECT)
		if (strmatch_cf(mask, db_data.dh_subject)) goto match_ok;
	    if (flags & ACC_ON_SENDER)
		if (strmatch_cf(mask, db_data.dh_sender)) goto match_ok;
	    continue;
	}
     match_ok:

     attr_again:

	switch (ah->attr) {
	 case A_LEAVE:
	    if (mask) {
		ah->attr = 0;
		break;
	    }

	    if (leave_attr == A_READ) {
		clrdisp();
		prompt("Select left over articles in group %s? ", gh->group_name);
		leave_attr = yes(0) > 0 ? A_SELECT : A_LEAVE_NEXT;
	    }
	    ah->attr = leave_attr;
	    goto attr_again;

	 case A_SELECT:
	    if (mask) ah->attr = 0;
	    break;

	 case A_READ:
	    if (flags & ACC_MERGED_NEWSRC) break;

	    if (!(flags & (ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES)))
		if (ah->a_number > gh->last_article)
		    continue;

	    /* FALL THRU */

	 case A_SEEN:
	 case 0:
	    if (flags & ACC_DO_KILL) {
		ah->replies = db_hdr.dh_replies;
		ah->sender = db_data.dh_sender;
		ah->subject = db_data.dh_subject;
		if (kill_article(ah)) continue;
	    }

	    /* The 'P' command to a read group must show articles as read */
/******/    if (gh->unread_count <= 0) ah->attr = A_READ;
	    break;

	 default:
	    break;
	}

	if (ah->name_length = db_hdr.dh_sender_length) {
	    ah->sender = alloc_str((int)db_hdr.dh_sender_length);
	    strcpy(ah->sender, db_data.dh_sender);
	} else
	    ah->sender = "";

	if (ah->subj_length = db_hdr.dh_subject_length) {
	    ah->subject = alloc_str((int)db_hdr.dh_subject_length);
	    strcpy(ah->subject, db_data.dh_subject);
	} else
	    ah->subject = "";

	ah->replies = db_hdr.dh_replies;
	ah->lines = db_hdr.dh_lines;
	ah->t_stamp = db_hdr.dh_date;

	ah->a_group = (flags & ACC_MERGED_MENU) ? current_group : NULL;

	add_article(ah);
	ah = alloc_art();
    }

    fclose(data);

    if ((flags & ACC_DONT_SORT_ARTICLES) == 0)
	sort_articles(-1);
    else
	no_sort_articles();

    return n_articles > 0 ? 1 : 0;

data_error:
    log_entry('E', "%s: data inconsistency", gh->group_name);
    fclose(data);
    if ((flags & ACC_EXTRA_ARTICLES) == 0)
	release_memory(&mem_marker);
    return -12;
}


These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.