home *** CD-ROM | disk | FTP | other *** search
- /*
- * (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_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_groups[cross_post];
- if (cpgh == gh) {
- if (seq_cross_filtering) continue;
- n = db_hdr.dh_cross_postings;
- break;
- }
- 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) {
- 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 (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_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->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);
-
- 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;
- }
-
-
-