[comp.sources.misc] v17i018: rkive - Usenet sources archiver, Part02/06

kent@sparky.imd.sterling.com (Kent Landfield) (02/25/91)

Submitted-by: Kent Landfield <kent@sparky.imd.sterling.com>
Posting-number: Volume 17, Issue 18
Archive-name: rkive/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 2 (of 6)."
# Contents:  rkive/rkive.c rkive/setup.c
# Wrapped by kent@sparky on Sun Feb 24 16:11:22 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'rkive/rkive.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/rkive.c'\"
else
echo shar: Extracting \"'rkive/rkive.c'\" \(27854 characters\)
sed "s/^X//" >'rkive/rkive.c' <<'END_OF_FILE'
X/*
X**  Subsystem:   USENET Sources Archiver             
X**  File Name:   rkive.c               
X**                                                        
X**  usage: rkive [-?dgstuvV] [-f config_file] [-n newsgroup] 
X**                           [-B batchfile] [-S newsgroup]
X**
X**
X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
X**
X** Permission is hereby granted to copy, distribute or otherwise 
X** use any part of this package as long as you do not try to make 
X** money from it or pretend that you wrote it.  This copyright 
X** notice must be maintained in any copy made.
X**
X** Use of this software constitutes acceptance for use in an AS IS 
X** condition. There are NO warranties with regard to this software.  
X** In no event shall the author be liable for any damages whatsoever 
X** arising out of or in connection with the use or performance of this 
X** software.  Any use of this software is at the user's own risk.
X**
X**  If you make modifications to this software that you feel 
X**  increases it usefulness for the rest of the community, please 
X**  email the changes, enhancements, bug fixes as well as any and 
X**  all ideas to me. This software is going to be maintained and 
X**  enhanced as deemed necessary by the community.
X**
X**              Kent Landfield
X**              uunet!sparky!kent
X**		kent@sparky.imd.sterling.com
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include "article.h"
X#include "cfg.h"
X
X#ifdef NNTP
Xchar sccsid[] = "@(#)rkive.c	2.2 2/23/91 - NNTP Version";
X#else
Xchar sccsid[] = "@(#)rkive.c	2.2 2/23/91";
X#endif /*!NNTP*/
X
X/* 
X** This is necessary since the builtin makedir call uses
X** mknod which is a superuser only call for directories.
X*/
X#if (!HAVE_MKDIR && !USE_SYSMKDIR)
X#define ROOT_ONLY
X#endif
X
X/* 
X** The following define is use for compilation
X** so that format_output can use the extended
X** fomating characters that are not available
X** in article.
X*/
X#define RKIVE
X
Xchar tmp_mailfile[] = "/tmp/rkive.mail";
Xchar global_mailfile[] = "/tmp/gbl.mail";
X
Xchar *batch_file = NULL;
Xchar article_name[MAXNAMLEN];
X
Xint retrieve = FROM_DISK;      /* default archiving is done from local disk */
Xint overwrite;
Xint status_only;
X
Xstruct stat sbuf;
X
XFILE *inputfp;
X
Xint needs_to_be_archived();
Xchar *save_article();
Xchar *compress_file();
Xchar *do_compress();
Xchar *basename();
Xchar *suffix();
Xchar *format_output();
Xvoid archive();
Xvoid build_index();
Xvoid display_group_info();
Xvoid logit();
Xvoid log_activities();
Xvoid mail_file();
Xvoid notify_users();
Xvoid record_problem();
Xvoid set_ownership();
X
Xint fclose();
Xint stat();
Xint strcmp();
Xint strlen();
Xint system();
Xint unlink();
Xchar *strcpy();
Xchar *strcat();
Xchar *strchr();
XFILE *efopen();
Xvoid exit();
X
Xextern int yydebug;
Xextern char inputstring[];
Xextern parser_return_value;
X
Xextern int debug;
Xextern int verbose;
Xextern int test;
Xextern int inum;
Xextern int problem_article;
Xextern char *nntp_server;
X
Xvoid usage()
X{
X    (void)fprintf(stderr,"usage: %s [-?dgstuvV] [-f config_file]\n", progname);
X    (void)fprintf(stderr,"          [-n newsgroup] [-B batchfile] [-S newsgroup]\n");
X    (void)fprintf(stderr,"options:\n");
X    (void)fprintf(stderr,"  -?   Display this message.\n");
X    (void)fprintf(stderr,"  -d   Debug, assumes verbose flag as well.\n");
X    (void)fprintf(stderr,"  -g   Fill in default values with group display.\n"); 
X    (void)fprintf(stderr,"       Only effective with verbose mode flag.\n");
X    (void)fprintf(stderr,"  -s   Display status of article archiving.\n");
X    (void)fprintf(stderr,"  -t   Test mode, display what would be done but do no archiving.\n");
X    (void)fprintf(stderr,"  -u   Unconditionally overwrite dupliclate articles.\n");
X    (void)fprintf(stderr,"  -v   Verbose archiving information printed.\n");
X    (void)fprintf(stderr,"  -V   Display %s software version information.\n",
X                  progname);
X    (void)fprintf(stderr,"  -f config_file\n");
X    (void)fprintf(stderr,"       Specify alternate configuration file to be used.\n");
X    (void)fprintf(stderr,"  -n newsgroup\n");
X    (void)fprintf(stderr,"       Specify newsgroup to archive or display status for.\n");
X    (void)fprintf(stderr,"  -B batchfile\n");
X    (void)fprintf(stderr,"       Read names of articles to archive from batchfile.\n");
X    (void)fprintf(stderr,"       Note: Use of the -B option requires a newsgroup\n");
X    (void)fprintf(stderr,"             be specified using the -n option.\n");
X    (void)fprintf(stderr,"  -S newsgroup\n");
X    (void)fprintf(stderr,"       Take the name of articles to archive from stdin.\n");
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X   int getopt();
X   void version();
X   void setup_defaults();
X   void init_article();
X
X   int c;
X   extern char *optarg;
X   extern int opterr;
X   char *nwsg = NULL;
X
X   yydebug = FALSE;
X
X   opterr = 0;
X   progname = argv[0];
X   inputfp = stdin;
X   logfp = stdout;
X   errfp = stderr;
X
X   status_only = debug = verbose = 0;
X   test = overwrite = fill_in_defaults = 0;
X
X   /*
X   ** Setup the default config file to be used
X   ** unless the user specifies otherwise.
X   */
X   config_file = LOCATION;
X
X   if (argc > 1) {
X      while ((c = getopt(argc, argv, "?dgstuvVn:f:B:S:y")) != EOF) {
X         switch (c) {
X             case 'B':   /* take filenames from batch file  */
X                 retrieve = FROM_BATCHFILE;
X                 batch_file = optarg;
X                 break;
X             case 'd':   /* for extremely verbose output    */
X                 debug++;
X                 verbose++;
X                 break;
X             case 'f':   /* alternate configuration file    */
X                 config_file = optarg;  
X                 break;  
X             case 'g':   /* display defaults filled in      */
X                 fill_in_defaults++;
X                 break;
X             case 'n':   /* specify an individual newsgroup */
X                 nwsg = optarg;
X                 break;
X             case 's':   /* display article archive status  */
X                 status_only++;
X                 break;
X             case 'S':   /* single article archiving        */
X                 retrieve = FROM_NAME;
X                 nwsg = optarg;
X                 break;
X             case 't':   /* test mode, show but do nothing  */
X                 test++;
X                 verbose++;
X                 break;
X             case 'u':   /* overwrite existing duplicates   */
X                 overwrite++;
X                 break;
X             case 'v':   /* display expanded output         */
X                 verbose++;
X                 break;
X             case 'V':   /* display software version only   */
X                 version();
X                 break;
X             case 'y':   /* turn on yydebug facilities      */
X                 yydebug++;
X                 break;
X             case '?':   /* display usage information       */
X             default:    /* display usage, invalid option   */
X                 usage();
X                 return(1);
X         }
X      }
X   }
X
X   /*
X   ** If the user has specified that input is be filenames
X   ** retrieved from a batch file, the user must specify a
X   ** a newsgroup in addition to the batch filename.
X   */
X   if (retrieve == FROM_BATCHFILE) {
X       if (nwsg == NULL) {
X           (void) fprintf(errfp,
X                  "%s: Must specify a newsgroup when using batchfile mode\n",
X                  progname);
X           (void) fprintf(errfp,"Sample command line...\n");
X           (void) fprintf(errfp,"\t%s -B %s -n newsgroup-here\n",
X                  progname, batch_file);
X           return(1);
X       }
X   }
X
X   setup_defaults();
X
X   init_article();
X
X   for (c = 0; c <= num; c++)  {
X       newsgrp = &group[c];
X       /*
X       ** Was a newsgroup specified on the command line ?
X       */
X       if (nwsg != NULL) {
X          if (strcmp(nwsg, newsgrp->ng_name) != 0)
X              continue;
X       }
X       archive();
X   }
X
X   if (!status_only) {
X       /*
X       ** Mail notification of the archived members to the 
X       ** list of users specified in the configuration file
X       ** and remove the file containing the archived info.
X       */
X       mail_file(mail, global_mailfile, "Rkive results");
X       (void) unlink(global_mailfile);
X   }
X   return(0);
X}
X
Xvoid archive()
X{
X    char *get_archived_rec();
X    int retrieve_article();
X    void get_header();
X
X    int cct;
X    int first;
X    int val;
X    char *rp, *rec;
X    char *new_member;
X    char *archived_file;
X    
X#ifdef ROOT_ONLY
X    /*
X    ** check to assure that the user is root if 
X    ** actual archiving is to take place. This is necessary
X    ** if there is no mkdir system call.
X    */
X
X    if (!status_only && (getuid() != 0)) {
X        (void) fprintf(errfp, "%s: Sorry, Must be root to rkive.\n",
X                        progname);
X        exit(1);
X    }
X#endif /* ROOT_ONLY */
X
X    inum = 0;  /* initialize chronological issue counter */
X
X    /* Remove any existing temporary mail file */
X
X    (void) unlink(tmp_mailfile);
X    cct = 0;  /* counter for newsgroup message in global mail */
X
X    /*
X    ** Assure that there something specified in the 
X    ** archive location variable...
X    */
X    if (!*newsgrp->location) {
X        (void) fprintf(errfp, "SKIPPING %s: No archive location specified..\n",
X                        newsgrp->ng_name);
X        return;
X    }
X
X    /*
X    ** print out the appropriate 
X    ** header for the newsgroup.
X    ** If the user wishes to see the newsgroup info as well as all the
X    ** information about a file archived, the user must specify 
X    ** rkive -svv to see it all... 
X    */
X
X    if (debug || (verbose == 2 && status_only)) {
X        (void) fprintf(logfp,"\n\n");
X        display_group_info(newsgrp);
X        (void) fprintf(logfp,"\n");
X    }
X    else if (status_only || verbose == 2)
X        (void) fprintf(logfp, "%s\n",newsgrp->ng_name);
X
X    /*
X    ** Create a path to the .archived file for the newsgroup's archive.
X    ** This file is used to determine if an article has already been
X    ** archived.  If the user did not specify one ...
X    */
X    if (!*newsgrp->arc_done)
X       (void) sprintf(newsgrp->arc_done,"%s/.archived",newsgrp->location);
X
X    /*
X    ** Create a path to the .patchlog file for the newsgroup's archive.
X    ** This file is used to record patches to posted software so that
X    ** it can easily be determined what the full set of software is.
X    */
X    if (!*newsgrp->patchlog)
X       (void) sprintf(newsgrp->patchlog,"%s/.patchlog",newsgrp->location);
X
X    /*
X    ** first indicates that archiving has just begun for this group
X    ** so that any necessary setup can be done in retrieve_article().
X    */
X
X    first = 1;
X
X#ifdef NNTP
X    /* 
X    ** Determine if the newsgroup being archived is to be accessed via
X    ** nntp or via local disk access.
X    */
X    if (*newsgrp->nntp) {
X        nntp_server = newsgrp->nntp;
X        retrieve = FROM_NNTP;
X    }
X    else if (*nntp) {
X        nntp_server = nntp;
X        retrieve = FROM_NNTP;
X    }
X#endif /*NNTP*/
X
X    while ((val = retrieve_article(article_name,first)) != DONE) {
X        first = 0;
X        if (val == ERROR_ENCOUNTERED)
X            return;
X        else if (val != RETRIEVED) {
X           /* 
X           ** Invalid return value encountered, we're in truble now..
X           */
X           (void) fprintf(errfp,"Invalid return from retrieve_article..?? Skipping %s\n",
X                          newsgrp->ng_path);
X           return;
X       }
X
X       /*
X       ** Read the news article file to extract the
X       ** header information and fill appropriate
X       ** data structures.
X       */
X       get_header(article_name);
X
X       /* 
X       ** If the user has specified that a quick status 
X       ** listing should be produced then hop to it....
X       */
X
X       if (status_only) {
X            if ((rec = get_archived_rec(header.ident)) == NULL) {
X                /*
X                ** Assure that the article that we are going
X                ** to give status on is one that would be archived
X                ** if archiving was occuring. (e.g. does it match 
X                ** the user supplied criteria for archiving...)
X                */
X                if (*newsgrp->match) {
X                     parser_return_value = 0;
X                     (void) strcpy(inputstring, newsgrp->match);
X                     if (yyparse()) 
X                         (void) fprintf(logfp, "Parse failed and returned %d\n",
X                                                parser_return_value);
X                     else {
X                         /* Did match string produce true as result? */
X
X                        if (debug)
X                            (void) fprintf(logfp, "Parser returned %d\n",
X                                                   parser_return_value);
X                    }
X                    if (!parser_return_value) {
X#ifdef NNTP
X                        /*
X                        ** Since they only want status, remove the 
X                        ** nntp transfer tmpfile if newsgroup is
X                        ** being archived via nntp.
X                        */
X                        if (retrieve == FROM_NNTP)
X                            (void) unlink(article_name);
X#endif /*NNTP*/
X                        continue;
X                    }
X               }
X#ifdef NNTP
X               if (retrieve == FROM_NNTP)
X                  (void) fprintf(logfp,
X                                 "\t[%s] Awaiting Archiving\n",header.ident);
X               else
X                  (void) fprintf(logfp,
X                                 "\t[%s] Awaiting Archiving\n",article_name);
X#else /*!NNTP*/
X               (void) fprintf(logfp,"\t[%s] Awaiting Archiving\n",article_name);
X#endif /*NNTP*/
X            }
X            else if (verbose) {
X                if ((rp = strchr(rec,' ')) == NULL) {
X#ifdef NNTP
X                   if (retrieve == FROM_NNTP)
X                      (void) fprintf(logfp,"\t[%s] Archived\n",header.ident);
X                   else
X                      (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
X#else /*!NNTP*/
X                   (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
X#endif /*NNTP*/
X                }
X                else {
X                    rp++;
X                    *(rp-1) = '\0';
X                    (void) fprintf(logfp,"\t%s Archived as %s\n",rec,rp);
X                }
X            }
X#ifdef NNTP
X            /*
X            ** Since they only want status, remove the 
X            ** nntp transfer tmpfile if newsgroup is
X            ** being archived via nntp.
X            */
X            if (retrieve == FROM_NNTP)
X                (void) unlink(article_name);
X#endif /*NNTP*/
X            continue;
X       }  /* End of status only... */
X
X       /* 
X       **
X       ** We have located a file that may need to be archived. 
X       ** First read the header information from the found file.
X       ** Next, determine if the file needs to be archived by
X       ** doing a linear search of of the contents of the .archived file
X       ** comparing the message-id of the new article with the message-ids
X       ** recorded in the .archived file. If the new message-id is not
X       ** specified in the .archived file, it has not been archived
X       ** before and we can proceed with the archiving.
X       ** Can we say slow... maybe dbm in the future ???
X       */
X
X       if (!needs_to_be_archived(header.ident)) {
X#ifdef NNTP
X           /*
X           ** Remove the nntp transfer tmpfile if the
X           ** newsgroup is being archived via nntp.
X           */
X           if (retrieve == FROM_NNTP)
X               (void) unlink(article_name);
X#endif /*NNTP*/
X           continue;
X       }
X          
X       if (*newsgrp->match) {
X           (void) strcpy(inputstring, newsgrp->match);
X
X           if (yyparse()) {
X               (void) fprintf(logfp, "Parse failed and returned %d\n",
X                                      parser_return_value);
X#ifdef NNTP
X               /*
X               ** Remove the nntp transfer tmpfile if the
X               ** newsgroup is being archived via nntp.
X               */
X               if (retrieve == FROM_NNTP)
X                   (void) unlink(article_name);
X#endif /*NNTP*/
X               continue;
X           }
X
X           /* Did match string produce true as result? */
X
X           if (debug)
X               (void) fprintf(logfp, "Parser returned %d\n", parser_return_value);
X
X           if (!parser_return_value) {
X#ifdef NNTP
X               /*
X               ** Remove the nntp transfer tmpfile if the
X               ** newsgroup is being archived via nntp.
X               */
X               if (retrieve == FROM_NNTP)
X                   (void) unlink(article_name);
X#endif /*NNTP*/
X               continue;
X           }
X       }
X
X       /*
X       ** Archiving from here on out.
X       */
X 
X       if ((new_member = save_article(article_name,newsgrp)) != NULL) {
X           /*
X           ** To not do any compression of setting of ownership
X           ** for newsgroup articles that are archived by an
X           ** external application.
X           */
X           if (newsgrp->type != EXTERNAL_COMMAND) {
X               archived_file = compress_file(new_member,newsgrp);
X               set_ownership(archived_file,new_member,newsgrp);
X           }
X           else
X               archived_file = new_member;
X           
X           /*
X           ** If a problem has been encountered,
X           ** the function do_problem handles
X           ** the logging, and notifying.
X           */
X
X           if (!problem_article) {
X               log_activities(archived_file,newsgrp);
X               build_index(new_member,newsgrp);
X               notify_users(archived_file,newsgrp,cct++);
X           }
X       }
X       else {
X           if (newsgrp->type != ONLY_ARCHIVE_NAME) {
X               (void) fprintf(logfp,"Unable to archive %s/%s!!!\n",
X                          newsgrp->ng_path, article_name);
X           }
X       }
X#ifdef NNTP
X       /*
X       ** Remove the nntp transfer tmpfile if the
X       ** newsgroup is being archived via nntp.
X       */
X       if (retrieve == FROM_NNTP)
X           (void) unlink(article_name);
X#endif /*NNTP*/
X    }
X
X    if (!status_only) {
X        /* Mail notification of the archived members to the   */
X        /* list of users specified in the configuration file  */
X        /* and remove the file containing the archived info.  */
X
X        mail_file(newsgrp->mail_list, tmp_mailfile, newsgrp->ng_name);
X        (void) unlink(tmp_mailfile);
X    }
X    return;
X}
X
X/* 
X** Notify Users of Archiving.
X**      If users have been specified to be informed, check to see
X**      if they have requested a specific logging format. If so
X**      use the specified format to notify the user. If not, use
X**      "file archived at path" message.
X*/
Xvoid notify_users(filename,ng,num_msgs)
Xchar *filename;
Xstruct group_archive *ng;
Xint num_msgs;
X{
X    /*
X    ** Are there users specified in the 
X    ** newsgroup section ? 
X    */
X    if ( *(ng->mail_list) ) {
X        if ( *(ng->logformat) )
X           logit(tmp_mailfile, ng->logformat, filename);
X        else
X           logit(tmp_mailfile, DEFAULT_LOG_FORMAT, filename);
X    }
X
X    /* 
X    ** Are there users specified in the 
X    ** global section ? 
X    */
X    if ( *mail ) {
X        if (num_msgs == 0) /* print the newsgroup name out */
X            logit(global_mailfile, "\n\t\t:%G:\n",filename);
X        if (*log_format)
X            logit(global_mailfile, log_format,filename);
X        else 
X            logit(global_mailfile, DEFAULT_LOG_FORMAT, filename);
X    }
X}
X
X/*
X** Log_activities
X**
X** There are two possible logfiles that need to be written. 
X** The group specific logfile (ng->logfile) and the global 
X** log. If it has been configured to use a specific format
X** for the logging, do so. Else, just record the fact the
X** file was sucessfully archived and the date.          
X*/
Xvoid log_activities(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X   long clock;
X   long time();
X   char *ctime();
X   
X   char logbuf[BUFSIZ];
X   char dms_date[30];
X   
X   if ( !*(ng->logformat) || !*log_format) {
X       clock = time((long *)0);
X       (void) strcpy(dms_date, ctime(&clock));
X       *(dms_date+(strlen(dms_date)-1)) = '\0';
X       (void) sprintf(logbuf,"%s archived %s",filename, dms_date);
X   }
X
X   if ( *(ng->logformat) )
X       logit(ng->logfile, ng->logformat, filename);
X   else
X       logit(ng->logfile, logbuf, filename);
X
X   if ( *log_format )
X       logit(log, log_format, filename);
X   else
X       logit(log, logbuf, filename);
X}
X
X/*
X** logit
X**
X** This function is used to append a logfile record 
X** if there is a logfile name specified.
X**
X*/
X
Xvoid logit(filename, format_of_log, arch_file)
Xchar *filename;
Xchar *format_of_log;
Xchar *arch_file;
X{
X    FILE *fp, *fopen();
X    char *qp;
X
X    if (!test) {
X        if ( *(filename) ) {   /* Is a logfile specified ? */
X            if ((fp = fopen(filename,"a")) != NULL) {
X                qp = format_output(format_of_log, arch_file, ARCHIVE);
X                (void) fprintf(fp,"%s\n",qp);
X                (void) fclose(fp);
X            }
X        }
X    }
X}    
X
X/*
X** Set_ownership
X**
X**      This functions is responsible for setting the owner, group
X**      and modes of a file just put into the archive. Two file names
X**      are passed to this function. "filename" contains the compression
X**      suffix if the file is to be compressed. "flname" is the name of
X**      the file without the compression suffix. If the ownership or
X**      modes can not be set on the target "filename", this function
X**      then tries to set the original file, "flname". In this manner,
X**      the file permissions get set even if the compression routine fails.
X*/     
X
Xvoid set_ownership(filename,flname,ng)
Xchar *filename;             /* filename with compression suffix    */ 
Xchar *flname;               /* filename without compression suffix */
Xstruct group_archive *ng;
X{
X    int chmod();
X    int chown();
X
X    if (verbose)    /* Print out the actions about to be preformed */
X        (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
X
X    if (!test) {    /* change the file modes to the specified modes */
X        if (chmod(filename,ng->modes) != 0) {
X            /* Assume the compress failed and try the original... */
X            if (chmod(flname,ng->modes) != 0) 
X                record_problem("Can't change modes of %O", filename, ng);
X        }
X    }
X
X    if (verbose) {  /* Print out the actions about to be preformed */
X        (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
X        (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
X    }
X
X    if (!test) {    /* chown the owner/group to the desired values */
X        if (chown(filename, ng->owner, ng->group) != 0) {
X            /* Assume the compress failed and try the original... */
X            if (chown(flname, ng->owner, ng->group) != 0) { 
X                /*
X                ** Are we on a system that has a braindamaged chown 
X                ** and does not let a general user give files away ?
X                ** Assume so.  Quota be gone!!
X                */
X                if (getuid() == 0)
X                    record_problem("Can't change ownership of %O",filename,ng);
X            }
X        }
X    }
X}
X
Xvoid mail_file(user_list, file_to_mail, nwsgrp)
Xchar *user_list;
Xchar *file_to_mail;
Xchar *nwsgrp;
X{
X    char  *list, *name;
X    char  cmdstr[80];
X
X    /* Is there a list of users to mail to ? */
X    if ( !*user_list || (strlen(user_list) == 0))
X        return;
X
X    /* Was there a notification file created ? */
X    if (stat(file_to_mail, &sbuf) != 0) 
X        return;
X
X    name = user_list;
X    do {
X       if ((list = strchr(name,',')) != NULL) {
X            list++;
X            *(list-1) = '\0';
X        }
X
X#ifdef SUBJECT_LINE
X        (void) sprintf(cmdstr, "%s -s '%s' %s < %s", 
X                   MAIL, nwsgrp, name, file_to_mail);
X#else
X        (void) sprintf(cmdstr, "%s %s < %s", MAIL, name, file_to_mail);
X#endif
X        if (verbose)
X            (void) fprintf(logfp,"Mailing %s to %s\n",
X                           nwsgrp, name);
X        if (!test) 
X            (void) system(cmdstr);
X
X        name = list;
X
X    } while (name != NULL);
X    return;
X}
X
Xvoid build_index(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X    if (*(ng->index)) {        /* Is there a newsgroup index file ?  */
X        if (*(ng->indformat))  /* Yes, Is there a index file format? */
X            logit(ng->index, ng->indformat, filename);
X        else if (*index_format)    /* No, is there a global format ? */
X            logit(ng->index, index_format, filename);
X        else                   /* No, use the default index format   */
X            logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
X    }
X
X    if (*mindex) {            /* Is there a global index file ?       */
X        if (*index_format)   /* Yes, Is there a global file format ? */
X            logit(mindex, index_format, filename);
X        else                 /* No, so use the default index format  */
X            logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
X    }
X}
X
X
Xchar *compress_file(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X    static char compressed[MAXNAMLEN];
X
X    (void) strcpy(compressed, filename);  /* store the filename */
X
X    /* Check to see if a group specific compress was specified.      */
X    /* If so, then execute the command with the filename passed in.  */
X    /* Else check to see if a global compress was specified. If so,  */
X    /* then execute the command with the filename passed in.         */
X    /* If both are NULL, no compression is done.                     */
X
X    if (*(ng->compress) || (*compress)) { 
X        if (*(ng->compress)) 
X            (void) strcat(compressed, do_compress(ng->compress, filename));
X        else if (*compress) 
X            (void) strcat(compressed, do_compress(compress, filename));
X
X        /* Check to see if the compression worked. If not, return the */
X        /* original file name passed to this function. The check is   */
X        /* done by assuring the compressed file exists. If not then   */
X        /* it is assumed that it failed.                              */
X
X        if (stat(compressed, &sbuf) == -1) 
X            (void) strcpy(compressed, filename);   /* restore filename */
X    }
X    return(compressed);
X}
X
Xchar *do_compress(packit,filename)
Xchar *packit;
Xchar *filename;
X{
X    char *comp_cmd;
X    char *kp;
X    char cmd[BUFSIZ];
X
X    (void) sprintf(cmd,"%s %s", packit, filename);
X
X    /* 
X    ** get the basename of the command to use.
X    */
X    comp_cmd = basename(packit);
X
X    if (verbose)
X       (void) fprintf(logfp,"%s %s\n", comp_cmd, filename);
X
X    if (!test) 
X       (void) system(cmd);
X
X    /* 
X    ** Need to remove any compression command 
X    ** options if they exist. (compress -f)
X    */
X
X    (void) sprintf(cmd,"%s", comp_cmd);
X
X    if ((kp = strchr(cmd,' ')) != NULL) {
X         *kp = '\0';
X    }
X    return(suffix(cmd));
X}
X
X
X/*
X** Record_problem()
X**	This function is used to log problems encountered
X**	to the designated parties.
X*/
X
Xvoid record_problem(msg_fmt,filename,ng)
Xchar *msg_fmt;
Xchar *filename;
Xstruct group_archive *ng;
X{
X    /* 
X    ** This function is used in the event that a problem
X    ** has occurred during archiving. It mails a message
X    ** to the newsgroup speecified list and it mails a 
X    ** message to the globally specified users.
X    ** 
X    ** It then logs the fact into both the newsgroup 
X    ** and the global logfiles if they have been specified.
X    */
X
X    if ( *(ng->mail_list) ) 
X        logit(tmp_mailfile, msg_fmt, filename);
X    
X    if ( *mail ) 
X        logit(global_mailfile, msg_fmt,filename);
X    
X    logit(ng->logfile, msg_fmt, filename);
X    logit(log, msg_fmt, filename);
X}
END_OF_FILE
if test 27854 -ne `wc -c <'rkive/rkive.c'`; then
    echo shar: \"'rkive/rkive.c'\" unpacked with wrong size!
fi
# end of 'rkive/rkive.c'
fi
if test -f 'rkive/setup.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/setup.c'\"
else
echo shar: Extracting \"'rkive/setup.c'\" \(23815 characters\)
sed "s/^X//" >'rkive/setup.c' <<'END_OF_FILE'
X/*
X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
X**
X** Permission is hereby granted to copy, distribute or otherwise 
X** use any part of this package as long as you do not try to make 
X** money from it or pretend that you wrote it.  This copyright 
X** notice must be maintained in any copy made.
X**
X*/
X
X#if !defined(lint) && !defined(SABER)
Xstatic char SID[] = "@(#)setup.c	2.2 2/23/91";
X#endif
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <pwd.h>
X#include <grp.h>
X#include "cfg.h"
X
X#define GAG(b) ((void) fprintf(errfp,"%s invalid variable, ignoring.\n",b))
X
Xchar spooldir[MAXNAMLEN]     = { SPOOLDIR };
Xchar problems_dir[MAXNAMLEN] = { PROBLEMS_DIR };
X
Xint default_owner = OWNER;
Xint default_group = GROUP;
Xint default_modes = MODES;
Xint default_type = CHRONOLOGICAL;
Xint default_patch_type = HISTORICAL;
X
Xchar default_match[MAXMATCHLEN];
X
X/*
X** compress -
X** Used to  determine whether or not articles should be compressed 
X** to save space. The command to execute is stored in compress.
X*/
Xchar compress[MAXNAMLEN] = { '\0' };
X
X/*
X** arch_command -
X** Used to determine whether or not articles should be piped
X** to an external command for the actual archiving.
X*/
Xchar arch_command[MAXNAMLEN] = { '\0' };
X
X/*
X** mail -
X** If specified, all actions logged are mailed to the list of users 
X** specified.  The user names are a comma seperated list. 
X*/
Xchar mail[MAXNAMLEN] = { '\0' };
X
X/*
X** checkhash -
X** If specified, command to feed article to for transit damage.
X*/
Xchar checkhash[MAXNAMLEN] = { '\0' };
X
X#ifdef NNTP
X/*
X** nntp -
X** If specified, nntp contains the system name of the nntp server.
X*/
Xchar nntp[MAXNAMLEN] = { '\0' };
X#endif /*NNTP*/
X
X/*
X** log -
X** The location of the master log in which all actions are logged. 
X** If not specified, all logged events are printed on stdout.
X*/
Xchar log[MAXNAMLEN] = { '\0' };
X
X/*
X** log_format -
X** The format of each individual log file record. The format is
X** then filled with information contained in the headers.
X*/
Xchar log_format[BUFSIZ] = { '\0' };
X
X/*
X** mindex -
X** The location of the master index.
X*/
Xchar mindex[MAXNAMLEN] = { '\0' };
X
X/*
X** index_format -
X** The format of each individual master index record. The format 
X** is then filled with information contained in the headers.
X*/
Xchar index_format[BUFSIZ] = { '\0' };
X
Xchar *config_file;
XFILE *config;
X
Xstruct stat stbuf;
Xstruct passwd *pwent;
X
Xint get_group();
Xint get_owner();
Xint correct_modes();
Xint get_patch_type();
Xint get_archive_type();
Xint fclose();
Xint sscanf();
Xint stat();
Xint strlen();
Xint strcmp();
Xint strncmp();
Xchar *strstrip();
Xchar *strchr();
Xchar *strcpy();
Xvoid error();
Xvoid get_spooldir();
Xvoid get_archive_basedir();
Xstruct passwd *getpwnam();
X
Xstruct restricted_dirs {
X    char   *dirstr;            /* path of restricted directory */
X};
X
Xstatic struct restricted_dirs base_dirs[] = {
X{  "/"               },
X{  "/bin"            },
X{  "/dev"            },
X{  "/dev/dsk"        },
X{  "/dev/rdsk"       },
X{  "/etc"            },
X{  "/lib"            },
X{  "/stand"          },
X{  "/sbin"           },
X{  "/sys"            },
X{  "/usr/5bin"       },
X{  "/usr/5include"   },
X{  "/usr/5lib"       },
X{  "/usr/adm"        },
X{  "/usr/adm"        },
X{  "/usr/boot"       },
X{  "/usr/diag"       },
X{  "/usr/etc"        },
X{  "/usr/include"    },
X{  "/usr/kvm"        },
X{  "/usr/spool/uucp" },
X{  "/usr/man"        },
X{  "/usr/sccs"       },
X{  "/usr/sys"        },
X{  "/usr/ucb"        },
X{  "/usr/ucbinclude" },
X{  "/usr/ucblib"     },
X{  "/usr/xpg2bin"    },
X{  "/usr/xpg2include" },
X{  "/usr/xpg2lib"    },
X{  NULL              },
X};
X
Xint config_line_count = 0;
X
X/*
X**  Reads lines from file, catting lines 
X**  ending with a backslash together. 
X*/
X
Xchar *long_fgets(buffer, size, fp)
Xchar *buffer;
Xint size;
XFILE *fp;
X{
X    static char buf[BUFSIZ];
X    extern char *strcat();
X    register char *p;
X
X    *buffer = 0;
X
X    for (;;) {
X        if (fgets(buf, BUFSIZ, fp) == NULL) {
X            if (*buffer) {
X                if ((p = strchr(buf, '\n')) != NULL) 
X                    *p = 0;
X                return buffer;
X            }
X            else
X                return NULL;
X        }
X
X        if ((p = strchr(buf, '\n')) != NULL)
X            *p = 0;
X
X        if (*buf) {
X            if (*(buf + strlen(buf) - 1) != '\\') {
X                /* 
X                ** If line would be too long,
X                ** print warning and return empty 
X                */
X                if (strlen(buffer) + strlen(buf) >= size) {
X                   (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
X                             config_line_count, size);
X                    *buffer = 0;
X                    return buffer;
X                }
X                (void) strcat(buffer, buf);
X                return buffer;
X            }
X            else {
X                *(buf + strlen(buf) - 1) = 0; /* Remove backslash */
X
X                /* 
X                ** If too long, print warning, read 
X                ** all continuation lines and ignore 
X                ** them, return empty line 
X                */
X
X                if (strlen(buffer) + strlen(buf) >= size) {
X                    (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
X                           config_line_count, size);
X                    while (*(buf + strlen(buf) - 1) == '\\' && fgets(buf, BUFSIZ, fp))
X                          ;
X                    *buffer = 0;
X                    return buffer;
X                }
X
X                /* Add new line and read next one */
X
X                (void) strcat(buffer, buf);
X             }
X         }
X         else
X             return buffer;
X
X       } /* End for(ever) */
X}
X
X
Xvoid setup_defaults()
X{
X    char *sp;
X    char *buf;
X    char buffer[BUFSIZ];
X    char mode_str[128];
X
X    char *sav_format();
X    char *get_cmd();
X    char *get_users();
X#ifdef NNTP
X    char *getnntp();
X#endif /*NNTP*/
X    FILE *efopen();
X
X    config = efopen(config_file,"r");
X
X    num = -1; /* initialize group structure index */
X    
X    while (long_fgets(buffer, sizeof buffer, config) != NULL) {
X        config_line_count++;
X        /* ignore comments and blank lines */
X        if (*buffer == '#' || !*buffer) 
X            continue;
X
X        buf = buffer;
X
X        /* strip leading spaces and tabs */
X	while(*buf == ' ' || *buf == '\t')
X             ++buf;
X
X        /* if embedded comments, truncate at the comment */
X        if ((sp = strchr(buf,'#')) != NULL)
X             *sp = '\0';
X    
X        /* check to see if newsgroup entry */
X
X        if (*buf == '$' && *(buf+1) == '$') {
X            if (++num >= NUM_NEWSGROUPS)
X               error("Maximum number of newsgroups exceeded!!\n", 
X                    "Please increase the NUM_NEWSGROUPS define...");
X
X            sp = buf+2;
X            while (*sp && !isspace(*sp))
X		++sp;
X            *sp = '\0';
X
X            group[num].owner     = default_owner;
X            group[num].group     = default_group;
X            group[num].modes     = default_modes;
X            group[num].type      = default_type;
X            group[num].patch_type = default_patch_type;
X            (void) strcpy (group[num].ng_name, strstrip(buf+2));
X            group[num].location[0]  = '\0';
X            group[num].mail_list[0] = '\0';
X            group[num].arc_done[0]  = '\0';
X            group[num].logfile[0]   = '\0';
X            group[num].index[0]     = '\0';
X            group[num].patchlog[0]  = '\0';
X            group[num].logformat[0] = '\0';
X            group[num].indformat[0] = '\0';
X            group[num].compress[0]  = '\0';
X            group[num].checkhash[0]  = '\0';
X            group[num].match[0]     = '\0';
X            group[num].arch_command[0] = '\0';
X
X#ifdef NNTP
X            group[num].nntp[0]  = '\0';
X#endif /*NNTP*/
X        }
X
X        else if ((sp = strchr(buf,'=')) != NULL) {
X            sp++;
X            		/* Global assignment */
X            while (*sp == ' ' || *sp == '\t')
X                sp++;
X
X            if (!*sp)		/* is something still there ? */
X		continue;
X
X            switch(*buf) {
X               case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
X                            (void) strcpy(arch_command, get_cmd(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
X                            (void) strcpy(compress, get_cmd(sp));
X                         else if (strncmp(buf, "CHECKHASH", 9) == 0)
X                            (void) strcpy(checkhash, get_cmd(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'G': if (strncmp(buf,"GROUP",5) == 0)
X                             default_group = get_group(sp);
X                         else
X                            GAG(buf);
X                         break;
X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
X                            (void) strcpy(index_format, sav_format(sp));
X                         else if (strncmp(buf, "INDEX", 3) == 0)
X                            (void) strcpy(mindex, strstrip(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
X                            (void) strcpy(log_format, sav_format(sp));
X                         else if (strncmp(buf, "LOG", 3) == 0)
X                            (void) strcpy(log, strstrip(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'M': if (strncmp(buf, "MAIL",4) == 0) 
X                             (void) strcpy(mail,get_users(sp));
X                         else if (strncmp(buf, "MODE",4) == 0) 
X                             default_modes = correct_modes(sp, mode_str);
X                         else if (strncmp(buf, "MATCH", 5) == 0)
X                             (void) strcpy(default_match, sp);
X                         else
X                             GAG(buf);
X                         break;
X#ifdef NNTP
X               case 'N': if (strncmp(buf, "NNTP",4) == 0) 
X                             (void) strcpy(nntp, getnntp(sp));
X                         else 
X                             GAG(buf);
X                         break;
X#endif /*NNTP*/
X               case 'O': if (strncmp(buf,"OWNER",5) == 0)
X                             default_owner = get_owner(sp);
X                         else 
X                             GAG(buf);
X                         break;
X               case 'P': if (strncmp(buf, "PROBLEMS", 8) == 0)
X                           (void) strcpy(problems_dir, strstrip(sp));
X                         else if (strncmp(buf,"PATCHES",7) == 0)
X                           default_patch_type = get_patch_type("Global",sp);
X                         else 
X                             GAG(buf);
X                         break;
X               case 'S': if (strncmp(buf,"SPOOLDIR",8) == 0)
X                             get_spooldir(sp);
X                         else 
X                             GAG(buf);
X                         break;
X               case 'T': if (strncmp(buf,"TYPE",4) == 0)
X                             default_type = get_archive_type("Global", sp);
X                         else 
X                             GAG(buf);
X                         break;
X               default : (void) fprintf(errfp,
X                                  "%s invalid global assignment, ignoring.\n",
X                                  buf);
X            }
X        }
X        else if ((sp = strchr(buf,':')) != NULL) {
X            sp++;
X                /* group variable assignment */
X            while (*sp == ' ' || *sp == '\t')
X                sp++;
X
X            if (!*sp)		/* is something still there ? */
X		continue;
X
X            switch(*buf) {
X               case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
X                            (void)strcpy(group[num].arch_command,get_cmd(sp));
X                         else if (strncmp(buf, "ARCHIVED_LOG", 11) == 0) 
X                            (void) sprintf(group[num].arc_done, strstrip(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'B': if (strncmp(buf, "BASEDIR",7) == 0) 
X                            get_archive_basedir(sp);
X                         break;
X               case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
X                            (void) strcpy(group[num].compress,get_cmd(sp));
X                         else if (strncmp(buf, "CHECKHASH", 9) == 0)
X                            (void) strcpy(group[num].checkhash,get_cmd(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'G': if (strncmp(buf,"GROUP",5) == 0)
X                             group[num].group = get_group(sp);
X                         else
X                            GAG(buf);
X                         break;
X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
X                            (void) strcpy(group[num].indformat,sav_format(sp));
X                         else if (strncmp(buf, "INDEX", 3) == 0)
X                             (void) strcpy(group[num].index, strstrip(sp));
X                         else
X                             GAG(buf);
X                         break;
X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
X                            (void) strcpy(group[num].logformat, sav_format(sp));
X                         else if (strncmp(buf, "LOG", 3) == 0)
X                            (void) strcpy(group[num].logfile, strstrip(sp));
X                         else
X                            GAG(buf);
X                         break;
X               case 'M': if (strncmp(buf, "MAIL",4) == 0)
X                            (void) strcpy(group[num].mail_list, get_users(sp));
X                         else if (strncmp(buf, "MODE",4) == 0) 
X                             group[num].modes = correct_modes(sp, mode_str);
X                         else if (strncmp(buf, "MATCH", 5) == 0)
X                             /* Copy as it is! */
X                             (void) strcpy(group[num].match, sp);
X                         else 
X                             GAG(buf);
X                         break;
X#ifdef NNTP
X               case 'N': if (strncmp(buf, "NNTP",4) == 0) 
X                             (void) strcpy(group[num].nntp, getnntp(sp));
X                         else 
X                             GAG(buf);
X                         break;
X#endif /*NNTP*/
X               case 'O': if (strncmp(buf,"OWNER",5) == 0)
X                             group[num].owner = get_owner(sp);
X                         else 
X                             GAG(buf);
X                         break;
X               case 'P': if (strncmp(buf,"PATCHLOG",8) == 0)
X                             (void) sprintf(group[num].patchlog, strstrip(sp));
X                         else if (strncmp(buf,"PATCHES",7) == 0)
X                             group[num].patch_type = get_patch_type(group[num].ng_name,sp);
X                         else 
X                             GAG(buf);
X                         break;
X               case 'T': if (strncmp(buf,"TYPE",4) == 0)
X                             group[num].type = get_archive_type(group[num].ng_name,sp);
X                         else 
X                             GAG(buf);
X                         break;
X               default : (void) fprintf(errfp,
X                                  "%s invalid group assignment, ignoring.\n",
X                                  buf);
X            }
X        }
X        else /* no idea what it is */
X            error("unknown line type", buf);
X    }
X    (void) fclose(config);
X    config_line_count = 0;
X}
X
Xvoid error(msg1,msg2)
X   char *msg1;
X   char *msg2;
X{
X   if (config_line_count)
X      (void) fprintf(errfp,"%s: config line %d: %s %s\n",
X                   progname, config_line_count, msg1, msg2);
X   else
X      (void) fprintf(errfp,"%s: %s %s\n",progname,msg1, msg2);
X
X    exit(1);
X/*NOTREACHED*/
X}
X
X/*
X** valid_base_directory
X**
X** Assure the directory specified in the configuration file 
X** as the base directory for a newsgroup archive is not found 
X** in the table of restricted base directories. 
X**
X** This kind of checking is almost insulting to me as an 
X** administrator but, enough people asked me to put it in 
X** so "this duds for you"..
X*/
X
Xint valid_base_directory(argstr)
X    char *argstr;
X {
X    register char *rp;
X    register char *dp;
X    char wpath[MAXNAMLEN];
X    char lastchar;
X    struct restricted_dirs *pt;
X
X    /* 
X    ** First check to see if the base directory is any
X    ** character other than a slash. We need to assure
X    ** that "../../../etc" or ./etc is not allowed.  We
X    ** need a valid absolute path with which to do relative
X    ** path addressing. (Have I confused myself yet ?)
X    */
X
X    if (*argstr != '/') 
X            return(FALSE);
X
X    /* 
X    ** Strip the string of duplicate '/'s.
X    ** Also check to assure that the path specified
X    ** does not contain the '..' sequence.
X    */
X
X    dp = argstr;
X    rp = wpath;
X    lastchar = ' ';
X
X    while (*dp) {
X       if (*dp != '/' || lastchar != '/') {
X           lastchar = *dp;
X           *rp++ = *dp;
X       }
X       if (*dp == '.' && lastchar == '.') {
X           if ((*(dp+1) == '/') || (*(dp+1) == '\0'))
X               return(FALSE);
X       }
X       ++dp;
X    }
X    *rp = '\0';
X
X    /* 
X    ** strip the string of trailing '/'s so
X    ** I can use the simple checking below.
X    */
X
X    dp = wpath+(strlen(wpath)-1);
X    while(*dp == '/' && dp > wpath)
X        *dp = '\0';
X
X    /* 
X    ** check if they match 
X    */
X
X    pt = &base_dirs[0];
X    while ((pt->dirstr) != NULL) {
X
X        if (strcmp(wpath, pt->dirstr) == 0) 
X            return(FALSE);
X
X        pt++;
X    }
X    return(TRUE);
X}
X
Xvoid get_archive_basedir(s)
Xchar *s;
X{
X    (void) strcpy(group[num].location, strstrip(s));
X
X    if (!valid_base_directory(group[num].location))
X        error(group[num].ng_name," - Invalid archive base directory!");
X}
X
Xint correct_modes(s,mode_string)
Xchar *s;
Xchar *mode_string;
X{
X    register int c;
X    register int i;
X
X    i = 0;
X    (void) sscanf(s, "%s", mode_string);
X    while ((c = *mode_string++) >= '0' && c <= '7')
X        i = (i << 3) + (c - '0');
X    mode_string--;
X    return(i);
X}
X
X
Xchar *get_cmd(cmd)
Xchar *cmd;
X{
X    static char *rp;
X    char *kp;
X
X    rp = strstrip(cmd);
X
X    /*
X    ** Here an external command needs to be verified.
X    ** To do so, the options must be removed. I am being
X    ** real lazy here but what the hey..
X    ** If a space is found after the cmdline is striped
X    ** put a null there and then replace it with a 
X    ** space after the check... 
X    */
X   
X    if ((kp = strchr(rp,' ')) != NULL)
X        *kp = '\0';
X    else if ((kp = strchr(rp,'\t')) != NULL)
X        *kp = '\0';
X
X    /* need to assure the user has specified */
X    /* a valid executable path.              */
X
X    if (stat(rp, &stbuf) != 0) 
X        error("Can't find specified command -", rp);
X
X    if (kp != NULL)  /* replace the space.. */
X        *kp = ' ';
X
X    return(rp);
X}
X
X#ifdef NNTP
Xchar *getnntp(loc)
Xchar *loc;
X{
X    static char *rp;
X
X    rp = strstrip(loc);
X     
X    /*
X    ** check to assure that the user does not wish to negate 
X    ** a global declaration for the nntp server.
X    */
X
X    if ((strncmp(rp,"LOCAL",5) == 0) || (strncmp(rp, "local",5) == 0))
X        return("");
X
X    return(rp);
X}
X#endif /*NNTP*/
X        
X
X
Xint get_group(valstr)
Xchar *valstr;
X{
X    char *wp;
X    struct group *grent;
X    struct group *getgrnam();
X    
X    /* group specified by names but */
X    /* needs to be numbers          */
X
X    wp = strstrip(valstr);
X
X    if ((grent = getgrnam(wp)) == NULL)
X         error("Invalid system group:",wp);
X    return(grent->gr_gid);
X}
X
X
Xint get_owner(valstr)
Xchar *valstr;
X{
X    char *wp;
X
X    /* owner specified by names but */
X    /* needs to be numbers          */
X
X    wp = strstrip(valstr);
X
X    if ((pwent = getpwnam(wp)) == NULL)
X         error("Invalid user:",wp);
X    return(pwent->pw_uid);
X}
X
Xint get_archive_type(ngname, s)
Xchar *ngname;
Xchar *s;
X{
X    int return_type = default_type;
X
X    if (strcmp(s, "Archive-Name") == 0) 
X        return_type = ARCHIVE_NAME;
X    else if (strcmp(s, "Volume-Issue") == 0) 
X        return_type = VOLUME_ISSUE;
X    else if (strcmp(s, "Chronological") == 0) 
X        return_type = CHRONOLOGICAL;
X    else if (strcmp(s, "Article-Number") == 0) 
X        return_type = ARTICLE_NUMBER;
X    else if (strcmp(s, "Comp-Archives") == 0) 
X        return_type = COMP_ARCHIVES;
X    else if (strcmp(s, "External-Command") == 0) 
X        return_type = EXTERNAL_COMMAND;
X    else if (strcmp(s, "Only-Archive-Name") == 0) 
X        return_type = ONLY_ARCHIVE_NAME;
X    else {
X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X                   ngname, "Invalid Archive Type:", s);
X        (void) fprintf(errfp,"\tTYPE Must be %s, %s, %s, %s, %s, %s or %s\n",
X                   "Archive-Name",  "Volume-Issue", "Comp-Archives",
X                   "External-Command", "Only-Archive-Name", 
X                   "Chronological", "Article-Number");
X        exit(1);
X    }
X    return(return_type);
X}
X
Xvoid get_spooldir(s)
Xchar *s;
X{
X    static char *rp;
X
X    rp = strstrip(s);
X
X    /* need to assure the user has specified */
X    /* a valid directory path for the base   */
X    /* directory for the news subsystem..    */
X    
X    if (stat(rp, &stbuf) != 0) 
X        error("Can't find SPOOLDIR -", rp);
X    
X    (void) strcpy(spooldir, rp);
X}
X
Xchar *get_users(s)
Xchar *s;
X{
X    char *strcat();
X
X    static char users[512];
X    char tmp_users[512];
X    char *list, *name;
X    char *cp, *dp;
X    register int i;
X
X    /* prepare the string for saving by stripping any spaces */
X
X    for (i = 0; i < sizeof users; i++)
X       users[i] = '\0';
X
X    cp = s;
X    dp = users;
X    while (*cp) {
X          if (*cp != ' ' && *cp != '\t')
X              *dp++ = *cp;
X          ++cp;
X    }
X      
X    /* Need to check the specified user list */
X    /* to assure that all users are valid.   */
X
X    (void) strcpy(tmp_users, users);
X    *users = '\0';
X
X    name = tmp_users;
X
X    while (name != NULL) {
X        /* is there additional users specified ? */
X	if ((list = strchr(name,',')) != NULL) {
X             list++;
X             *(list-1) = '\0';
X        }
X
X#ifdef CHECK_LOGNAME 
X        /* check if user is found in passwd file */
X        if ((pwent = getpwnam(name)) == NULL) 
X            error("Invalid user:",name);
X#endif /* CHECK_LOGNAME */
X
X        if (*users != '\0') {
X            (void) strcat(users, ",");
X            (void) strcat(users, name);
X        }
X        else 
X            (void) strcpy(users, name);
X        name = list;
X    }
X    return(users);
X}
X
X/*
X** get a specified format from the buffer
X**	Must allow for spaces and tabs so they
X**      need to be passed intact in the format.
X*/
Xchar *sav_format(s)
X    char *s;
X{
X    static char *cp;
X    char *dp;
X    
X    if ((cp = strchr(s,'"')) != NULL && 
X        (dp = strchr(++cp,'"')) != NULL) {
X        *dp = '\0';
X    }
X    else
X        cp = NULL;
X    return(cp);
X}
X
Xint get_patch_type(ngname,s)
Xchar *ngname;
Xchar *s;
X{
X    int return_type = default_type;
X
X    if (strcmp(s, "Package") == 0) 
X        return_type = PACKAGE;
X    else if (strcmp(s, "Historical") == 0) 
X        return_type = HISTORICAL;
X    else {
X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X                   ngname, "Invalid Patches Type:", s);
X        (void) fprintf(errfp,"\tPATCHES Must be %s, or %s\n",
X                   "Historical", "Package");
X        exit(1);
X    }
X    return(return_type);
X}
END_OF_FILE
if test 23815 -ne `wc -c <'rkive/setup.c'`; then
    echo shar: \"'rkive/setup.c'\" unpacked with wrong size!
fi
# end of 'rkive/setup.c'
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.