home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / news.c < prev    next >
C/C++ Source or Header  |  1996-08-11  |  8KB  |  408 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Article header parsing.
  5.  */
  6.  
  7. #include "config.h"
  8. #include "news.h"
  9.  
  10.  
  11. /* news.c */
  12.  
  13. static char **art_hdr_field __APROTO((register char *lp, int all));
  14.  
  15.  
  16. export int retry_on_error = 0;
  17.  
  18. char *parse_header(f, hdr_field, modes, hdrbuf)
  19. FILE             *f;
  20. char             **(*hdr_field)();
  21. int             modes;
  22. news_header_buffer    hdrbuf;
  23. {
  24.     register char *bp, *cp, **fptr;
  25.     int siz, all, date_only;
  26.     off_t pos;
  27.  
  28.     pos = ftell(f);
  29.  
  30. /* read first NEWS_HEADER_BUFFER bytes (should be more than enough) */
  31.  
  32.     all     = modes & GET_ALL_FIELDS;
  33.     date_only     = modes & GET_DATE_ONLY;
  34.  
  35.     siz = fread(hdrbuf, sizeof(char), NEWS_HEADER_BUFFER, f);
  36.     if (siz <= 0) {
  37.     hdrbuf[0] = NUL;
  38.     return hdrbuf;
  39.     }
  40.  
  41.     bp = hdrbuf;
  42.     bp[siz-1] = NUL;
  43.  
  44.     /* decode subarticle header */
  45.     while (*bp) {
  46.  
  47.     if (*bp == NL) {    /* empty line following header */
  48.         ++bp;
  49.         fseek(f, pos + (bp - hdrbuf), 0);
  50.         return bp;
  51.     }
  52.  
  53.     if (bp[0] == SP && bp[1] == SP) { /* An ugly hack so that NN can read */
  54.         bp += 2;              /* it's own FAQ... :-) (sorry Bill) */
  55.         continue;
  56.     }
  57.  
  58.     if (date_only && *bp != 'D')
  59.         fptr = NULL;
  60.     else
  61.         if ((fptr = (*hdr_field)(bp, all))) {
  62.         while (*bp && *bp != ':' && isascii(*bp) && !isspace(*bp))
  63.             bp++;
  64.         if (*bp) bp++;
  65.         while (*bp && isascii(*bp) && isspace(*bp) && *bp != NL) bp++;
  66.         *fptr = bp;
  67.         }
  68. #ifdef NO_HEADER_SEPARATION_HACK
  69.         else {
  70.         for (cp = bp; *cp && *cp != ':'; cp++) {
  71.             if (!isascii(*cp)) break;
  72.             if (*cp == '_' || *cp == '-') continue;
  73.             if (isalnum(*cp)) continue;
  74.             break;
  75.         }
  76.         if (*cp != ':') {
  77.             *bp = NL;
  78.             pos--;
  79.             continue;
  80.         }
  81.         }
  82. #endif
  83.  
  84.     while (*bp && *bp != NL) bp++;
  85.  
  86.     /* Assume that continued lines are never empty! */
  87.     if (fptr && bp == *fptr) *fptr = NULL;
  88.  
  89.     while (*bp) {        /* look for continued lines */
  90.         cp = bp + 1;
  91.  
  92.         if (! (*cp && isascii(*cp) && isspace(*cp) && *cp != NL)) {
  93.         /* next line is empty or not indented */
  94.         *bp++ = NUL;
  95.         break;
  96.         }
  97.  
  98.         *bp = SP;        /* substitute NL with SPACE */
  99.         bp = cp;
  100.         while (*bp && *bp != NL) bp++;
  101.     }
  102.     }
  103.  
  104.     return bp;
  105. }
  106.  
  107. static char **art_hdr_field(lp, all)
  108. register char *lp;
  109. int all;
  110. {
  111.  
  112. #define check(name, lgt, field) \
  113.     if (isascii(lp[lgt]) && isspace(lp[lgt]) && strncmp(name, lp, lgt) == 0)\
  114.     return &news.field
  115.  
  116.     switch (*lp++) {
  117.  
  118.      case 'A':
  119.      case 'a':
  120.     if (!all) break;
  121.     check("pproved:",     8, ng_appr);
  122.     break;
  123.  
  124.      case 'B':
  125.      case 'b':
  126.     check("ack-References:", 15, ng_bref);
  127.     break;
  128.  
  129.      case 'C':
  130.      case 'c':
  131.     check("ontrol:",     7, ng_control);
  132.     check("omment-To:",    10, ng_comment);
  133.     break;
  134.  
  135.      case 'D':
  136.      case 'd':
  137.     check("ate:",          4, ng_date);
  138.     if (!all) break;
  139.     check("ate-Received:",    13, ng_rdate);
  140.     check("istribution:",     12, ng_dist);
  141.     break;
  142.  
  143.      case 'F':
  144.      case 'f':
  145.     check("rom:",         4, ng_from);
  146.     if (!all) break;
  147.     check("ollowup-To:",    11, ng_follow);
  148.     check("ollowup-to:",    11, ng_follow);
  149.     break;
  150.  
  151.      case 'K':
  152.      case 'k':
  153.     if (!all) break;
  154.     check("eywords:",     8, ng_keyw);
  155.     break;
  156.  
  157.      case 'L':
  158.      case 'l':
  159.     check("ines:",          5, ng_xlines);
  160.     break;
  161.  
  162.      case 'M':
  163.      case 'm':
  164.     if (!all) break;
  165.     if (strncmp(lp, "essage-", 7)) break;
  166.     lp += 7;
  167.     check("ID:",    3, ng_ident);
  168.     check("Id:",    3, ng_ident);
  169.     check("id:",    3, ng_ident);
  170.     break;
  171.  
  172.      case 'N':
  173.      case 'n':
  174.     check("ewsgroups:",    10, ng_groups);
  175.     break;
  176.  
  177.      case 'O':
  178.      case 'o':
  179.     if (!all) break;
  180.     check("rganization:",    12, ng_org);
  181.     check("rganisation:",    12, ng_org);
  182.     check("riginator:",    10, ng_origr);
  183.     break;
  184.  
  185.      case 'P':
  186.      case 'p':
  187.     if (!all) break;
  188.     check("ath:",         4, ng_path);
  189.     break;
  190.  
  191.      case 'R':
  192.      case 'r':
  193.     check("eferences:",    10, ng_ref);
  194.     check("eply-To:",     8, ng_reply);
  195.     check("eply-to:",     8, ng_reply);
  196.     break;
  197.  
  198.      case 'S':
  199.      case 's':
  200.     check("ubject:",     7, ng_subj);
  201.     check("ender:",         6, ng_sender);
  202.     if (!all) break;
  203.     check("ummary:",     7, ng_summ);
  204.     break;
  205.  
  206.      case 'T':
  207.      case 't':
  208.     check("itle:",          5, ng_subj);
  209.     break;
  210.  
  211.      case 'X':
  212.      case 'x':
  213.     check("ref:",         4, ng_xref);
  214.     break;
  215.     }
  216.  
  217.     return NULL;
  218.  
  219. #undef check
  220. }
  221.  
  222. int
  223. is_header_line(line)
  224. char *line;
  225. {
  226.     return art_hdr_field(line, 0) != (char **)NULL;
  227. }
  228.  
  229.  
  230. FILE *open_news_article(art, modes, buffer1, buffer2)
  231. article_header         *art;
  232. int             modes;
  233. news_header_buffer    buffer1, buffer2;
  234. {
  235.   
  236.     char *digest_buffer;
  237.     int c, retry;
  238.     FILE *f;
  239.     struct stat statb;
  240. #ifndef DONT_COUNT_LINES
  241.     off_t digest_artlen;
  242. #endif    /* DONT_COUNT_LINES */
  243. #ifdef NNTP
  244.     int lazy;
  245.     off_t fpos;
  246.     FILE *nntp_get_article();
  247. #endif /* NNTP */
  248.  
  249. #ifndef DONT_COUNT_LINES
  250.     digest_artlen = 0;
  251. #endif  /* DONT_COUNT_LINES */
  252.     if (art->flag & A_FOLDER) {
  253.     f = open_file(group_path_name, OPEN_READ);
  254.     if (f == NULL) return NULL;
  255.     fseek(f, art->hpos, 0);
  256. #ifndef DONT_COUNT_LINES
  257.     digest_artlen = art->lpos - art->fpos;
  258. #endif  /* DONT_COUNT_LINES */
  259.     }
  260. #ifdef NNTP
  261.     else if (use_nntp) {
  262.     lazy = (current_group->master_flag & M_ALWAYS_DIGEST) == 0
  263.         && (modes & LAZY_BODY) ? 1 : 0;
  264.     f = nntp_get_article(art->a_number, lazy);
  265.     if (f == NULL) return NULL;
  266.     }
  267. #endif /* NNTP */
  268.     else {
  269.     sprintf(group_file_name, "%d", art->a_number);
  270.  
  271.     retry = retry_on_error;
  272.     while ((f = open_file(group_path_name, OPEN_READ)) == NULL)
  273.         if (--retry < 0) return NULL;
  274.  
  275.     /* necessary because empty files wreak havoc */
  276.     if (fstat(fileno(f), &statb) < 0 ||
  277. #ifdef NOV
  278.         (art->lpos = statb.st_size, statb.st_size <= (off_t)0)) {
  279. #else
  280.         statb.st_size < art->lpos || statb.st_size <= (off_t)0) {
  281. #endif /* NOV */
  282.         fclose(f);
  283.         return who_am_i == I_AM_MASTER ? (FILE *)1 : NULL;
  284.     }
  285.     }
  286.  
  287.     digest_buffer = buffer1;
  288.  
  289.     if (modes & FILL_NEWS_HEADER) {
  290.  
  291.     news.ng_from     = NULL;
  292.     news.ng_reply     = NULL;
  293.     news.ng_name     = NULL;
  294.     news.ng_subj     = NULL;
  295.     news.ng_groups     = NULL;
  296.     news.ng_ref     = NULL;
  297.     news.ng_bref     = NULL;
  298.     news.ng_sender    = NULL;
  299.  
  300.     news.ng_xlines     = NULL;
  301.     news.ng_xref     = NULL;
  302.  
  303.     if (modes & GET_ALL_FIELDS) {
  304.         news.ng_path     = NULL;
  305.         news.ng_reply     = NULL;
  306.         news.ng_ident     = NULL;
  307.         news.ng_follow     = NULL;
  308.         news.ng_keyw     = NULL;
  309.         news.ng_dist     = NULL;
  310.         news.ng_org     = NULL;
  311.         news.ng_appr     = NULL;
  312.         news.ng_summ    = NULL;
  313.         news.ng_control    = NULL;
  314.         news.ng_date    = NULL;
  315.         news.ng_rdate    = NULL;
  316.         news.ng_comment    = NULL;
  317.         news.ng_origr    = NULL;
  318.     }
  319.  
  320.     if (modes & GET_DATE_ONLY)
  321.         news.ng_date    = NULL;
  322.  
  323.     (void) parse_header(f, art_hdr_field, modes, buffer1);
  324.  
  325.     if (news.ng_from == NULL) news.ng_from = news.ng_sender;
  326.  
  327. #ifdef NOV
  328.     /* fill in article positions..  new style.. */
  329.     if ((art->flag & (A_FOLDER | A_DIGEST)) == 0) {
  330.         setpos(art, f);
  331.         news.ng_fpos = art->fpos;
  332.     }
  333. #else /* NOV */
  334.     if (modes & FILL_OFFSETS) /* used only by old DB code */
  335.         art->fpos = news.ng_fpos = ftell(f);
  336.  
  337. #endif /* NOV */
  338.  
  339.     if (news.ng_xlines)
  340.         news.ng_lines = atoi(news.ng_xlines);
  341.     else {
  342. #ifndef DONT_COUNT_LINES
  343. #ifdef NNTP
  344.         if (use_nntp && lazy && !(art->flag & (A_DIGEST | A_FOLDER))) {
  345.         fpos = ftell(f);
  346.         fclose(f);
  347.         f = nntp_get_article(art->a_number, 2);
  348.         if (f == NULL) return NULL;
  349.         lazy = 0;
  350.         fseek(f, fpos, 0);
  351.         }
  352. #endif /* NNTP */
  353.         news.ng_lines = 0;
  354.         while ((c = getc(f)) != EOF) {
  355.         if (c == '\n')
  356.             news.ng_lines++;
  357.         if (digest_artlen && --digest_artlen == 0)
  358.             break;
  359.         }
  360. #else /* DONT_COUNT_LINES */
  361.         news.ng_lines = -1;
  362. #endif /* DONT_COUNT_LINES */
  363.     }
  364.  
  365.     if (modes & FILL_OFFSETS) {
  366.         fseek(f, (off_t)0, 2);
  367.         news.ng_lpos = ftell(f);
  368.     }
  369. #ifdef NNTP
  370.     else if (use_nntp && (art->flag & (A_DIGEST | A_FOLDER)) == 0) {
  371.         fseek(f, (off_t)0, 2);
  372.         art->lpos = ftell(f);
  373.     }
  374. #endif
  375.  
  376.     news.ng_flag = 0;
  377.  
  378.     if (news.ng_appr) news.ng_flag |= N_MODERATED;
  379.  
  380.     if (modes & DIGEST_CHECK && is_digest(news.ng_subj))
  381.         news.ng_flag |= N_DIGEST;
  382.  
  383. #ifdef NNTP
  384.     if (use_nntp && lazy && news.ng_flag & N_DIGEST) {
  385.         fclose(f);
  386.         f = nntp_get_article(art->a_number, 2);
  387.         if (f == NULL) return NULL;
  388.     }
  389. #endif
  390.     digest_buffer = buffer2;
  391.     }
  392. #ifdef NNTP
  393.     else if (use_nntp && (art->flag & (A_DIGEST | A_FOLDER)) == 0) {
  394.     fseek(f, (off_t)0, 2);
  395.     art->lpos = ftell(f);
  396.     }
  397. #endif
  398.  
  399.     if (modes & FILL_DIGEST_HEADER) {
  400.     fseek(f, art->hpos, 0);
  401.     parse_digest_header(f, modes & GET_ALL_FIELDS, digest_buffer);
  402.     }
  403.  
  404.     fseek(f, (modes & SKIP_HEADER) ? art->fpos : art->hpos, 0);
  405.  
  406.     return f;
  407. }
  408.