home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part17 / articles.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  9.9 KB  |  474 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Basic article access and management
  5.  */
  6.  
  7. #include "config.h"
  8. #include "db.h"
  9. #include "articles.h"
  10. #include "regexp.h"
  11.  
  12. export int  seq_cross_filtering = 1;
  13. export int  select_leave_next = 0;     /* ask to select left over art. */
  14.  
  15.  
  16. /*
  17.  * memory management
  18.  */
  19.  
  20. static thunk
  21.     dummy_str_t = {
  22.     NULL,
  23.     NULL,
  24.     0L
  25.     },
  26.     dummy_art_t = {
  27.     NULL,
  28.     NULL,
  29.     0L
  30.     };
  31.  
  32.  
  33. static thunk *first_str_t = &dummy_str_t;
  34. static thunk *current_str_t = &dummy_str_t;
  35. static thunk *first_art_t = &dummy_art_t;
  36. static thunk *current_art_t = &dummy_art_t;
  37. static long  cur_str_size = 0, cur_art_size = 0;
  38. static char *next_str;
  39. static article_header *next_art;
  40. static article_header **art_array = NULL;
  41.  
  42. static article_number max_articles = 0, mem_offset = 0;
  43.  
  44. /*
  45.  * allocate one article header
  46.  */
  47.  
  48. #ifndef ART_THUNK_SIZE
  49. #define ART_THUNK_SIZE    127
  50. #endif
  51.  
  52. static new_thunk(t, ptr, size)
  53. thunk *t;
  54. char *ptr;
  55. long size;
  56. {
  57.     thunk *new;
  58.  
  59.     new = newobj(thunk, 1);
  60.  
  61.     new->next_thunk = t->next_thunk;
  62.     t->next_thunk = new;
  63.  
  64.     new->this_thunk = ptr;
  65.     new->thunk_size = size;
  66. }
  67.  
  68.  
  69. article_header *alloc_art()
  70. {
  71.     if (cur_art_size == 0) {
  72.     if (current_art_t->next_thunk == NULL)
  73.         new_thunk(current_art_t,
  74.               (char *)newobj(article_header, ART_THUNK_SIZE),
  75.               (long)ART_THUNK_SIZE);
  76.  
  77.     current_art_t = current_art_t->next_thunk;
  78.     next_art = (article_header *)current_art_t->this_thunk;
  79.     cur_art_size = current_art_t->thunk_size;
  80.     }
  81.  
  82.     cur_art_size--;
  83.     return next_art++;
  84. }
  85.  
  86. /*
  87.  * allocate a string of length 'len'
  88.  */
  89.  
  90. #ifndef STR_THUNK_SIZE
  91. #define STR_THUNK_SIZE    ((1<<14) - 32)    /* leave room for malloc header */
  92. #endif
  93.  
  94. char *alloc_str(len)
  95. int len;
  96. {
  97.     char *ret;
  98.  
  99.     if (cur_str_size <= len) {    /* must be room for len+1 bytes */
  100.     if (current_str_t->next_thunk == NULL)
  101.         new_thunk(current_str_t,
  102.               newstr(STR_THUNK_SIZE), (long)STR_THUNK_SIZE);
  103.  
  104.     current_str_t = current_str_t->next_thunk;
  105.     next_str = current_str_t->this_thunk;
  106.     cur_str_size = current_str_t->thunk_size;
  107.     }
  108.  
  109.     ret = next_str;
  110.     cur_str_size -= len + 1;
  111.     next_str += len;
  112.     *next_str++ = NUL;    /* string is null terminated */
  113.  
  114.     return ret;
  115. }
  116.  
  117. /*
  118.  * "free" the allocated memory
  119.  */
  120.  
  121. free_memory()
  122. {
  123.     current_str_t = first_str_t;
  124.     current_art_t = first_art_t;
  125.     cur_str_size  = 0;
  126.     cur_art_size  = 0;
  127.     n_articles      = 0;
  128. }
  129.  
  130.  
  131. /*
  132.  * mark/release memory
  133.  */
  134.  
  135.  
  136. mark_str(str_marker)
  137. string_marker *str_marker;
  138. {
  139.     str_marker->sm_cur_t = current_str_t;
  140.     str_marker->sm_size  = cur_str_size;
  141.     str_marker->sm_next  = next_str;
  142. }
  143.  
  144. release_str(str_marker)
  145. string_marker *str_marker;
  146. {
  147.     current_str_t = str_marker->sm_cur_t;
  148.     cur_str_size  = str_marker->sm_size;
  149.     next_str      = str_marker->sm_next;
  150. }
  151.  
  152.  
  153. mark_memory(mem_marker)
  154. memory_marker *mem_marker;
  155. {
  156.     mark_str(&(mem_marker->mm_string));
  157.  
  158.     mem_marker->mm_cur_t = current_art_t;
  159.     mem_marker->mm_size  = cur_art_size;
  160.     mem_marker->mm_next  = next_art;
  161.  
  162.     mem_marker->mm_nart     = n_articles;
  163.     mem_offset += n_articles;
  164.  
  165.     n_articles = 0;
  166.     articles = art_array + mem_offset;
  167. }
  168.  
  169. release_memory(mem_marker)
  170. memory_marker *mem_marker;
  171. {
  172.     release_str(&(mem_marker->mm_string));
  173.  
  174.     current_art_t = mem_marker->mm_cur_t;
  175.     cur_art_size  = mem_marker->mm_size;
  176.     next_art      = mem_marker->mm_next;
  177.  
  178.     n_articles = mem_marker->mm_nart;
  179.  
  180.     mem_offset -= n_articles;
  181.     articles = art_array + mem_offset;
  182. }
  183.  
  184. /*
  185.  * merge all memory chunks into one.
  186.  */
  187.  
  188. merge_memory()
  189. {
  190.     n_articles += mem_offset;
  191.     mem_offset = 0;
  192.     articles = art_array;
  193. }
  194.  
  195.  
  196. /*
  197.  * save article header in 'articles' array
  198.  * 'articles' is enlarged if too small
  199.  */
  200.  
  201. #define    FIRST_ART_ARRAY_SIZE    500    /* malloc header */
  202. #define    NEXT_ART_ARRAY_SIZE    512
  203.  
  204. add_article(art)
  205. article_header *art;
  206. {
  207.     if ((n_articles + mem_offset) == max_articles) {
  208.     /* must increase size of 'articles' */
  209.  
  210.     if (max_articles == 0) {
  211.         /* allocate initial 'articles' array */
  212.         max_articles = FIRST_ART_ARRAY_SIZE;
  213.     } else {
  214.         max_articles += NEXT_ART_ARRAY_SIZE;
  215.     }
  216.     art_array = resizeobj(art_array, article_header *, max_articles);
  217.     articles = art_array + mem_offset;
  218.     }
  219.  
  220.     articles[n_articles] = art;
  221.     n_articles++;
  222. }
  223.  
  224.  
  225. access_group(gh, first_article, last_article, flags, mask)
  226. register group_header *gh;
  227. article_number first_article, last_article;
  228. register flag_type flags;
  229. char *mask;
  230. {
  231.     group_header *cpgh;
  232.     FILE *data;
  233.     off_t data_offset;
  234.     register article_header *ah;
  235.     cross_post_number cross_post;
  236.     int skip_digest, n;
  237.     attr_type leave_attr, test_article();
  238.     memory_marker mem_marker;
  239.     static regexp *rexp = NULL;
  240.     static char subptext[80];
  241.  
  242.     if (first_article < gh->first_db_article)
  243.     first_article = gh->first_db_article;
  244.  
  245.     if (last_article > gh->last_db_article)
  246.     last_article = gh->last_db_article;
  247.  
  248.     if (last_article == 0 || first_article > last_article) return 0;
  249.  
  250.     data = open_data_file(gh, 'd', OPEN_READ);
  251.     if (data == NULL) return -10;
  252.  
  253.     if ((data_offset = get_data_offset(gh, first_article)) == (off_t)(-1))
  254.     return -11;
  255.  
  256.  
  257.     if (mask == NULL) {
  258.     if (rexp != NULL) {
  259.         freeobj(rexp);
  260.         rexp = NULL;
  261.     }
  262.     } else {
  263.     if (*mask == '/') {
  264.         mask++;
  265.         if (rexp != NULL) {
  266.         if (strncmp(mask, subptext, 80) != 0) {
  267.             freeobj(rexp);
  268.             rexp = NULL;
  269.         }
  270.         }
  271.         if (rexp == NULL) {
  272.         strncpy(subptext, mask, 80);
  273.         rexp = regcomp(mask);
  274.         if (rexp == NULL) return -1;
  275.         }
  276.         /* notice mask is still non-NULL */
  277.     }
  278.     }
  279.  
  280.     if ((flags & (ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES)))
  281.     leave_attr = 0;
  282.     else if (select_leave_next)
  283.     leave_attr = A_READ;    /* will prompt */
  284.     else
  285.     leave_attr = A_LEAVE_NEXT;
  286.  
  287.     if (!(flags & ACC_SPEW_MODE))
  288.     use_newsrc(gh, (flags & ACC_ORIG_NEWSRC) ? 1 : 0);
  289.  
  290.     if ((flags & ACC_EXTRA_ARTICLES) == 0)
  291.     mark_memory(&mem_marker);
  292.  
  293.     ah = alloc_art();
  294.  
  295.     skip_digest = 0;
  296.  
  297.     fseek(data, data_offset, 0);
  298.  
  299.     while (ftell(data) < gh->data_write_offset) {
  300.     if (db_read_art(data) <= 0) {
  301.         fclose(data);
  302.         if ((flags & ACC_EXTRA_ARTICLES) == 0)
  303.         release_memory(&mem_marker);
  304.         return -2;
  305.     }
  306.  
  307.     if (db_hdr.dh_lpos == (off_t)0)
  308.         continue;    /* article not accessible */
  309.  
  310.     if (db_hdr.dh_number > gh->last_db_article
  311.         || db_hdr.dh_number < gh->first_db_article)
  312.         goto data_error;
  313.  
  314.     if (skip_digest && db_data.dh_type == DH_SUB_DIGEST)
  315.         continue;
  316.  
  317.     skip_digest = 0;
  318.  
  319.     if (db_hdr.dh_cross_postings && !(flags & ACC_ALSO_CROSS_POSTINGS)) {
  320.         for (n = 0; n < db_hdr.dh_cross_postings; n++) {
  321.         cross_post = NETW_CROSS_INT(db_data.dh_cross[n]);
  322.         if (cross_post < 0 || cross_post >= master.number_of_groups)
  323.             continue;
  324.         cpgh = &active_groups[cross_post];
  325.         if (cpgh == gh) {
  326.             if (seq_cross_filtering) continue;
  327.             n = db_hdr.dh_cross_postings;
  328.             break;
  329.         }
  330.         if (cpgh->group_flag & G_UNSUBSCRIBED) continue;
  331.  
  332.         if (!seq_cross_filtering) break;
  333.         if (cpgh->preseq_index > 0 &&
  334.             cpgh->preseq_index < gh->preseq_index) break;
  335.         }
  336.  
  337.         if (n < db_hdr.dh_cross_postings) {
  338.         if (db_data.dh_type == DH_DIGEST_HEADER) skip_digest++;
  339.         continue;
  340.         }
  341.     }
  342.  
  343.     ah->flag = 0;
  344.  
  345.     switch (db_data.dh_type) {
  346.      case DH_DIGEST_HEADER:
  347.         if (flags & ACC_DONT_SPLIT_DIGESTS)
  348.         skip_digest++;
  349.         else
  350.         if ((flags & ACC_ALSO_FULL_DIGEST) == 0)
  351.             continue;    /* don't want the full digest when split */
  352.         ah->flag |= A_FULL_DIGEST;
  353.         break;
  354.      case DH_SUB_DIGEST:
  355.         ah->flag |= A_DIGEST;
  356.         break;
  357.     }
  358.  
  359.     ah->a_number = db_hdr.dh_number;
  360.     if (ah->a_number > last_article) break;
  361.  
  362.     if (flags & ACC_SPEW_MODE) {
  363.         printf("%x:%s\n", (int)(gh->group_num), db_data.dh_subject);
  364.         continue;
  365.     }
  366.  
  367.     ah->hpos = db_hdr.dh_hpos;
  368.     ah->fpos = ah->hpos + (off_t)(db_hdr.dh_fpos);
  369.     ah->lpos = db_hdr.dh_lpos;
  370.  
  371.     ah->attr = test_article(ah);
  372.  
  373.     if (ah->attr != A_READ && (flags & ACC_ONLY_READ_ARTICLES))
  374.         continue;
  375.  
  376.     if (rexp != NULL) {
  377.         if (flags & ACC_ON_SUBJECT)
  378.         if (regexec_cf(rexp, db_data.dh_subject)) goto match_ok;
  379.         if (flags & ACC_ON_SENDER)
  380.         if (regexec_cf(rexp, db_data.dh_sender)) goto match_ok;
  381.         continue;
  382.     } else
  383.     if (mask != NULL) {
  384.         if (flags & ACC_ON_SUBJECT)
  385.         if (strmatch_cf(mask, db_data.dh_subject)) goto match_ok;
  386.         if (flags & ACC_ON_SENDER)
  387.         if (strmatch_cf(mask, db_data.dh_sender)) goto match_ok;
  388.         continue;
  389.     }
  390.      match_ok:
  391.  
  392.      attr_again:
  393.  
  394.     switch (ah->attr) {
  395.      case A_LEAVE:
  396.         if (mask) {
  397.         ah->attr = 0;
  398.         break;
  399.         }
  400.  
  401.         if (leave_attr == A_READ) {
  402.         clrdisp();
  403.         prompt("Select left over articles in group %s? ", gh->group_name);
  404.         leave_attr = yes(0) > 0 ? A_SELECT : A_LEAVE_NEXT;
  405.         }
  406.         ah->attr = leave_attr;
  407.         goto attr_again;
  408.  
  409.      case A_SELECT:
  410.         if (mask) ah->attr = 0;
  411.         break;
  412.  
  413.      case A_READ:
  414.         if (!(flags & (ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES)))
  415.         if (ah->a_number > gh->last_article)
  416.             continue;
  417.  
  418.         /* FALL THRU */
  419.  
  420.      case A_SEEN:
  421.      case 0:
  422.         if (flags & ACC_DO_KILL) {
  423.         ah->sender = db_data.dh_sender;
  424.         ah->subject = db_data.dh_subject;
  425.         if (kill_article(ah)) continue;
  426.         }
  427.  
  428.         /* The 'P' command to a read group must show articles as read */
  429. /******/    if (gh->unread_count <= 0) ah->attr = A_READ;
  430.         break;
  431.  
  432.      default:
  433.         break;
  434.     }
  435.  
  436.     if (ah->name_length = db_hdr.dh_sender_length) {
  437.         ah->sender = alloc_str((int)db_hdr.dh_sender_length);
  438.         strcpy(ah->sender, db_data.dh_sender);
  439.     } else
  440.         ah->sender = "";
  441.  
  442.     if (ah->subj_length = db_hdr.dh_subject_length) {
  443.         ah->subject = alloc_str((int)db_hdr.dh_subject_length);
  444.         strcpy(ah->subject, db_data.dh_subject);
  445.     } else
  446.         ah->subject = "";
  447.  
  448.     ah->replies = db_hdr.dh_replies;
  449.     ah->lines = db_hdr.dh_lines;
  450.     ah->t_stamp = db_hdr.dh_date;
  451.  
  452.     ah->a_group = (flags & ACC_MERGED_MENU) ? current_group : NULL;
  453.  
  454.     add_article(ah);
  455.     ah = alloc_art();
  456.     }
  457.  
  458.     fclose(data);
  459.  
  460.     if ((flags & ACC_DONT_SORT_ARTICLES) == 0)
  461.     sort_articles(-1);
  462.  
  463.     return n_articles > 0 ? 1 : 0;
  464.  
  465. data_error:
  466.     log_entry('E', "%s: data inconsistency", gh->group_name);
  467.     fclose(data);
  468.     if ((flags & ACC_EXTRA_ARTICLES) == 0)
  469.     release_memory(&mem_marker);
  470.     return -12;
  471. }
  472.  
  473.  
  474.