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

  1. /*
  2.  * slurp - a passive nntp news client
  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 is the main routine for slurp together with the routines to
  11.  * handle the configuration files and command line arguments.
  12.  *
  13.  * 1.00   7 Aug 92  SH  Initial coding.
  14.  * 1.01   4 Dec 92  SH  Fixed null dereferencing of nn_distributions.
  15.  * 1.01   6 Dec 92  SH  Made no_time_flag global.
  16.  * 1.02   7 Dec 92  SH  Corrected test for 4.2/4.3 syslog open.
  17.  * 1.03  15 Dec 92  SH  Open syslog *before* we start doing things that
  18.  *                      might write to it. Informational messages logged
  19.  *                      as LOG_INFO.
  20.  *                      Assorted minor tidy-ups.
  21.  *
  22.  */
  23.  
  24. #include "slurp.h"
  25. #include <sys/stat.h>
  26.  
  27. char *hostname = NULL;
  28. char *pname;
  29.  
  30. int  debug_flag = 0;
  31. int  no_time_flag = 0;
  32. static int local_time_flag = 0;
  33.  
  34. int  dupart = 0;
  35. int  misart = 0;
  36. int  newart = 0;
  37. long totalsize = 0;
  38.  
  39. char *nn_newsgroups    = NULL;
  40. char *nn_time          = NULL;
  41. char *nn_distributions = NULL;
  42.  
  43. struct mnode *root = NULL;
  44. int entries = 0;
  45.  
  46. static long newdate, newtime;
  47.  
  48.  
  49. /*
  50.  * test_time - Check NEWNEWS time string is in the right format (ish)
  51.  */
  52.  
  53.     static int
  54. test_time () 
  55.     {
  56.     return (!(isdigit (nn_time [0]) &&
  57.               isdigit (nn_time [1]) &&
  58.               isdigit (nn_time [2]) &&
  59.               isdigit (nn_time [3]) &&
  60.               isdigit (nn_time [4]) &&
  61.               isdigit (nn_time [5]) &&
  62.               isspace (nn_time [6]) &&
  63.               isdigit (nn_time [7]) &&
  64.               isdigit (nn_time [8]) &&
  65.               isdigit (nn_time [9]) &&
  66.               isdigit (nn_time [10]) &&
  67.               isdigit (nn_time [11]) &&
  68.               isdigit (nn_time [12])));
  69.     }
  70.  
  71.  
  72. /*
  73.  * parse_args - Parse the command line arguments. Returns 1 if there is
  74.  * an error, otherwise returns 0.
  75.  */
  76.  
  77.     static int
  78. parse_args (int argc, char **argv)
  79.     {
  80.     int c;
  81.     extern int optind;
  82.     extern char *optarg;
  83.     
  84.     while ((c = getopt (argc, argv, "s:t:g:d:lwx")) != EOF)
  85.         switch (c)
  86.             {
  87.             case 's':    /* System name */
  88.                 hostname = optarg;
  89.                 break;
  90.             case 't':    /* Start time */
  91.                 nn_time = optarg;
  92.                 break;
  93.             case 'g':    /* Newsgroups list */
  94.                 nn_newsgroups = optarg;
  95.                 no_time_flag++;
  96.                 break;
  97.             case 'd':    /* Distributions */
  98.                 nn_distributions = optarg;
  99.                 break;
  100.             case 'l':    /* Use local time */
  101.                 local_time_flag++;
  102.                 break;
  103.             case 'w':    /* Don't set next time */
  104.                 no_time_flag++;
  105.                 break;
  106.             case 'x':    /* Debugging on */
  107.                 debug_flag++;
  108.                 break;
  109.             default:
  110.                 return (1);
  111.             }
  112.  
  113.     /* There must be a system name supplied */
  114.     if (hostname == NULL)
  115.         {
  116.         (void) fprintf (stderr, "No server name supplied\n");
  117.         return (1);
  118.         }
  119.  
  120.     /* If groups are specified, then must have a time */
  121.     if ((nn_newsgroups != NULL) && (nn_time == NULL))
  122.         {
  123.         (void) fprintf (stderr, "Time must be specified for -g option\n");
  124.         return (1);
  125.         }
  126.  
  127.     /* Verify that the time is in something like the right format */
  128.     if (nn_time)
  129.         if (test_time ())
  130.             return (1);
  131.  
  132.     /* Don't run if too many args as user probably got it wrong */
  133.     if (argc > optind)
  134.         return (1);
  135.  
  136.     return (0);
  137.     }
  138.  
  139.  
  140. /*
  141.  * read_sys_line - Read a line from the slurp.sys file, skipping lines
  142.  * which are blank or all comments, truncating lines at comments.
  143.  * Identical interface-wise to fgets.
  144.  */
  145.  
  146.     static char *
  147. read_sys_line (char *line, int size, FILE *sysfp)
  148.     {
  149.     char *status;
  150.     char *pos;
  151.  
  152.     for (;;)
  153.         {
  154.         if ((status = fgets (line, size, sysfp)) == NULL)
  155.             return (status);
  156.  
  157.         if (pos = strchr (line, '\n'))
  158.             *pos = '\0';
  159.  
  160.         if (pos = strchr (line, '#'))
  161.             *pos = '\0';
  162.  
  163.         if (strlen (line))
  164.             return (status);
  165.         }
  166.     }
  167.  
  168.  
  169. /*
  170.  * read_sys - Read in the appropriate entry from the slurp.sys file
  171.  * for the specified hostname. Stores the relevant newsgroups for that
  172.  * host in nn_newsgroups and the relevant distribution in nn_distributions.
  173.  * Returns 0 if an appropriate entry for the current host is found, 
  174.  * otherwise returns 1.
  175.  */
  176.  
  177.     static int
  178. read_sys ()
  179.     {
  180.     FILE *sysfp;
  181.     char buf [BUFSIZ];
  182.     char searchname [BUFSIZ];
  183.     size_t tlen;
  184.     struct stat stbuf;
  185.     int more, distfound;
  186.  
  187.     /* Attempt to open the sys file */
  188.     if ((sysfp = fopen (SYSFILE, "r")) == NULL)
  189.         log_sys ("read_sys: Error opening %s", SYSFILE);
  190.  
  191.     /* Allocate memory block for newsgroups list */
  192.     if (fstat (fileno (sysfp), &stbuf) < 0)
  193.         log_sys ("read_sys: Can't fstat %s", SYSFILE);
  194.  
  195.     if (stbuf.st_size == 0)
  196.         {
  197.         log_msg ("read_sys: Host %s not found in %s", hostname, SYSFILE);
  198.         return (1);
  199.         }
  200.  
  201.     nn_newsgroups = (char *) malloc (stbuf.st_size);
  202.     nn_newsgroups [0] = '\0';
  203.     
  204.     /* Get hostname and add a colon on the end */
  205.     (void) strcpy (searchname, hostname);
  206.     (void) strcat (searchname, ":");
  207.     tlen = strlen (searchname);
  208.  
  209.     /* Read in file until we find hostname */
  210.     for (;;)
  211.         {
  212.         if (read_sys_line (buf, sizeof (buf), sysfp) == NULL)
  213.             {
  214.             if (feof (sysfp))
  215.                 {
  216.                 log_msg ("read_sys: Host %s not found in %s",
  217.                          hostname, SYSFILE);
  218.                 return (1);
  219.                 }
  220.             else
  221.                 log_sys ("read_sys: Error reading %s", SYSFILE);
  222.             }
  223.         if (strncmp (buf, searchname, tlen) == 0)
  224.             break;
  225.         }
  226.  
  227.     /* Read groups up to '/' or line without '\' at end */
  228.     (void) strcpy (buf, buf + tlen);
  229.  
  230.     for (;;)
  231.         {
  232.         tlen = (size_t) strchr (buf, '/');
  233.         if (tlen == NULL)
  234.             {
  235.             distfound = FALSE;
  236.             tlen = (size_t) strchr (buf, '\\');
  237.             if (tlen == NULL)
  238.                 {
  239.                 more = FALSE;
  240.                 tlen = strlen (buf);
  241.                 }
  242.             else
  243.                 {
  244.                 tlen = tlen - (size_t) &buf;
  245.                 more = TRUE;
  246.                 }
  247.             }
  248.         else
  249.             {
  250.             tlen = tlen - (size_t) &buf;
  251.             distfound = TRUE;
  252.             }
  253.  
  254.         (void) strncat (nn_newsgroups, buf, tlen);
  255.  
  256.         if (distfound)
  257.             break;
  258.  
  259.         if (!more)
  260.             return (0);
  261.  
  262.         if (read_sys_line (buf, sizeof (buf), sysfp) == NULL)
  263.             log_sys ("read_sys: Error reading %s", SYSFILE);
  264.         }
  265.  
  266.     /* Set distributions from file if not already set */
  267.     if (nn_distributions != NULL)
  268.         return (0);
  269.  
  270.     nn_distributions = (char *) malloc (stbuf.st_size);
  271.     nn_distributions [0] = '\0';
  272.  
  273.     /* Read distributions up to line without '\' at end */
  274.     (void) strcpy (buf, buf + tlen + 1);
  275.     for (;;)
  276.         {
  277.         tlen = (size_t) strchr (buf, '\\');
  278.         if (tlen == NULL)
  279.             {
  280.             tlen = tlen - (size_t) &buf;
  281.             more = TRUE;
  282.             }
  283.         else
  284.             {
  285.             tlen = strlen (buf);
  286.             more = FALSE;
  287.             }
  288.  
  289.         (void) strncat (nn_distributions, buf, tlen);
  290.  
  291.         if (!more)
  292.             return (0);
  293.  
  294.         if (read_sys_line (buf, sizeof (buf), sysfp) == NULL)
  295.             log_sys ("read_sys: Error reading %s", SYSFILE);
  296.         }
  297.     }
  298.  
  299.  
  300. /*
  301.  * get_ntime - Get the start time for this NEWNEWS for system. Returns 0
  302.  * if an appropriate entry for the current host is found, otherwise 1.
  303.  */
  304.  
  305.     static int
  306. get_ntime ()
  307.     {
  308.     FILE *timefp;
  309.     char buf [BUFSIZ];
  310.     size_t tlen;
  311.  
  312.     /* Attempt to open the time file */
  313.     if ((timefp = fopen (TIMFILE, "r")) == NULL)
  314.         log_sys ("get_ntime: error opening %s", TIMFILE);
  315.  
  316.     /* Read in file until we find hostname */
  317.     tlen = strlen (hostname);
  318.     for (;;)
  319.         {
  320.         if (fgets (buf, sizeof (buf), timefp) == NULL)
  321.             {
  322.             if (feof (timefp))
  323.                 {
  324.                 log_msg ("get_ntime: Host %s not found in %s",
  325.                          hostname, TIMFILE);
  326.                 return (1);
  327.                 }
  328.             else
  329.                 log_sys ("get_ntime: Error reading %s", TIMFILE);
  330.             (void) fclose (timefp);
  331.             return (1);
  332.             }
  333.         if (strncmp (buf, hostname, tlen) == 0)
  334.             break;
  335.         }
  336.  
  337.     (void) fclose (timefp);
  338.  
  339.     /* Get the time following the hostname */
  340.     nn_time = (char *) malloc (14);
  341.     (void) strncpy (nn_time, buf + tlen + 1, 13);
  342.     nn_time [13] = '\0';
  343.  
  344.     /* And check it's in the right format */
  345.     return (test_time ());
  346.     }
  347.  
  348.  
  349. /*
  350.  * set_ntime - Set the start time for the next NEWNEWS for system
  351.  */
  352.  
  353.     static void
  354. set_ntime ()
  355.     {
  356.     FILE *oldfp;
  357.     FILE *newfp;
  358.     char backup [PATH_MAX];
  359.     char buf [BUFSIZ];
  360.     int tlen;
  361.  
  362.     /* Copy the file to a backup */
  363.     (void) strcpy (backup, TIMFILE);
  364.     (void) strcat (backup, ".o");
  365.     if (rename (TIMFILE, backup))
  366.         log_sys ("set_ntime: Error renaming %s to %s", TIMFILE, backup);
  367.  
  368.     /* Attempt to open the backup and new file */
  369.     if ((oldfp = fopen (backup, "r")) == NULL)
  370.         log_sys ("get_ntime: Error opening %s", backup);
  371.  
  372.     if ((newfp = fopen (TIMFILE, "w")) == NULL)
  373.         log_sys ("get_ntime: Error opening %s", TIMFILE);
  374.  
  375.     /* Copy file line by line, excluding the current host */
  376.     tlen = strlen (hostname);
  377.     for (;;)
  378.         {
  379.         if (fgets (buf, sizeof (buf), oldfp) == NULL)
  380.             if (feof (oldfp))
  381.                 break;
  382.             else
  383.                 log_sys ("set_ntime: Error reading %s", backup);
  384.         if (strncmp (buf, hostname, tlen) != 0)
  385.             if (fputs (buf, newfp) == NULL)
  386.                 log_sys ("set_ntime: Error writing %s", TIMFILE);
  387.         }
  388.  
  389.     /* Write the new time for current host at end */
  390.     (void) fprintf (newfp, "%s %06ld %06ld\n", hostname, newdate, newtime);
  391.     if (ferror (newfp))
  392.         log_sys ("set_ntime: Error writing %s", TIMFILE);
  393.     (void) fclose (oldfp);
  394.     (void) fclose (newfp);
  395.     }
  396.  
  397.  
  398. /*
  399.  * MAIN PROCEDURE
  400.  */
  401.  
  402.     void
  403. main (int argc, char **argv)
  404.     {
  405.     int ret;
  406.     time_t clock, starttime, endtime;
  407.     struct tm *now;
  408.  
  409.     /* Set the name of the program and parse the args */
  410.     pname = (pname = (char *) strrchr (argv [0], '/')) ? pname + 1 : argv [0];
  411.     if (parse_args (argc, argv))
  412.         {
  413.         (void) fprintf (stderr, "Usage: %s -s server [-g newsgroups] [-t time] [-d distribution] [-l] [-w] [-x]\n", pname);
  414.         exit (2);
  415.         }
  416.  
  417.     /* Open syslog if required with appropriate BSD 4.2/4.3 call */
  418. #ifdef SYSLOG
  419. #ifdef LOG_AUTH
  420.     openlog(pname, LOG_PID, SYSLOG);
  421. #else
  422.     openlog(pname, LOG_PID);
  423. #endif
  424. #endif
  425.  
  426.     /* If groups not supplied in args, then get from slurp.sys file */
  427.     if (nn_newsgroups == NULL)
  428.         if (read_sys ())
  429.             exit (2);
  430.  
  431.     /* If distributions not set, then point at null string */
  432.     if (!nn_distributions)
  433.         nn_distributions = "";
  434.  
  435.     /* If start time not supplied in args, then get from slurp.tim file */
  436.     if (nn_time == NULL)
  437.         if (get_ntime ())
  438.             exit (2);
  439.  
  440.     if (debug_flag)
  441.         {
  442.         (void) fprintf (stderr, "server: %s\n", hostname);
  443.         (void) fprintf (stderr, "time: %s\n", nn_time);
  444.         (void) fprintf (stderr, "newsgroups: '%s'\n", nn_newsgroups);
  445.         (void) fprintf (stderr, "distributions: '%s'\n", nn_distributions);
  446.         }
  447.  
  448.     /* Unless don't write flag set, get time for next NEWNEWS */
  449.     if (!no_time_flag)
  450.         {
  451.         if (local_time_flag)
  452.             clock = time ((time_t *) 0);
  453.         else
  454.             if ((clock = server_time (hostname)) == 0)
  455.                 exit (3);
  456.  
  457.         now = gmtime (&clock);
  458.         newdate = (now->tm_year * 10000) +
  459.                  ((now->tm_mon + 1) * 100) +
  460.                    now->tm_mday;
  461.         newtime = (now->tm_hour * 10000) +
  462.                   (now->tm_min * 100) +
  463.                    now->tm_sec;
  464.         }
  465.  
  466.     /* Open the history file */
  467.     if (open_history ())
  468.         log_sys ("Can't open history file %s", HISTORY_FILE);
  469.  
  470.     /* Set up the connection to the server */
  471.     switch (ret = server_init (hostname))
  472.         {
  473.         case -1 :
  474.             exit (3);
  475.         case OK_CANPOST :
  476.         case OK_NOPOST :
  477.             break;
  478.         default :
  479.             log_msg ("Can't talk to %s: got response code %d", hostname, ret);
  480.             exit (4);
  481.         }
  482.  
  483.     /* Get a list of the new articles */
  484.     get_ids ();
  485.  
  486.     /* Now get the actual articles */
  487.     starttime = time ((time_t *) 0);
  488.     if (entries > 0)
  489.         get_articles ();
  490.     endtime = time ((time_t *) 0);
  491.  
  492.     /* Time to say goodbye */
  493.     close_server ();
  494.     close_history ();
  495.  
  496.     /* Submit the remaining batch, if present */
  497.     enqueue_batch ();
  498.  
  499.     /* do we want to update the timestamp file? */
  500.     if (!no_time_flag)
  501.         set_ntime ();
  502.  
  503. #ifdef SYSLOG
  504.     if (!debug_flag)
  505.         syslog (LOG_INFO,"Processed %d new, %d duplicate, %d missing articles",
  506.                 newart, dupart, misart);
  507.     else
  508. #endif
  509.         (void) fprintf (stderr, "Processed %d new, %d duplicate, %d missing articles\n",
  510.                         newart, dupart, misart);
  511.  
  512. #ifdef SPEEDSTATS
  513.   #ifdef SYSLOG
  514.     if (!debug_flag)
  515.         syslog (LOG_INFO, "Average transfer speed %ld cps",
  516.                 totalsize / (starttime == endtime ? 1 : endtime - starttime));
  517.     else
  518.   #endif
  519.         (void) fprintf (stderr, "Average transfer speed %ld cps\n",
  520.                 totalsize / (starttime == endtime ? 1 : endtime - starttime));
  521. #endif
  522.  
  523.     exit (0);
  524.     }
  525.  
  526. /* END-OF-FILE */
  527.