home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume36 / slurp / part01 / articles.c next >
Encoding:
C/C++ Source or Header  |  1993-03-12  |  9.1 KB  |  391 lines

  1. /*
  2.  * articles - handle retrieval and batching of articles
  3.  *
  4.  * Copyright (C) 1992/93 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.  * $Id: articles.c,v 1.5 1993/03/01 17:36:51 root Exp $
  15.  *
  16.  * $Log: articles.c,v $
  17.  * Revision 1.5  1993/03/01  17:36:51  root
  18.  * Removed stray text after an endif.
  19.  *
  20.  * Revision 1.4  1993/02/14  14:44:25  root
  21.  * Fixed problem with newline being added to article line buffer which
  22.  * could already be at its maximum length.
  23.  * Support for writing out batch files as well as piping batches to
  24.  * rnews.
  25.  * If BATCHSIZE is zero then keep pipe open to rnews indefinitely.
  26.  * If error occurs then submit batch and dump unretrieved ids.
  27.  *
  28.  * Revision 1.3  1992/12/15
  29.  * Minor tidy-ups, plus fixed flushing of tfp every time after it had
  30.  * been opened once.
  31.  *
  32.  * Revision 1.1  1992/12/04
  33.  * Print line before it is sent to server when debugging is on.
  34.  *
  35.  * Revision 1.0  1992/11/27
  36.  * Adapted from nntpxfer-e code.
  37.  * Pipe batches to rnews instead of creating in in.coming directory,
  38.  * so can be used with INN.
  39.  *
  40.  */
  41.  
  42. #include "slurp.h"
  43.  
  44.  
  45. static struct mnode *last_article = NULL; /* last article requested */
  46. static char artbuf [COPYSIZE];        /* temp storage for article in memory */
  47. static char *endart = artbuf;        /* points to just past end of article */
  48. static int incore = TRUE;            /* article in memory, not temp file */
  49. static FILE *tfp = NULL;            /* temporary file descriptor */
  50.  
  51. static FILE *batchfp = NULL;        /* file descriptor of rnews pipe */
  52. static size_t batchsize = 0;        /* size of current batch */
  53. static char batchname [PATH_MAX];    /* name of current batch */
  54.  
  55. static void new_batch ();
  56. static void read_article ();
  57. static void batch_article ();
  58. static void fetch_article ();
  59. static void get_article ();
  60. static void request_article (char *msgid);
  61. static void traverse_tree ();
  62.  
  63.  
  64. /*
  65.  * new_batch - Determines if there is enough room for the batch on the
  66.  * disk containing the news spool directories. If there is, then a pipe
  67.  * is opened to rnews and the batch variable initialised with the
  68.  * details.
  69.  */
  70.  
  71.     static void
  72. new_batch ()
  73.     {
  74.     /* Make sure there is enough room for batch */
  75. #ifdef MINFREE
  76.     if (!space (MINFREE))
  77.         {
  78.         log_msg ("new_batch: Not enough space for incoming batch");
  79.         if ((root != NULL) && (!no_time_flag) && (!no_id_load_flag))
  80.             set_ntime ();
  81.         exit (5);
  82.         }
  83. #endif
  84.  
  85. #ifdef RNEWS
  86.     /* Open a pipe to rnews for the batch */
  87.     if ((batchfp = popen (RNEWS, "w")) == NULL)
  88.         log_sys ("new_batch: Can't open pipe to %s", RNEWS);
  89. #else
  90.     /* Open a file in incoming news directory with temporary name */
  91.     (void) strcpy (batchname, BATCHNAME);
  92.     (void) mktemp (batchname);
  93.     if ((batchfp = fopen (batchname, "w")) == NULL)
  94.         log_sys ("new_batch: Can't open file %s", batchname);
  95. #endif
  96.     }
  97.  
  98.  
  99. /*
  100.  * read_article - Read an article into artbuf or, if too large, into a
  101.  * temporary file from the currently open NNTP server socket, reading up
  102.  * to the end-of-article marker, a '.' on a single line. If it is stored
  103.  * in memory, then incore will be TRUE, otherwise it will be FALSE and the
  104.  * temporary file name will be stored in tempfile.
  105.  */
  106.  
  107.     static void
  108. read_article ()
  109.     {
  110.     char *realline;
  111.     char line [NNTP_STRLEN];
  112.     int lines = 0;
  113.     int len;
  114.  
  115.     incore = TRUE;
  116.     endart = artbuf;
  117.  
  118.     /* Read in the article */
  119.     for (;;)
  120.         {
  121.         get_server (line, sizeof (line));
  122.  
  123.         /* Dot on its own means article end reached */
  124.         if (!strcmp (line, "."))
  125.             break;
  126.  
  127.         /* remove hidden dot if present */
  128.         realline = (line [0] == '.' ? line + 1 : line);
  129.  
  130.         /* Article is currently stored in memory */
  131.         if (incore)
  132.             {
  133.             /* If no room in artbuf, open tempfile and copy article there */
  134.             len = strlen (realline);
  135.             if ((endart + len + 2 ) > (artbuf + sizeof (artbuf)))
  136.                 {
  137.                 if ((tfp = tmpfile ()) == NULL)
  138.                     log_sys ("read_article: Can't create temporary file");
  139.                 (void) fwrite (artbuf, 1, endart - artbuf, tfp);
  140.                 if (ferror (tfp))
  141.                     log_sys ("read_article: Can't write to tempfile");
  142.                 (void) fputs (realline, tfp);
  143.                 (void) putc ('\n', tfp);
  144.                 if (ferror (tfp))
  145.                     log_sys ("read_article: Can't write to tempfile");
  146.                 incore = FALSE;
  147.                 }
  148.             else
  149.                 {
  150.                 /* If fits, append realline to artbuf at endart */
  151.                 (void) strcpy (endart, realline);
  152.                 endart += len;
  153.                 *endart++ = '\n';
  154.                 *endart = '\0';
  155.                 }
  156.             }
  157.  
  158.         /* Already writing article to temp file */
  159.         else
  160.             {
  161.             (void) fputs (realline, tfp);
  162.             (void) putc ('\n', tfp);
  163.             if (ferror (tfp))
  164.                 log_sys ("read_article: Can't write to tempfile");
  165.             }
  166.  
  167.         lines++;
  168.         }
  169.  
  170.     /* Article successfully read in */
  171.     if (debug_flag)
  172.         (void) fprintf (stderr, "-> %d lines\n", lines);
  173.     }
  174.  
  175.  
  176. /* batch_article - Append "#! rnews <count>" and the article from artbuf
  177.  * or temporary file to the batch file.
  178.  */
  179.  
  180.     static void
  181. batch_article ()
  182.     {
  183.     size_t bytes = 0;
  184.     size_t size = 0;
  185.  
  186.     /* Find article size */
  187.     if (incore)
  188.         size = endart - artbuf;
  189.     else
  190.         size = ftell (tfp);
  191.  
  192.     totalsize += size;
  193.     batchsize += size;
  194.  
  195.     /* Print the article header */
  196.     (void) fprintf (batchfp, "#! rnews %ld %s\n", (long) size, hostname);
  197.  
  198.     /* Copy the article to the batch file */
  199.     if (incore)
  200.         {
  201.         (void) fwrite (artbuf, 1, size, batchfp);
  202.         if (ferror (batchfp))
  203.             log_sys ("batch_article: Can't write to batch");
  204.         }
  205.     else
  206.         {
  207.         rewind (tfp);
  208.         while ((bytes = fread (artbuf, 1, sizeof (artbuf), tfp)) > 0)
  209.             {
  210.             (void) fwrite (artbuf, 1, bytes, batchfp);
  211.             if (ferror (batchfp))
  212.                 log_sys ("batch_article: Can't write to batch");
  213.             }
  214.         (void) fclose (tfp);
  215.  
  216.         }
  217.     }
  218.  
  219.  
  220. /*
  221.  * fetch_article - Retrieve an article from the currently open NNTP
  222.  * server socket which has already been requested. The article is written
  223.  * to the end of the current batch. If there is not already a batch
  224.  * then a new pipe to rnews for the batch will be opened. If the current
  225.  * batch is too large or has too many articles then the pipe will be
  226.  * closed so that the batch may be submitted to the news system.
  227.  */
  228.  
  229.     static void
  230. fetch_article ()
  231.     {
  232.     /* Open a new batch if required */
  233.     if (batchfp == NULL)
  234.         new_batch ();
  235.  
  236.     /* Read in article */
  237.     read_article ();
  238.  
  239.     /* Add it to the batch */
  240.     batch_article ();
  241.  
  242.     /* Submit batch if ready */
  243.     if ((batchsize > BATCHSIZEMAX) && (BATCHSIZEMAX != 0))
  244.         enqueue_batch ();
  245.     }
  246.  
  247.  
  248. /*
  249.  * get_article
  250.  */
  251.  
  252.     static void
  253. get_article ()
  254.     {
  255.     char status [NNTP_STRLEN];
  256.  
  257.     /* Read status line from server */
  258.     get_server (status, sizeof (status));
  259.     if (debug_flag)
  260.         (void) fprintf (stderr, "-> %s\n", status);
  261.  
  262.     switch (atoi (status))
  263.         {
  264.         /* If missing, then add to missing list */
  265.         case ERR_NOART:
  266.             misart++;
  267.             newart--;
  268.             return;
  269.  
  270.         /* If present, then fetch and add to batch */
  271.         case OK_ARTICLE:
  272.             fetch_article ();
  273.             break;
  274.  
  275.         /* Otherwise must be a protocol error */
  276.         default:
  277.             log_msg ("get_article: NNTP protocol error: got '%s'", status);
  278.             if ((root != NULL) && (!no_time_flag) && (!no_id_load_flag))
  279.                 set_ntime ();
  280.             exit (4);
  281.         }
  282.     }
  283.  
  284.  
  285. /*
  286.  * request_article - Request an article with specified id from the server
  287.  */
  288.  
  289.     static void
  290. request_article (char *msgid)
  291.     {
  292.     char request [NNTP_STRLEN];
  293.  
  294.     (void) sprintf (request, "ARTICLE %s", msgid);
  295.     if (debug_flag)
  296.         (void) fprintf (stderr, "<- %s\n", request);
  297.     put_server (request);
  298.     }
  299.  
  300.  
  301. /*
  302.  * traverse_tree - Traverse the tree requesting and getting each article
  303.  */
  304.  
  305.     static void
  306. traverse_tree (struct mnode *p)
  307.     {
  308.     if (p != NULL)    
  309.         {
  310.         traverse_tree (p->left);
  311.         request_article (p->msgid);
  312. #ifdef SPEEDUP
  313.         if (last_article != NULL)
  314.             {
  315.             get_article ();
  316.             last_article->used = TRUE;
  317.             }
  318.         last_article = p;
  319. #else
  320.         get_article ();
  321.         p->used = TRUE;
  322. #endif /* SPEEDUP */
  323.         traverse_tree (p->right);
  324.         }
  325.     }
  326.  
  327.  
  328. /*
  329.  * get_articles - Get the articles from the server whose message ids
  330.  * were previously collected with do_newnews.
  331.  */
  332.  
  333.     void
  334. get_articles ()
  335.     {
  336.     traverse_tree (root);
  337. #ifdef SPEEDUP
  338.     get_article ();
  339.     last_article->used = TRUE;
  340. #endif
  341.     }
  342.  
  343.  
  344. /*
  345.  * enqueue_batch - Submit the batch to the new system by closing the
  346.  * currently open pipe to rnews or renaming the temporary file in the
  347.  * incoming news directory so it can be seen by the news system.
  348.  */
  349.  
  350.     void
  351. enqueue_batch ()
  352.     {
  353. #ifndef RNEWS
  354.     char permname [PATH_MAX];
  355.     time_t now;
  356. #endif
  357.  
  358.     /* Return if there is no currently open batch */
  359.     if (batchfp == NULL)
  360.         return;
  361.  
  362. #ifdef RNEWS
  363.     /* Close the pipe to rnews */
  364.     if (pclose (batchfp))
  365.         log_sys ("enqueue_batch: Can't close pipe to %s", RNEWS);
  366. #else
  367.     /* Close the temporary file */
  368.     if (fclose (batchfp))
  369.         log_sys ("enqueue_batch: Can't close %s", batchname);
  370.  
  371.     /* Rename it so it can be seen by news */
  372.     for (;;)
  373.         {
  374.         (void) sprintf (permname, "%ld.t", (long) time (&now));
  375.         if (link (batchname, permname) == 0)
  376.             break;
  377.         if (errno != EEXIST)
  378.             log_sys ("enqueue_batch: Error linking %s to %s", batchname, permname);
  379.         (void) sleep (2);
  380.         }
  381.     if (unlink (batchname))
  382.             log_sys ("enqueue_batch: Error unlinking %s", batchname);
  383. #endif /* RNEWS */
  384.  
  385.     /* Reset the batch descriptor for a new batch */
  386.     batchfp = NULL;
  387.     batchsize = 0;
  388.     }
  389.  
  390. /* END-OF-FILE */
  391.