home *** CD-ROM | disk | FTP | other *** search
- /*
- * slurp - a passive nntp news client
- *
- * Copyright (C) 1992/93 Stephen Hebditch. All rights reserved.
- * TQM Communications, BCM Box 225, London, WC1N 3XX.
- * steveh@orbital.demon.co.uk +44 836 825962
- *
- * See README for more information and disclaimers
- *
- * This is the main routine for slurp together with the routines to
- * handle the configuration files and command line arguments.
- *
- *
- * $Id: slurp.c,v 1.5 1993/03/01 17:51:33 root Exp $
- *
- * $Log: slurp.c,v $
- * Revision 1.5 1993/03/01 17:51:33 root
- * read_sys can cope with lines longer than BUFSIZ.
- * report when attempting to load unretrieved message ids.
- * Move sublist to a parameter after the hostname, separate by a slash.
- * Changed some system error checking.
- *
- * Revision 1.4 1993/02/14 14:57:43 root
- * Added support for simple authorisation protocol.
- * Added support for INN's 'MODE READER' command.
- * Re-arranged command line options.
- * Rewrote read_sys and added flags and authorisation options to it.
- * Rewrote get_ntime and set_ntime to use a filename of slurp.<hostname>
- * instead of slurp.tim, solving lack of locking and allowing the file
- * to contain a list of unretrieved message ids on the lines following
- * the time.
- * Don't care if slurp.<hostname> doesn't exist already.
- * If RNEWS is not defined, then change to INDIR for writing out batch
- * files.
- *
- * Revision 1.3 1992/12/15
- * Open syslog *before* we start doing things that might write to it.
- * Informational messages logged as LOG_INFO.
- * Assorted minor tidy-ups.
- *
- * Revision 1.2 1992/12/07
- * Corrected test for 4.2/4.3 BSD syslog open.
- *
- * Revision 1.1 1992/12/06
- * Made no_time_flag global.
- * Fixed null dereferencing of nn_distributions.
- *
- * Revision 1.0 1992/08/07
- * Initial coding.
- *
- */
-
- #include "slurp.h"
- #include <sys/stat.h>
-
- char *hostname = NULL;
- char *pname;
-
- int debug_flag = FALSE;
- int no_time_flag = FALSE;
- int no_id_load_flag = FALSE;
- static int local_time_flag = FALSE;
- static int mode_reader_flag = FALSE;
-
- int dupart = 0;
- int misart = 0;
- int newart = 0;
- long totalsize = 0;
-
- char *nn_newsgroups = NULL;
- char *nn_time = NULL;
- char *nn_distributions = NULL;
-
- static char *sublist = NULL;
- static char *ai_username = NULL;
- static char *ai_password = NULL;
-
- struct mnode *root = NULL;
- int entries = 0;
-
- static long newdate, newtime;
-
-
- /*
- * test_time - Check NEWNEWS time string is in the right format (ish)
- */
-
- static int
- test_time ()
- {
- return (!(isdigit (nn_time [0]) &&
- isdigit (nn_time [1]) &&
- isdigit (nn_time [2]) &&
- isdigit (nn_time [3]) &&
- isdigit (nn_time [4]) &&
- isdigit (nn_time [5]) &&
- isspace (nn_time [6]) &&
- isdigit (nn_time [7]) &&
- isdigit (nn_time [8]) &&
- isdigit (nn_time [9]) &&
- isdigit (nn_time [10]) &&
- isdigit (nn_time [11]) &&
- isdigit (nn_time [12])));
- }
-
-
- /*
- * parse_args - Parse the command line arguments. Returns 1 if there is
- * an error, otherwise returns 0.
- */
-
- static int
- parse_args (int argc, char **argv)
- {
- int c;
- extern int optind;
- extern char *optarg;
- char *pos;
-
- while ((c = getopt (argc, argv, "a:g:t:dilrw")) != EOF)
- switch (c)
- {
- case 'a': /* Do an authinfo */
- if (pos = strchr (optarg, '/'))
- {
- ai_username = optarg;
- *pos++ = '\0';
- ai_password = pos;
- }
- else
- {
- (void) fprintf (stderr, "Invalid authinfo username/password");
- return (1);
- }
- break;
- case 'g': /* Newsgroups list */
- if (pos = strchr (optarg, '/'))
- {
- *pos++ = '\0';
- nn_distributions = pos;
- }
- else
- nn_distributions = "";
- nn_newsgroups = optarg;
- no_time_flag++;
- break;
- case 't': /* Start time */
- nn_time = optarg;
- break;
- case 'd': /* Debugging on */
- debug_flag++;
- break;
- case 'i': /* Don't load unprocessed ids */
- no_id_load_flag++;
- break;
- case 'l': /* Use local time */
- local_time_flag++;
- break;
- case 'r': /* Do a 'MODE READER' */
- mode_reader_flag++;
- break;
- case 'w': /* Don't set next time */
- no_time_flag++;
- break;
- default:
- return (1);
- }
-
- /* Get server name */
- if (optind < argc)
- {
- hostname = argv [optind];
- if (pos = strchr (hostname, '/'))
- {
- *pos++ = '\0';
- sublist = pos;
- }
- }
- else
- {
- (void) fprintf (stderr, "No server name supplied\n");
- return (1);
- }
-
- /* If groups are specified, then must have a time */
- if ((nn_newsgroups != NULL) && (nn_time == NULL))
- {
- (void) fprintf (stderr, "Time must be specified for -g option\n");
- return (1);
- }
-
- /* Verify that the time is in something like the right format */
- if (nn_time)
- if (test_time ())
- {
- (void) fprintf (stderr, "Invalid time specification - should be 'YYMMDD HHMMSS'\n");
- return (1);
- }
-
- return (0);
- }
-
-
- /*
- * read_sys_line - Read a line from the slurp.sys file, skipping lines
- * which are blank or all comments, truncating lines at comments.
- * If the line has not yet all been read or the continued-on-next-line
- * token '\' is present, then returns 1; if eof then returns -1, otherwise
- * returns 0.
- */
-
- static int
- read_sys_line (char *line, int size, FILE *sysfp)
- {
- int status;
- char *pos;
-
- for (;;)
- {
- status = 0;
-
- (void) fgets (line, size, sysfp);
- if (feof (sysfp))
- return (-1);
- if (ferror (sysfp))
- log_sys ("read_sys: Error reading %s", SYSFILE);
-
- if (pos = strchr (line, '\n'))
- *pos = '\0';
- else
- status = 1;
-
- if (pos = strchr (line, '\\'))
- {
- *pos = '\0';
- status = 1;
- }
-
- if (pos = strchr (line, '#'))
- *pos = '\0';
-
- if (strlen (line))
- return (status);
- }
- }
-
-
- /*
- * read_sys - Read in the appropriate entry from the slurp.sys file
- * for the specified hostname. Stores the relevant newsgroups for that
- * host in nn_newsgroups and the relevant distribution in nn_distributions.
- * Returns 0 if an appropriate entry for the current host is found,
- * otherwise returns 1.
- */
-
- static int
- read_sys ()
- {
- FILE *sysfp;
- char buf [BUFSIZ];
- char searchname [BUFSIZ];
- struct stat stbuf;
- size_t tlen;
- char *pos;
- char *mbuf;
- int status;
- int object;
-
- /* Attempt to open the sys file */
- if ((sysfp = fopen (SYSFILE, "r")) == NULL)
- log_sys ("read_sys: Error opening %s", SYSFILE);
-
- /* Allocate memory block for storing the details */
- if (fstat (fileno (sysfp), &stbuf) < 0)
- log_sys ("read_sys: Can't fstat %s", SYSFILE);
- if (stbuf.st_size == 0)
- {
- log_msg ("read_sys: Host %s not found in %s", hostname, SYSFILE);
- return (1);
- }
- if ((mbuf = (char *) malloc (stbuf.st_size)) == NULL)
- log_sys ("read_sys: malloc %d bytes", stbuf.st_size);
-
- /* Create pattern to search for in the sys file */
- (void) strcpy (searchname, hostname);
- if (sublist)
- {
- (void) strcat (searchname, "/");
- (void) strcat (searchname, sublist);
- }
- (void) strcat (searchname, ":");
- tlen = strlen (searchname);
-
- /* Read in file until we find hostname */
- for (;;)
- {
- if ((status = read_sys_line (buf, sizeof (buf), sysfp)) == -1)
- {
- log_msg ("read_sys: Host %s not found in %s",
- hostname, SYSFILE);
- return (1);
- }
- if (strncmp (buf, searchname, tlen) == 0)
- break;
- }
-
- /* Strip off hostname stuff from front of line */
- (void) strcpy (buf, buf + tlen);
- object = 1;
- nn_newsgroups = mbuf;
-
- /* Loop through entry */
- for (;;)
- {
- /* Currently adding newsgroups */
- if (object == 1)
- {
- if (pos = strchr (buf, ':')) /* Flags next */
- {
- *pos++ = '\0';
- object = 3;
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf) + 1;
- ai_username = mbuf;
- (void) strcpy (buf, pos);
- }
- else if (pos = strchr (buf, '/')) /* Distributions next */
- {
- *pos++ = '\0';
- object = 2;
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf) + 1;
- nn_distributions = mbuf;
- (void) strcpy (buf, pos);
- }
- else
- {
- (void) strcpy (mbuf, buf); /* Nothing else this line */
- mbuf += strlen (buf);
- }
- }
-
- /* Currently adding distributions */
- if (object == 2)
- {
- if (pos = strchr (buf, ':')) /* Flags next */
- {
- *pos++ = '\0';
- object = 3;
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf) + 1;
- ai_username = mbuf;
- (void) strcpy (buf, pos);
- }
- else /* Nothing else this line */
- {
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf);
- }
- }
-
- /* Currently setting flags */
- if (object == 3)
- {
- if (pos = strchr (buf, ':')) /* authinfo user next */
- *pos++ = '\0';
- if (strchr (buf, 'i'))
- no_id_load_flag++;
- if (strchr (buf, 'l'))
- local_time_flag++;
- if (strchr (buf, 'r'))
- mode_reader_flag++;
- if (pos)
- {
- (void) strcpy (buf, pos);
- object = 4;
- }
- }
-
- /* Currently setting username */
- if (object == 4)
- {
- if (pos = strchr (buf, '/')) /* authinfo pass next */
- {
- *pos++ = '\0';
- object = 5;
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf) + 1;
- ai_password = mbuf;
- (void) strcpy (buf, pos);
- }
- else
- {
- (void) strcpy (mbuf, buf);
- break;
- }
- }
-
- /* Currently setting password */
- if (object == 5)
- {
- (void) strcpy (mbuf, buf);
- mbuf += strlen (buf) +1;
- }
-
- if (status != 1)
- break;
-
- status = read_sys_line (buf, sizeof (buf), sysfp);
- }
-
- (void) fclose (sysfp);
-
- if (nn_distributions == NULL)
- nn_distributions = "";
-
- return (0);
- }
-
-
- /*
- * get_ntime - Get the start time for this NEWNEWS for system. Returns 0
- * if an appropriate entry for the current host is found, otherwise 1.
- */
-
- static int
- get_ntime ()
- {
- FILE *timefp;
- char buf [BUFSIZ];
- char filename [PATH_MAX];
- char *pos;
-
- /* Attempt to open the time file */
- (void) strcpy (filename, TIMFILE);
- (void) strcat (filename, hostname);
- if (sublist)
- {
- (void) strcat (filename, ".");
- (void) strcat (filename, sublist);
- }
- if ((timefp = fopen (filename, "r")) == NULL)
- log_sys ("get_ntime: error opening %s", filename);
-
- /* Read in the time and store it */
- nn_time = (char *) malloc (14);
- (void) fgets (nn_time, 14, timefp);
- if (ferror (timefp))
- log_sys ("get_ntime: Error reading %s", filename);
-
- /* Return if time doesn't look ok */
- if (test_time ())
- return (1);
-
- /* Load in any message ids following */
- if (!no_id_load_flag)
- {
- if (debug_flag)
- (void) fprintf (stderr, "Loading any unretrieved message IDs\n");
- for (;;)
- {
- (void) fgets (buf, sizeof (buf), timefp);
- if (feof (timefp))
- break;
- if (ferror (timefp))
- log_sys ("get_ntime: Error reading %s", filename);
- if (pos = strchr (buf, '\n'))
- *pos = '\0';
- if (strlen (buf))
- if ((buf [0] == '<') && (buf [strlen (buf) - 1] == '>'))
- process_id (buf);
- }
- }
-
- (void) fclose (timefp);
- return (0);
- }
-
-
- /*
- * write_tree - Traverse the tree writing out ids of articles that were
- * not successfully retrieved.
- */
-
- static void
- write_tree (struct mnode *p, FILE *timefp)
- {
- if (p != NULL)
- {
- write_tree (p->left, timefp);
- if (!p->used)
- {
- (void) fprintf (timefp, "%s\n", p->msgid);
- if (ferror (timefp))
- log_sys ("write_tree: Error writing ids");
- }
- write_tree (p->right, timefp);
- }
- }
-
-
- /*
- * set_ntime - Set the start time for the next NEWNEWS for system
- */
-
- void
- set_ntime ()
- {
- FILE *timefp;
- char filename [PATH_MAX];
- char backup [PATH_MAX];
-
- /* Copy the file to a backup */
- (void) strcpy (filename, TIMFILE);
- (void) strcat (filename, hostname);
- if (sublist)
- {
- (void) strcat (filename, ".");
- (void) strcat (filename, sublist);
- }
- (void) strcpy (backup, filename);
- (void) strcat (backup, ".o");
- if (rename (filename, backup))
- if (errno != ENOENT)
- {
- log_ret ("set_ntime: Error renaming %s to %s", filename, backup);
- exit (1);
- }
-
- /* Open new file */
- if ((timefp = fopen (filename, "w")) == NULL)
- {
- log_ret ("get_ntime: Error opening %s", filename);
- exit (1);
- }
-
- /* Write the new time for current host */
- (void) fprintf (timefp, "%06ld %06ld\n", newdate, newtime);
- if (ferror (timefp))
- {
- log_ret ("set_ntime: Error writing %s", filename);
- exit (1);
- }
-
- /* Write out any message ids not read in */
- write_tree (root, timefp);
-
- (void) fclose (timefp);
- }
-
-
- /*
- * do_authinfo - Check in the authinfo username and password with the
- * server.
- */
-
- static void
- do_authinfo ()
- {
- char buf [NNTP_STRLEN];
-
- /* Send the username to the server */
- (void) sprintf (buf, "AUTHINFO USER %s", ai_username);
- if (debug_flag)
- (void) fprintf (stderr, "<- %s\n", buf);
- put_server (buf);
-
- /* Get the response and check it's okay */
- get_server (buf, sizeof (buf));
- if (debug_flag)
- (void) fprintf (stderr, "-> %s\n", buf);
- if (atoi (buf) != NEED_AUTHDATA)
- {
- log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
- exit (4);
- }
-
- /* Send the password to the server */
- (void) sprintf (buf, "AUTHINFO PASS %s", ai_password);
- if (debug_flag)
- (void) fprintf (stderr, "<- %s\n", buf);
- put_server (buf);
-
- /* Get the response and check it's okay */
- get_server (buf, sizeof (buf));
- if (debug_flag)
- (void) fprintf (stderr, "-> %s\n", buf);
- if (atoi (buf) != OK_AUTH)
- {
- log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
- exit (4);
- }
- }
-
-
- /*
- * do_mode_reader - Send mode reader command to INN to switch to nnrpd
- * so we can do a NEWNEWS.
- */
-
- static void
- do_mode_reader ()
- {
- char buf [NNTP_STRLEN];
-
- /* Send the command to the server */
- if (debug_flag)
- (void) fprintf (stderr, "<- MODE reader\n");
- put_server ("MODE READER");
-
- /* Get the response and check it's okay */
- get_server (buf, sizeof (buf));
- if (debug_flag)
- (void) fprintf (stderr, "-> %s\n", buf);
- switch (atoi (buf))
- {
- case OK_CANPOST :
- case OK_NOPOST :
- break;
- default :
- log_msg ("do_authinfo: NNTP protocol error: got '%s'", buf);
- exit (4);
- }
- }
-
-
- /*
- * MAIN PROCEDURE
- */
-
- int
- main (int argc, char **argv)
- {
- int ret;
- time_t clock, starttime, endtime;
- struct tm *now;
-
- /* Set the name of the program and parse the args */
- pname = (pname = (char *) strrchr (argv [0], '/')) ? pname + 1 : argv [0];
- if (parse_args (argc, argv))
- {
- (void) fprintf (stderr, "Usage: %s [-g newsgroups/distribution] [-t time] [-a username/password]\n", pname);
- (void) fprintf (stderr, " [-d] [-i] [-l] [-r] [-w] server[/sublist]\n");
- exit (2);
- }
-
- /* Open syslog if required with appropriate BSD 4.2/4.3 call */
- #ifdef SYSLOG
- #ifdef LOG_AUTH
- openlog(pname, LOG_PID, SYSLOG);
- #else
- openlog(pname, LOG_PID);
- #endif
- #endif
-
- /* If groups not supplied in args, then get from slurp.sys file */
- if (nn_newsgroups == NULL)
- if (read_sys ())
- exit (2);
-
- /* If start time not supplied in args, then get from slurp.tim file */
- if (nn_time == NULL)
- if (get_ntime ())
- exit (2);
-
- if (debug_flag)
- {
- (void) fprintf (stderr, "server: %s\n", hostname);
- (void) fprintf (stderr, "time: %s\n", nn_time);
- (void) fprintf (stderr, "newsgroups: '%s'\n", nn_newsgroups);
- (void) fprintf (stderr, "distributions: '%s'\n", nn_distributions);
- }
-
- /* Unless don't write flag set, get time for next NEWNEWS */
- if (!no_time_flag)
- {
- if (local_time_flag)
- clock = time ((time_t *) 0);
- else
- if ((clock = server_time (hostname)) == 0)
- exit (3);
-
- now = gmtime (&clock);
- newdate = (now->tm_year * 10000) +
- ((now->tm_mon + 1) * 100) +
- now->tm_mday;
- newtime = (now->tm_hour * 10000) +
- (now->tm_min * 100) +
- now->tm_sec;
- }
-
- /* Open the history file */
- if (open_history ())
- log_sys ("Can't open history file %s", HISTORY_FILE);
-
- #ifndef RNEWS
- /* Change to the incoming batch directory */
- if (chdir (INDIR))
- log_sys ("Can't change directory to %s", INDIR);
- #endif
-
- /* Set up the connection to the server */
- switch (ret = server_init (hostname))
- {
- case -1 :
- exit (3);
- case OK_CANPOST :
- case OK_NOPOST :
- break;
- default :
- log_msg ("Can't talk to %s: got response code %d", hostname, ret);
- exit (4);
- }
-
- /* If authinfo details supplied, then use 'em */
- if (ai_username)
- do_authinfo ();
-
- /* Switch INN to nnrpd instead of innd if needed */
- if (mode_reader_flag)
- do_mode_reader ();
-
- /* Get a list of the new articles */
- get_ids ();
-
- /* Now get the actual articles */
- starttime = time ((time_t *) 0);
- if (entries > 0)
- get_articles ();
- endtime = time ((time_t *) 0);
-
- /* Time to say goodbye */
- close_server ();
- close_history ();
-
- /* Submit the remaining batch, if present */
- enqueue_batch ();
-
- /* do we want to update the timestamp file? */
- if (!no_time_flag)
- set_ntime ();
-
- #ifdef SYSLOG
- if (!debug_flag)
- syslog (LOG_INFO,"Processed %d new, %d duplicate, %d missing articles",
- newart, dupart, misart);
- else
- #endif
- (void) fprintf (stderr, "Processed %d new, %d duplicate, %d missing articles\n",
- newart, dupart, misart);
-
- #ifdef SPEEDSTATS
- #ifdef SYSLOG
- if (!debug_flag)
- syslog (LOG_INFO, "Average transfer speed %ld cps",
- totalsize / (starttime == endtime ? 1 : endtime - starttime));
- else
- #endif
- (void) fprintf (stderr, "Average transfer speed %ld cps\n",
- totalsize / (starttime == endtime ? 1 : endtime - starttime));
- #endif
-
- exit (0);
- }
-
- /* END-OF-FILE */
-