home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part16 / collect.c next >
Encoding:
C/C++ Source or Header  |  1990-06-07  |  11.0 KB  |  485 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Collect and save article information in database.
  5.  */
  6.  
  7. #include "config.h"
  8. #include "db.h"
  9. #include "news.h"
  10.  
  11. #define COUNT_RE_REFERENCES    /* no of >>> depends on Reference: line */
  12.  
  13. export int ignore_bad_articles = 1;    /* no Newsgroups: line */
  14. export int remove_bad_articles = 0;
  15. export time_t max_article_age = 0;
  16.  
  17. import int trace, debug_mode;
  18.  
  19. extern time_stamp pack_date();
  20.  
  21. static long bad_count;
  22.  
  23. static FILE *ix, *data;
  24.  
  25. static do_auto_archive(gh, f, num)
  26. group_header *gh;
  27. register FILE *f;
  28. article_number num;
  29. {
  30.     char line[200];
  31.     article_number last;
  32.     register FILE *arc;
  33.     register int c;
  34.     off_t start;
  35.     static char *arc_header = "Archived-Last: ";
  36.     /* Header format: Archived-Last: 88888888 group.name */
  37.     /* Fixed constants length == 15 and offset == 24 are used below */
  38.  
  39.     arc = open_file(gh->archive_file, OPEN_READ);
  40.     last = 0;
  41.     start = 0;
  42.     if (arc != NULL) {
  43.     while (fgets(line, 200, arc) != NULL) {
  44.         if (strncmp(line, arc_header, 15)) {
  45.         log_entry('E', "%s not archive for %s\n",
  46.               gh->archive_file, gh->group_name);
  47.         gh->master_flag &= ~M_AUTO_ARCHIVE;
  48.         fclose(arc);
  49.         return;
  50.         }
  51.         if (strncmp(line + 24, gh->group_name, gh->group_name_length)) {
  52.         start = ftell(arc);
  53.         continue;
  54.         }
  55.         last = atol(line + 15);
  56.         break;
  57.     }
  58.     fclose(arc);
  59.     arc = NULL;
  60.     }
  61.  
  62.     if (last >= num) return;
  63.  
  64.     arc = open_file(gh->archive_file, last > 0 ? OPEN_UPDATE : OPEN_CREATE);
  65.     if (arc == NULL) {
  66.     log_entry('E', "Cannot create archive file: %s\n", gh->archive_file);
  67.     gh->master_flag &= ~M_AUTO_ARCHIVE;
  68.     return;
  69.     }
  70.  
  71.     fseek(arc, start, 0);
  72.     fprintf(arc, "%s%8ld %s\n", arc_header, (long)num, gh->group_name);
  73.     fseek(arc, (off_t)0, 2);
  74.  
  75.     fseek(f, (off_t)0, 0);
  76.     while ((c = getc(f)) != EOF) putc(c, arc);
  77.     putc(NL, arc);
  78.     fclose(arc);
  79. }
  80.  
  81. static build_hdr(type)
  82. int type;
  83. {
  84.     register char *name, *subj;
  85.     int re;
  86.  
  87.     db_data.dh_type = type;
  88.  
  89.     if (type == DH_SUB_DIGEST) {
  90.  
  91.     name = digest.dg_from;
  92.     subj = digest.dg_subj;
  93.  
  94.     db_hdr.dh_lines = digest.dg_lines;
  95.  
  96.     db_hdr.dh_hpos = digest.dg_hpos;
  97.     db_hdr.dh_fpos = (int16)(digest.dg_fpos - db_hdr.dh_hpos);
  98.     db_hdr.dh_lpos = digest.dg_lpos;
  99.  
  100.     db_hdr.dh_date = pack_date(digest.dg_date ? digest.dg_date : news.ng_date);
  101.     } else {
  102.  
  103.     if (!news.ng_from) news.ng_from = news.ng_reply;
  104.  
  105.     name = news.ng_from;
  106.     subj = news.ng_subj;
  107.  
  108.     db_hdr.dh_lines = news.ng_lines;
  109.  
  110.     db_hdr.dh_hpos = 0;
  111.     db_hdr.dh_fpos = (int16)(news.ng_fpos);
  112.     db_hdr.dh_lpos = news.ng_lpos;
  113.  
  114.     db_hdr.dh_date = pack_date(news.ng_date);
  115.     }
  116.  
  117.     if (name) {
  118.     db_hdr.dh_sender_length = pack_name(db_data.dh_sender, name, NAME_LENGTH);
  119.     } else
  120.         db_hdr.dh_sender_length = 0;
  121.  
  122.     if (type == DH_DIGEST_HEADER) {
  123.     db_hdr.dh_subject_length = 1;
  124.     db_data.dh_subject[0] = '@';
  125.     } else
  126.     db_hdr.dh_subject_length = 0;
  127.  
  128.     db_hdr.dh_subject_length +=
  129.     pack_subject(db_data.dh_subject + db_hdr.dh_subject_length, subj, &re,
  130.              DBUF_SIZE);
  131.  
  132. #ifdef COUNT_RE_REFERENCES
  133.     if (re) re = 0x80;
  134.     if (news.ng_ref) {
  135.     for (name = news.ng_ref; *name; name++) {
  136.         if ((re & 0x7f) == 0x7f) break;
  137.         if (*name == '<') re++;
  138.     }
  139.     }
  140. #endif
  141.     db_hdr.dh_replies = re;
  142.  
  143.     if (db_write_art(data) < 0) write_error();
  144. }
  145.  
  146.  
  147. static collect_article(gh, art_num)
  148. register group_header *gh;
  149. article_number art_num;
  150. {
  151.     FILE *art_file;
  152.     news_header_buffer nhbuf, dgbuf;
  153.     article_header art_hdr;
  154.     int mode, count;
  155.     cross_post_number *cp_ptr;
  156.     long age;
  157.  
  158.     count = 0;
  159.  
  160.     db_hdr.dh_number = art_num;
  161.  
  162.     /* get article header */
  163.  
  164.     art_hdr.a_number = art_num;
  165.     art_hdr.hpos = (off_t)0;
  166.     art_hdr.lpos = (off_t)0;
  167.     art_hdr.flag = 0;
  168.  
  169.     mode = FILL_NEWS_HEADER | FILL_OFFSETS | SKIP_HEADER;
  170.     if ((gh->master_flag & (M_CONTROL | M_NEVER_DIGEST | M_ALWAYS_DIGEST)) == 0)
  171.     mode |= DIGEST_CHECK;
  172. #ifdef NNTP
  173.     if ((gh->master_flag & M_ALWAYS_DIGEST) == 0)
  174.     mode |= LAZY_BODY;
  175. #endif
  176.     if ((art_file = open_news_article(&art_hdr, mode, nhbuf, (char *)NULL)) == NULL) {
  177.  
  178. #ifdef NNTP
  179.     import nntp_failed;
  180.  
  181.     if (nntp_failed) {
  182.         /*
  183.          * connection to nntp_server is broken
  184.          * stop collection of articles immediately
  185.          */
  186.         return -1;
  187.     }
  188. #endif
  189.     /*
  190.      * it is not really necessary to save anything in the data file
  191.      * we simply use the index file to get the *first* available article
  192.      */
  193.     return 0;
  194.     }
  195.  
  196.     if (art_file == (FILE *)1) {    /* empty file */
  197.     if (!ignore_bad_articles) return 0;
  198.     news.ng_groups = NULL;
  199.     art_file = NULL;
  200.     } else
  201.     if ( max_article_age &&    /* == 0 if use_nntp */
  202.         (gh->master_flag & M_INCLUDE_OLD) == 0 &&
  203.         (age = m_time(art_file)) < max_article_age) {
  204.  
  205.         if (remove_bad_articles) unlink(group_path_name);
  206.  
  207.         log_entry('O', "%sold article (%ld days): %s/%ld",
  208.               remove_bad_articles ? "removed " : "",
  209.               (cur_time() - age) / (24 * 60 * 60),
  210.               current_group->group_name, (long)art_num);
  211.         bad_count++;
  212.         fclose(art_file);
  213.         return 0;
  214.     }
  215.  
  216.     if (ignore_bad_articles && news.ng_groups == NULL) {
  217.     char *rem = "";
  218.  
  219.     if (!use_nntp && remove_bad_articles) {
  220.         unlink(group_path_name);
  221.         rem = "removed ";
  222.     }
  223.  
  224.     log_entry('B', "%sbad article: %s/%ld", rem,
  225.           current_group->group_name, (long)art_num);
  226.     if (art_file != NULL) fclose(art_file);
  227.     bad_count++;
  228.     return 0;
  229.     }
  230.  
  231.     /* map cross-postings into a list of group numbers */
  232.  
  233.     db_hdr.dh_cross_postings = 0;
  234.  
  235.     if (gh->master_flag & M_CONTROL) {
  236.     /* we cannot trust the Newsgroups: line in the control group */
  237.     /* so we simply ignore it (i.e. use "Newsgroups: control") */
  238.     goto dont_digest;
  239.     }
  240.  
  241.     if (news.ng_groups) {
  242.     char *curg, *nextg;
  243.     group_header *gh1;
  244.  
  245.     for (nextg = news.ng_groups, cp_ptr = db_data.dh_cross; *nextg; ) {
  246.         curg = nextg;
  247.  
  248.         if (nextg = strchr(curg, ','))
  249.         *nextg++ = NUL;
  250.         else
  251.         nextg = "";
  252.  
  253.         if (strcmp(gh->group_name, curg) == 0)
  254.         gh1 = gh;
  255.         else
  256.         if ((gh1 = lookup(curg)) == NULL) continue;
  257.  
  258.         *cp_ptr++ = NETW_CROSS_EXT(gh1->group_num);
  259.         if (++db_hdr.dh_cross_postings == DBUF_SIZE) break;
  260.     }
  261.     }
  262.  
  263.     if (db_hdr.dh_cross_postings == 1)
  264.     db_hdr.dh_cross_postings = 0;    /* only current group */
  265.  
  266.     if (gh->master_flag & M_NEVER_DIGEST)
  267.     goto dont_digest;
  268.  
  269.     /* split digest */
  270.  
  271.     if ((gh->master_flag & M_ALWAYS_DIGEST) || (news.ng_flag & N_DIGEST)) {
  272.     int any = 0, cont = 1;
  273.  
  274.     skip_digest_body(art_file);
  275.  
  276.     while (cont && (cont = get_digest_article(art_file, dgbuf)) >= 0) {
  277.  
  278.         if (any == 0) {
  279.         build_hdr(DH_DIGEST_HEADER);    /* write DIGEST_HEADER */
  280.         count++;
  281.         db_hdr.dh_cross_postings = 0;    /* no cross post in sub */
  282.         any++;
  283.         }
  284.         build_hdr(DH_SUB_DIGEST);    /* write SUB_DIGEST */
  285.         count++;
  286.     }
  287.  
  288.     if (any) goto finish;
  289.     }
  290.  
  291.     /* not a digest */
  292.  
  293.  dont_digest:
  294.  
  295.     build_hdr(DH_NORMAL);    /* normal article */
  296.     count++;
  297.  
  298. finish:
  299.  
  300.     if (gh->master_flag & M_AUTO_ARCHIVE)
  301.     do_auto_archive(gh, art_file, art_num);
  302.  
  303.     fclose(art_file);
  304.  
  305.     return count;
  306. }
  307.  
  308.  
  309. /*
  310.  *    Collect unread articles in current group
  311.  *
  312.  *    On entry, init_group has been called to setup the proper environment
  313.  */
  314.  
  315. static long collect_group(gh)
  316. register group_header *gh;
  317. {
  318.     long article_count, temp, obad;
  319.     article_number start_collect;
  320.  
  321.     if (gh->last_db_article == 0) {
  322.     gh->first_db_article = gh->first_a_article;
  323.     gh->last_db_article = gh->first_db_article - 1;
  324.     }
  325.  
  326.     if (gh->last_db_article >= gh->last_a_article) return 0;
  327.  
  328.     if (gh->index_write_offset) {
  329.     ix = open_data_file(gh, 'x', OPEN_UPDATE|MUST_EXIST);
  330.     fseek(ix, gh->index_write_offset, 0);
  331.     } else
  332.         ix = open_data_file(gh, 'x', OPEN_CREATE|MUST_EXIST);
  333.  
  334.     if (gh->data_write_offset) {
  335.     data = open_data_file(gh, 'd', OPEN_UPDATE|MUST_EXIST);
  336.     fseek(data, gh->data_write_offset, 0);
  337.     } else
  338.     data = open_data_file(gh, 'd', OPEN_CREATE|MUST_EXIST);
  339.  
  340.     article_count = 0;
  341.     start_collect = gh->last_db_article+1;
  342.  
  343.     if (debug_mode) {
  344.     printf("\t\t%s (%ld..%ld)\r",
  345.            gh->group_name, start_collect, gh->last_a_article);
  346.     fl;
  347.     }
  348.     bad_count = obad = 0;
  349.  
  350.     while (gh->last_db_article < gh->last_a_article) {
  351.     if (s_hangup) break;
  352.     gh->last_db_article++;
  353.     if (debug_mode) {
  354.         printf("\r%ld", gh->last_db_article);
  355.         if (obad != bad_count) printf("\t%ld", bad_count);
  356.         obad = bad_count;
  357.         fl;
  358.     }
  359.     gh->data_write_offset = ftell(data);
  360. #ifdef NNTP
  361.     gh->index_write_offset = ftell(ix);
  362. #endif
  363.     temp = collect_article(gh, gh->last_db_article);
  364. #ifdef NNTP
  365.     if (temp < 0) {
  366.         /* connection failed, current article is not collected */
  367.         gh->last_db_article--;
  368.         article_count = -1;
  369.         goto out;
  370.     }
  371. #endif
  372. #ifndef RENUMBER_DANGER
  373.     if (temp == 0 && gh->data_write_offset == (off_t)0) {
  374.         gh->first_db_article = gh->last_db_article + 1;
  375.         continue;
  376.     }
  377. #endif
  378.     if (!db_write_offset(ix, &(gh->data_write_offset)))
  379.         write_error();
  380.     article_count += temp;
  381.     }
  382.  
  383.     if (start_collect < gh->first_db_article)
  384.     start_collect = gh->first_db_article;
  385.  
  386.     if (trace && start_collect <= gh->last_db_article)
  387.     log_entry('T', "Col %s (%d to %d) %d",
  388.           gh->group_name,
  389.           start_collect, gh->last_db_article,
  390.           article_count);
  391.  
  392.     if (debug_mode)
  393.     printf("\nCol %s (%d to %d) %d",
  394.            gh->group_name,
  395.            start_collect, gh->last_db_article,
  396.            article_count);
  397.  
  398.     gh->data_write_offset = ftell(data);
  399.     gh->index_write_offset = ftell(ix);
  400.  
  401.  out:
  402.     fclose(data);
  403.     fclose(ix);
  404.  
  405.     if (debug_mode) putchar(NL);
  406.  
  407.     return article_count;
  408. }
  409.  
  410.  
  411. do_collect()
  412. {
  413.     register group_header *gh;
  414.     long col_article_count, temp;
  415.     int col_group_count;
  416.     time_t start_time;
  417.  
  418.     start_time = cur_time();
  419.     col_article_count = col_group_count = 0;
  420.     current_group = NULL; /* for init_group */
  421.     temp = 0;
  422.  
  423.     Loop_Groups_Header(gh) {
  424.     if (s_hangup) {
  425.         temp = -1;
  426.         break;
  427.     }
  428.  
  429.     if (gh->master_flag & M_IGNORE_GROUP) continue;
  430.  
  431.     if (gh->master_flag & M_MUST_CLEAN)
  432.         clean_group(gh);
  433.  
  434.     if (gh->last_db_article == gh->last_a_article) {
  435.         if (gh->master_flag & M_BLOCKED) goto unblock_group;
  436.         continue;
  437.     }
  438.  
  439.     if (!init_group(gh)) {
  440.         if ((gh->master_flag & M_NO_DIRECTORY) == 0) {
  441.         log_entry('R', "%s: no directory", gh->group_name);
  442.         gh->master_flag |= M_NO_DIRECTORY;
  443.         }
  444.         gh->last_db_article = gh->last_a_article;
  445.         gh->first_db_article = gh->last_a_article;    /* OBS: not first */
  446.         gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
  447.         db_write_group(gh);
  448.         continue;
  449.     }
  450.  
  451.     if (gh->master_flag & M_NO_DIRECTORY) {
  452.         /* The directory has been created now */
  453.         gh->master_flag &= ~M_NO_DIRECTORY;
  454.         clean_group(gh);
  455.     }
  456.  
  457.     temp = collect_group(gh);
  458. #ifdef NNTP
  459.     if (temp < 0) {
  460.         /* connection broken */
  461.         gh->master_flag &= ~M_EXPIRE;    /* remains blocked */
  462.         db_write_group(gh);
  463.         break;
  464.     }
  465. #endif
  466.     if (temp > 0) {
  467.         col_article_count += temp;
  468.         col_group_count++;
  469.     }
  470.  
  471.      unblock_group:
  472.     if (temp > 0 || (gh->master_flag & M_BLOCKED)) {
  473.         gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
  474.         db_write_group(gh);
  475.     }
  476.     }
  477.  
  478.     if (col_article_count > 0)
  479.     log_entry('C', "Collect: %ld art, %d gr, %ld s",
  480.           col_article_count, col_group_count,
  481.           cur_time() - start_time);
  482.  
  483.     return temp >= 0;
  484. }
  485.