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

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Digest article handling
  5.  */
  6.  
  7. #include "config.h"
  8. #include "news.h"
  9. #include "debug.h"
  10.  
  11. #ifdef DG_TEST
  12.  
  13. #define TEST(fmt, x, y) if (Debug & DG_TEST) printf(fmt, x, y)
  14.  
  15. #else
  16.  
  17. #define TEST(fmt, x, y)
  18.  
  19. #endif
  20.  
  21. #define UNIFY 040
  22.  
  23. static char digest_pattern[] = "igest";
  24.  
  25. init_digest_parsing()
  26. {
  27.     register char *m;
  28.  
  29.     for (m = digest_pattern; *m; m++) *m |= UNIFY;
  30. }
  31.  
  32.  
  33. is_digest()
  34. {
  35.     register char *subject;
  36.     register char c, *q, *m;
  37.  
  38.     if ((subject = news.ng_subj) == NULL) return 0;
  39.  
  40.     while (c = *subject++) {
  41.     if ((c | UNIFY) != ('d' | UNIFY)) continue;
  42.  
  43.     q = subject; m = digest_pattern;
  44.     while ((c = *m++) && (*q++ | UNIFY) == c);
  45.     if (c == NUL) return 1;
  46.     }
  47.     return 0;
  48. }
  49.  
  50.  
  51. /*
  52.  * expect that f is positioned at header of an article
  53.  */
  54.  
  55. static int is_mmdf_folder = 0;
  56.  
  57. get_digest_article(f, hdrbuf)
  58. FILE *f;
  59. news_header_buffer hdrbuf;
  60. {
  61.     int cont;
  62.  
  63.     digest.dg_hpos = ftell(f);
  64.     TEST("GET DIGEST hp=%ld\n", digest.dg_hpos, 0);
  65.  
  66.     do {
  67.     if (!parse_digest_header(f, 0, hdrbuf)) return -1;
  68.     digest.dg_fpos = ftell(f);
  69.     TEST("END HEADER hp=%ld fp=%ld\n", digest.dg_hpos, digest.dg_fpos);
  70.     } while ((cont = skip_digest_body(f)) < 0);
  71.  
  72.     TEST("END BODY lp=%ld next=%ld\n", digest.dg_lpos, ftell(f));
  73.  
  74.     return cont;
  75. }
  76.  
  77. #define BACKUP_LINES     50    /* remember class + offset for parsed lines */
  78.  
  79. #define    LN_BLANK    0x01    /* blank line */
  80. #define    LN_DASHED    0x02    /* dash line */
  81. #define    LN_HEADER    0x04    /* (possible) header line */
  82. #define    LN_ASTERISK    0x08    /* asterisk line (near end) */
  83. #define    LN_END_OF    0x10    /* End of ... line */
  84. #define    LN_TEXT        0x20    /* unclassified line */
  85.  
  86.  
  87. /*
  88.  * skip until 'Subject: ' (or End of digest) line is found
  89.  * then backup till start of header
  90.  */
  91.  
  92. /*
  93.  * Tuning parameters:
  94.  *
  95.  *    MIN_HEADER_LINES:    number of known header lines that must
  96.  *                be found in a block to identify a new
  97.  *                header
  98.  *
  99.  *    MAX_BLANKS_DASH        max no of blanks on a 'dash line'
  100.  *
  101.  *    MIN_DASHES        min no of dashes on a 'dash line'
  102.  *
  103.  *    MAX_BLANKS_ASTERISKS    max no of blanks on an 'asterisk line'
  104.  *
  105.  *    MIN_ASTERISKS        min no of asterisks on an 'asterisk line'
  106.  *
  107.  *    MAX_BLANKS_END_OF    max no of blanks before "End of "
  108.  */
  109.  
  110. #define    MIN_HEADER_LINES    2
  111. #define    MAX_BLANKS_DASH        3
  112. #define    MIN_DASHES        16
  113. #define    MAX_BLANKS_ASTERISK    1
  114. #define    MIN_ASTERISKS        10
  115. #define    MAX_BLANKS_END_OF    1
  116.  
  117. skip_digest_body(f)
  118. register FILE *f;
  119. {
  120.     off_t  backup_p[BACKUP_LINES];
  121.     int       line_type[BACKUP_LINES];
  122.     register int backup_index, backup_count;
  123.     int    more_header_lines, end_or_asterisks, blanks;
  124.     char   line[1024];
  125.     register char *cp;
  126.     char **dg_hdr_field();
  127.  
  128. #define    decrease_index()    \
  129.     if (--backup_index < 0) backup_index = BACKUP_LINES - 1
  130.  
  131.     backup_index = -1;
  132.     backup_count = 0;
  133.     end_or_asterisks = 0;
  134.  
  135.     digest.dg_lines = 0;
  136.  
  137.  
  138.  next_line:
  139.     more_header_lines = 0;
  140.  
  141.  next_possible_header_line:
  142.     digest.dg_lines++;
  143.  
  144.     if (++backup_index == BACKUP_LINES) backup_index = 0;
  145.     if (backup_count < BACKUP_LINES) backup_count++;
  146.  
  147.     backup_p[backup_index] = ftell(f);
  148.     line_type[backup_index] = LN_TEXT;
  149.  
  150.     if (fgets(line, 1024, f) == NULL) {
  151.     TEST("end_of_file, bc=%d, lines=%d\n", backup_count, digest.dg_lines);
  152.  
  153.     if (is_mmdf_folder) {
  154.         digest.dg_lpos = backup_p[backup_index];
  155.         is_mmdf_folder = 0;
  156.         return 0;
  157.     }
  158.  
  159.     /* end of file => look for "****" or "End of" line */
  160.  
  161.     if (end_or_asterisks)
  162.         while (--backup_count >= 0) {
  163.         --digest.dg_lines;
  164.         decrease_index();
  165.         if (line_type[backup_index] & (LN_ASTERISK | LN_END_OF)) break;
  166.         }
  167.  
  168.     if (digest.dg_lines == 0) return 0;
  169.  
  170.     while (--backup_count >= 0) {
  171.         --digest.dg_lines;
  172.         digest.dg_lpos = backup_p[backup_index];
  173.         decrease_index();
  174.         if ((line_type[backup_index] &
  175.         (LN_ASTERISK | LN_END_OF | LN_BLANK | LN_DASHED)) == 0)
  176.         break;
  177.     }
  178.  
  179.     return 0;    /* no article follows */
  180.     }
  181.  
  182.     TEST("\n>>%-.50s ==>>", line, 0);
  183.  
  184.     if (line[0] == '\001' && strcmp(line, "\001\001\001\001\n") == 0) {
  185.     digest.dg_lpos = backup_p[backup_index];
  186.     if (!is_mmdf_folder) fseek(f, digest.dg_lpos, 0);
  187.     --digest.dg_lines;
  188.     is_mmdf_folder = 0;
  189.     return (digest.dg_lines <= 0) ? -1 : 1;
  190.     }
  191.  
  192.     if (is_mmdf_folder) goto next_line;
  193.  
  194.     for (cp = line; *cp && isascii(*cp) && isspace(*cp); cp++);
  195.  
  196.     if (*cp == NUL) {
  197.     TEST("BLANK", 0, 0);
  198.     line_type[backup_index] = LN_BLANK;
  199.     goto next_line;
  200.     }
  201.  
  202.     blanks = cp - line;
  203.  
  204.     if (*cp == '-') {
  205.     if (blanks > MAX_BLANKS_DASH) goto next_line;
  206.  
  207.     while (*cp == '-') cp++;
  208.     if (cp - line - blanks > MIN_DASHES) {
  209.         while (*cp && (*cp == '-' || (isascii(*cp) && isspace(*cp)))) cp++;
  210.         if (*cp == NUL) {
  211.         TEST("DASHED", 0, 0);
  212.  
  213.         line_type[backup_index] = LN_DASHED;
  214.         }
  215.  
  216.     }
  217.     goto next_line;
  218.     }
  219.  
  220.     if (*cp == '*') {
  221.     if (blanks > MAX_BLANKS_ASTERISK) goto next_line;
  222.  
  223.     while (*cp == '*') cp++;
  224.     if (cp - line - blanks > MIN_ASTERISKS) {
  225.         while (*cp && (*cp == '*' || (isascii(*cp) && isspace(*cp)))) cp++;
  226.         if (*cp == NUL) {
  227.         TEST("ASTERISK", 0, 0);
  228.         line_type[backup_index] = LN_ASTERISK;
  229.         end_or_asterisks++;
  230.         }
  231.     }
  232.     goto next_line;
  233.     }
  234.  
  235.     if (blanks <= MAX_BLANKS_END_OF &&
  236.     *cp == 'E' && strncmp(cp, "End of ", 7) == 0) {
  237.     TEST("END_OF_", 0, 0);
  238.     line_type[backup_index] = LN_END_OF;
  239.     end_or_asterisks++;
  240.     goto next_line;
  241.     }
  242.  
  243.     if (blanks == 0) {
  244.     if (dg_hdr_field(line, 0)) {
  245.         TEST("HEADER", 0, 0);
  246.  
  247.         line_type[backup_index] = LN_HEADER;
  248.         if (++more_header_lines < MIN_HEADER_LINES)
  249.         goto next_possible_header_line;
  250.  
  251.         /* found block with MIN_HEADER_LINES */
  252.  
  253.         /* search for beginning of header */
  254.  
  255.         TEST("\nSearch for start of header\n", 0, 0);
  256.  
  257.         for (;;) {
  258.         fseek(f, backup_p[backup_index], 0);
  259.         --digest.dg_lines;
  260.         if (--backup_count == 0) break;
  261.         decrease_index();
  262.         if ((line_type[backup_index] & (LN_HEADER | LN_TEXT)) == 0)
  263.             break;
  264.         }
  265.  
  266.         if (digest.dg_lines == 0) {
  267.         TEST("Skipped empty article\n", 0, 0);
  268.         return -1;
  269.         }
  270.  
  271.         for (;;) {
  272.         digest.dg_lpos = backup_p[backup_index];
  273.         if (--backup_count < 0) break;
  274.         decrease_index();
  275.         if ((line_type[backup_index] & (LN_BLANK | LN_DASHED)) == 0)
  276.             break;
  277.         --digest.dg_lines;
  278.         }
  279.  
  280.         return (digest.dg_lines == 0) ? -1 : 1;
  281.     }
  282.     goto next_possible_header_line;
  283.     }
  284.  
  285.     goto next_line;
  286. }
  287.  
  288.  
  289. parse_digest_header(f, all, hdrbuf)
  290. FILE *f;
  291. int all;
  292. news_header_buffer hdrbuf;
  293. {
  294.     extern char *parse_header(), **dg_hdr_field();
  295.  
  296.     digest.dg_date = digest.dg_from = digest.dg_subj = digest.dg_to = NULL;
  297.  
  298.     parse_header(f, dg_hdr_field, all, hdrbuf);
  299.  
  300.     return digest.dg_from || digest.dg_subj;
  301. }
  302.  
  303.  
  304. static char **dg_hdr_field(lp, all)
  305. register char *lp;
  306. int all;
  307. {
  308.  
  309. #define check(name, lgt, field) \
  310.     if (isascii(lp[lgt]) && isspace(lp[lgt]) && strncmp(name, lp, lgt) == 0) {\
  311.     TEST("MATCH: field ", 0, 0); \
  312.     return &digest.field; \
  313.     }
  314.  
  315.  
  316.     TEST("\nPARSE[%.20s] ==>> ", lp, 0);
  317.  
  318.     switch (*lp++) {
  319.  
  320.      case '\001':
  321.     if (!is_mmdf_folder && strncmp(lp, "\001\001\001\n", 4) == 0) {
  322.         is_mmdf_folder = 1;
  323.         digest.dg_hpos += 5;
  324.         return NULL;
  325.     }
  326.     break;
  327.  
  328.      case 'D':
  329.      case 'd':
  330.     check("ate:",    4, dg_date);
  331.     break;
  332.  
  333.      case 'F':
  334.      case 'f':
  335.     check("rom:",    4, dg_from);
  336.     break;
  337.  
  338.      case 'R':
  339.      case 'r':
  340.     if (!all) break;
  341.     check("e:",    2, dg_subj);
  342.     break;
  343.  
  344.      case 'S':
  345.      case 's':
  346.     check("ubject:", 7, dg_subj);
  347.     check("ubject",    6, dg_subj);
  348.     break;
  349.  
  350.      case 'T':
  351.      case 't':
  352.     check("itle:",    5, dg_subj);
  353.     if (!all) break;
  354.     check("o:",    2, dg_to);
  355.     break;
  356.     }
  357.  
  358. #undef check
  359.     TEST("NOT MATCHED ", 0, 0);
  360.  
  361.     return NULL;
  362. }
  363.