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.