home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / s / slurp103.zip / ARTICLES.C next >
C/C++ Source or Header  |  1992-12-20  |  8KB  |  338 lines

  1. /*
  2.  * articles - handle retrieval and batching of articles
  3.  *
  4.  * Copyright (C) 1992 Stephen Hebditch. All rights reserved.
  5.  * TQM Communications, BCM Box 225, London, WC1N 3XX.
  6.  * steveh@orbital.demon.co.uk  +44 836 825962
  7.  *
  8.  * See README for more information and disclaimers
  9.  *
  10.  * This file provides a set of routines to retrieve articles from the
  11.  * remote NNTP server and add to a batch of articles being piped to
  12.  * the local news system via rnews.
  13.  *
  14.  * 1.00  31 Sep 92  SH  Adapted from nntpxfer-e code.
  15.  * 1.00  27 Nov 92  SH  Pipe batches to rnews instead of creating in
  16.  *                      the in.coming directory, so can be used with INN.
  17.  * 1.01   4 Dec 92  SH  Print line before it is sent to server when
  18.  *                      debugging is on.
  19.  * 1.03  15 Dec 92  SH  Minor tidy-ups, plus fixed flushing of tfp
  20.  *                      whenever it was once opened.
  21.  *
  22.  */
  23.  
  24. #include "slurp.h"
  25.  
  26.  
  27. static int first_article = TRUE;/* first article to be requested */
  28. static char artbuf [COPYSIZE];    /* temp storage for article in memory */
  29. static char *endart = artbuf;    /* points to just past end of article */
  30. static int incore = TRUE;        /* article in memory, not temp file */
  31. static FILE *tfp = NULL;        /* temporary file descriptor */
  32.  
  33. static struct batch_file
  34.     {
  35.     FILE *file;                    /* file descriptor of rnews pipe */
  36.     size_t size;                /* size of current batch */
  37.     int arts;                    /* number of articles in current batch */
  38.     } batch = { NULL, 0, 0 };
  39.  
  40.  
  41. static void new_batch ();
  42. static void read_article ();
  43. static void batch_article ();
  44. static void fetch_article ();
  45. static void get_article ();
  46. static void request_article (char *msgid);
  47. static void traverse_tree ();
  48.  
  49.  
  50. /*
  51.  * new_batch - Determines if there is enough room for the batch on the
  52.  * disk containing the news spool directories. If there is, then a pipe
  53.  * is opened to rnews and the batch variable initialised with the
  54.  * details.
  55.  */
  56.  
  57.     static void
  58. new_batch ()
  59.     {
  60.     /* Make sure there is enough room for batch */
  61. #ifdef MINFREE
  62.     if (!space (MINFREE))
  63.         {
  64.         log_msg ("new_batch: Not enough space for incoming batch");
  65.         exit (5);
  66.         }
  67. #endif MINFREE
  68.  
  69.  
  70.     /* Open a pipe to rnews for the batch */
  71.     if ((batch.file = popen (RNEWS, "w")) == NULL)
  72.         log_sys ("new_batch: Can't open pipe to %s", RNEWS);
  73.     }
  74.  
  75.  
  76. /*
  77.  * read_article - Read an article into artbuf or, if too large, into a
  78.  * temporary file from the currently open NNTP server socket, reading up
  79.  * to the end-of-article marker, a '.' on a single line. If it is stored
  80.  * in memory, then incore will be TRUE, otherwise it will be FALSE and the
  81.  * temporary file name will be stored in tempfile.
  82.  */
  83.  
  84.     static void
  85. read_article ()
  86.     {
  87.     char *realline;
  88.     char line [NNTP_STRLEN];
  89.     int lines = 0;
  90.     int len;
  91.  
  92.     incore = TRUE;
  93.     endart = artbuf;
  94.  
  95.     /* Read in the article */
  96.     for (;;)
  97.         {
  98.         if (get_server (line, sizeof (line)))
  99.             exit (1);
  100.  
  101.         /* Dot on its own means article end reached */
  102.         if (!strcmp (line, "."))
  103.             break;
  104.  
  105.         /* remove hidden dot if present and add a newline */
  106.         realline = (line [0] == '.' ? line + 1 : line);
  107.         (void) strcat (realline, "\n");
  108.  
  109.         /* Article is currently stored in memory */
  110.         if (incore)
  111.             {
  112.             /* If no room in artbuf, open tempfile and copy article there */
  113.             len = strlen (realline);
  114.             if ((endart + len + 1) > (artbuf + sizeof (artbuf)))
  115.                 {
  116.                 if ((tfp = tmpfile ()) == NULL)
  117.                     log_sys ("read_article: Can't create temporary file");
  118.                 (void) fwrite (artbuf, 1, endart - artbuf, tfp);
  119.                 if (ferror (tfp))
  120.                     log_sys ("read_article: Can't write to tempfile");
  121.                 (void) fputs (realline, tfp);
  122.                 if (ferror (tfp))
  123.                     log_sys ("read_article: Can't write to tempfile");
  124.                 incore = FALSE;
  125.                 }
  126.             else
  127.                 {
  128.                 /* If fits, append realline to artbuf at endart */
  129.                 (void) strcpy (endart, realline);
  130.                 endart += len;
  131.                 }
  132.             }
  133.  
  134.         /* Already writing article to temp file */
  135.         else
  136.             {
  137.             (void) fputs (realline, tfp);
  138.             if (ferror (tfp))
  139.                 log_sys ("read_article: Can't write to tempfile");
  140.             }
  141.  
  142.         lines++;
  143.         }
  144.  
  145.     /* Article successfully read in */
  146.     if (debug_flag)
  147.         (void) fprintf (stderr, "-> %d lines\n", lines);
  148.     }
  149.  
  150.  
  151. /* batch_article - Append "#! rnews <count>" and the article from artbuf
  152.  * or temporary file to the batch file.
  153.  */
  154.  
  155.     static void
  156. batch_article ()
  157.     {
  158.     size_t bytes = 0;
  159.     size_t size = 0;
  160.  
  161.     /* Find article size */
  162.     if (incore)
  163.         size = endart - artbuf;
  164.     else
  165.         size = ftell (tfp);
  166.  
  167.     totalsize += size;
  168.     batch.size += size;
  169.     batch.arts++;
  170.  
  171.     /* Print the article header */
  172.     (void) fprintf (batch.file, "#! rnews %ld %s\n", size, hostname);
  173.  
  174.     /* Copy the article to the batch file */
  175.     if (incore)
  176.         {
  177.         (void) fwrite (artbuf, 1, size, batch.file);
  178.         if (ferror (batch.file))
  179.             log_sys ("batch_article: Can't write to %s", RNEWS);
  180.         }
  181.     else
  182.         {
  183.         rewind (tfp);
  184.         while ((bytes = fread (artbuf, 1, sizeof (artbuf), tfp)) > 0)
  185.             {
  186.             (void) fwrite (artbuf, 1, bytes, batch.file);
  187.             if (ferror (batch.file))
  188.                 log_sys ("batch_article: Can't write to %s", RNEWS);
  189.             }
  190.         (void) fclose (tfp);
  191.  
  192.         }
  193.     }
  194.  
  195.  
  196. /*
  197.  * fetch_article - Retrieve an article from the currently open NNTP
  198.  * server socket which has already been requested. The article is written
  199.  * to the end of the current batch. If there is not already a batch
  200.  * then a new pipe to rnews for the batch will be opened. If the current
  201.  * batch is too large or has too many articles then the pipe will be
  202.  * closed so that the batch may be submitted to the news system.
  203.  */
  204.  
  205.     static void
  206. fetch_article ()
  207.     {
  208.     /* Open a new batch if required */
  209.     if (batch.file == NULL)
  210.         new_batch ();
  211.  
  212.     /* Read in article */
  213.     read_article ();
  214.  
  215.     /* Add it to the batch */
  216.     batch_article ();
  217.  
  218.     /* Submit batch if ready */
  219.     if ((batch.arts >= BATCHARTSMAX) || (batch.size > BATCHSIZEMAX))
  220.         enqueue_batch ();
  221.     }
  222.  
  223.  
  224. /*
  225.  * get_article
  226.  */
  227.  
  228.     static void
  229. get_article ()
  230.     {
  231.     char status [NNTP_STRLEN];
  232.  
  233.     /* Read status line from server */
  234.     if (get_server (status, sizeof (status)))
  235.         exit (1);
  236.     if (debug_flag)
  237.         (void) fprintf (stderr, "-> %s\n", status);
  238.  
  239.     switch (atoi (status))
  240.         {
  241.         /* If missing, then add to missing list */
  242.         case ERR_NOART:
  243.             misart++;
  244.             newart--;
  245.             return;
  246.  
  247.         /* If present, then fetch and add to batch */
  248.         case OK_ARTICLE:
  249.             fetch_article ();
  250.             break;
  251.  
  252.         /* Otherwise must be a protocol error */
  253.         default:
  254.             log_msg ("get_article: NNTP protocol error: got '%s'", status);
  255.             exit (4);
  256.         }
  257.     }
  258.  
  259.  
  260. /*
  261.  * request_article - Request an article with specified id from the server
  262.  */
  263.  
  264.     static void
  265. request_article (char *msgid)
  266.     {
  267.     char request [NNTP_STRLEN];
  268.  
  269.     (void) sprintf (request, "ARTICLE %s", msgid);
  270.     if (debug_flag)
  271.         (void) fprintf (stderr, "<- %s\n", request);
  272.     put_server (request);
  273.     }
  274.  
  275.  
  276. /*
  277.  * traverse_tree - Traverse the tree requesting and getting each article
  278.  */
  279.  
  280.     static void
  281. traverse_tree (struct mnode *p)
  282.     {
  283.     if (p != NULL)    
  284.         {
  285.         traverse_tree (p->left);
  286.         request_article (p->msgid);
  287. #ifdef SPEEDUP
  288.         if (!first_article)
  289. #endif
  290.             get_article ();
  291. #ifdef SPEEDUP
  292.         else
  293.             first_article = FALSE;
  294. #endif
  295.         traverse_tree (p->right);
  296.         }
  297.     }
  298.  
  299.  
  300. /*
  301.  * get_articles - Get the articles from the server whose message ids
  302.  * were previously collected with do_newnews.
  303.  */
  304.  
  305.     void
  306. get_articles ()
  307.     {
  308.     traverse_tree (root);
  309. #ifdef SPEEDUP
  310.     get_article ();
  311. #endif
  312.     }
  313.  
  314.  
  315. /*
  316.  * enqueue_batch - Close the currently open pipe to rnews (if it is open)
  317.  * thereby submitting the batch to the news system.
  318.  */
  319.  
  320.     void
  321. enqueue_batch ()
  322.     {
  323.     /* Return if there is no currently open batch */
  324.     if (batch.file == NULL)
  325.         return;
  326.  
  327.     /* Close the batch file */
  328.     if (pclose (batch.file))
  329.         log_sys ("enqueue_batch: Can't close pipe to %s", RNEWS);
  330.  
  331.     /* Reset the batch descriptor for a new batch */
  332.     batch.file = NULL;
  333.     batch.size = 0;
  334.     batch.arts = 0;
  335.     }
  336.  
  337. /* END-OF-FILE */
  338.