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.