v19i100: Usenet sources archiver, Part03/04

Rich Salz rsalz at uunet.uu.net
Sat Jul 1 00:46:57 AEST 1989


Submitted-by: Kent Landfield <ssbell!kent>
Posting-number: Volume 19, Issue 100
Archive-name: rkive/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 4)."
# Contents:  header.c rkive.cf setup.c
# Wrapped by kent at ssbell on Thu Jun  1 16:19:13 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'header.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'header.c'\"
else
echo shar: Extracting \"'header.c'\" \(15302 characters\)
sed "s/^X//" >'header.c' <<'END_OF_FILE'
X/*
X**
X** This software is Copyright (c) 1989 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**  History:
X**	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X**                                                               
X*/
X#ifndef lint
Xstatic char SID[] = "@(#)header.c	1.1 6/1/89";
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include "article.h"
X
Xint its(s1)
Xregister char *s1;
X{
X    if (strncmp(s,s1,strlen(s1)) == 0)
X        return(TRUE);
X    return(FALSE);
X}
X
Xint line_type()
X{
X    if (its("Path: "))
X        return PATH;
X    if (its("From: "))
X        return FROM;
X    if (its("Newsgroups: "))
X        return NEWSGROUP;
X    if (its("Subject: "))
X        return SUBJECT;
X    if (its("Keywords: "))
X        return KEYWORDS;
X    if (its("Date: "))
X        return DATE;
X    if (its("Message-ID: "))
X        return MSG_ID;
X    if (its("Lines: "))
X        return NUMLINES;
X    if (its("Approved: "))
X        return APPROVED;
X
X    /* The following is the auxilliary headers used by */
X    /* the moderators of the sources groups. In some  */
X    /* cases, line checks are done with "historical"  */
X    /* auxilliary headers. Most of the moderators have */
X    /* now standardized on comp.sources.unix's format.*/
X
X    /* Archive header lines for comp.sources.unix     */
X    /* for comp.sources.amiga, comp.sources.atari.st, */
X    /* comp.sources.misc, and comp.sources.x.         */
X
X    if (its("Submitted-by: "))         
X        return SUBMITTED_BY;
X    if (its("Posting-number: "))       
X        return POSTING_NUMBER;
X    if (its("Archive-name: "))
X        return ARCH_NAME;
X
X    /* Archive header lines for historical purposes */
X    /* once used in comp.sources.misc               */
X
X    if (its("Submitted-By: "))        
X        return SUBMITTED_BY;
X    if (its("comp.sources.misc: "))
X        return POSTING_NUMBER;
X    if (its("Archive-Name: "))
X        return ARCH_NAME;
X
X    /* Archive header lines used in comp.sources.games   */
X    /* Archive-name is the same as comp.sources.unix     */
X
X    if (its("Submitted by: "))        
X        return SUBMITTED_BY;
X    if (its("Comp.sources.games: "))
X        return POSTING_NUMBER;
X
X    /* Auxiliary header used as a backward reference   */
X    /* to the location of the initially posted sources */
X    /* in the event of a patch. This line only exists  */
X    /* if the current article is a patch.              */
X
X    if (its("Patch-To: "))
X        return PATCH_TO;
X
X    /* Archive header lines for historical purposes */
X    /* once used in mod.sources articles.           */
X
X    if (its("Mod.sources: "))       
X        return POSTING_NUMBER;
X
X    /* The remainder are other types of lines included */
X    /* headers and are includes for formatting output  */
X    /* and for potential future use.                   */
X
X    if (its("References: "))
X        return REFERENCES;
X    if (its("Organization: "))
X        return ORGANIZATION;
X    if (its("Distribution: "))
X        return DISTRIBUTION;
X    if (its("Xref: "))
X        return XREF;
X    if (its("Expires: "))
X        return EXPIRE;
X    if (its("Article-I.D.: "))
X        return ARTICLEID;
X    if (its("Reply-To: "))
X        return REPLY_TO;
X    if (its("Control: "))
X        return CONTROL;
X    if (its("Sender: "))
X        return SENDER;
X    if (its("Followup-To: "))
X        return FOLLOWUP_TO;
X    if (its("Summary: "))
X        return SUMMARY;
X    if (its("Supersedes: "))
X        return SUPERSEDES;
X
X    return OTHER;
X}
X
Xdata(hpfield, size, fldname)
Xchar    *hpfield;
Xint    size;
Xchar    *fldname;
X{
X    register char *ptr;
X    register char *p;
X    char *strncpy();
X    char *strchr();
X
X    for (ptr = strchr(s, ':'); isspace(*++ptr); )
X        ;
X    if (*ptr != '\0') {
X        (void) strncpy(hpfield, ptr, size - 1);
X        /*
X         * Strip trailing newlines, blanks, and tabs from hpfield.
X         */
X        for (p = hpfield; *p; ++p)
X             ;
X        while (--p >= hpfield && (*p == '\n' || *p == ' ' || *p == '\t'))
X             ;
X        *++p = '\0';
X    }
X    if (debug)
X       (void) fprintf(logfp,"%s: %s\n",fldname, hpfield);
X}
X
Xdump_article()
X{
X    char *type_str;
X
X    switch(article.rectype) {
X             case PATCH  : type_str = "PATCH";
X                           break;
X      case INFORMATIONAL : type_str = "INFORMATIONAL"; 
X                           break;
X                 default : type_str = "NORMAL"; 
X                           break;
X    }
X
X    (void) fprintf(logfp,"Article:           [%s]\n",article.newsarticle);
X    (void) fprintf(logfp,"   newsgroup:      [%s]\n",article.newsgroup);
X    (void) fprintf(logfp,"   filename:       [%s]\n",article.filename);
X    (void) fprintf(logfp,"   volume:         [%d]\n",article.volume);
X    (void) fprintf(logfp,"   issue:          [%d]\n",article.issue);
X    (void) fprintf(logfp,"   record type:    [%s]\n", type_str);
X    if (article.rectype == PATCH) {
X        (void) fprintf(logfp,"   patch volume:   [%d]\n",article.patch_volume);
X        (void) fprintf(logfp,"   patch issue:    [%d]\n",article.patch_issue);
X    }
X    (void) fprintf(logfp,"   reposted:       [%s]\n", 
X                   article.repost ? "YES": "NO");
X    (void) fprintf(logfp,"   description:    [%s]\n",article.description);
X    (void) fprintf(logfp,"   author's name:  [%s]\n",article.author_name);
X    (void) fprintf(logfp,"   author's logon: [%s]\n\n",article.author_signon);
X}
X
Xinit_article()
X{
X    article.newsgroup[0] = '\0';
X    article.newsarticle[0] = '\0';
X    article.filename[0] = '\0';
X    article.volume = -1;
X    article.issue = -1;
X    article.rectype = NORMAL;
X    article.repost = FALSE;
X    article.patch_volume = -1;
X    article.patch_issue = -1;
X    article.description[0] = '\0';
X    article.author_name[0] = '\0';
X    article.author_signon[0] = '\0';
X
X    header.from[0] = '\0';         /* From:                 */
X    header.path[0] = '\0';         /* Path:                 */
X    header.nbuf[0] = '\0';         /* Newsgroups:           */
X    header.subject[0] = '\0';      /* Subject:              */
X    header.ident[0] = '\0';        /* Message-ID:           */
X    header.replyto[0] = '\0';      /* Reply-To:             */
X    header.references[0] = '\0';   /* References:           */
X    header.subdate[0] = '\0';      /* Date: (submission)    */
X    header.subtime = 0;            /* subdate in secs       */
X    header.expdate[0] = '\0';      /* Expires:              */
X    header.ctlmsg[0] = '\0';       /* Control:              */
X    header.sender[0] = '\0';       /* Sender:               */
X    header.followup_to[0] = '\0';  /* Followup-to:          */
X    header.distribution[0] = '\0'; /* Distribution:         */
X    header.organization[0] = '\0'; /* Organization:         */
X    header.numlines[0] = '\0';     /* Lines:                */
X    header.intnumlines = 0;        /* Integer Version       */
X    header.keywords[0] = '\0';     /* Keywords:             */
X    header.summary[0] = '\0';      /* Summary:              */
X    header.approved[0] = '\0';     /* Approved:             */
X    header.xref[0] = '\0';         /* Xref:                 */
X    header.supersedes[0] = '\0';   /* Supersedes:           */
X    header.submitted_by[0] = '\0'; /* Submitted_by:         */
X    header.posting_num[0] = '\0';  /* Posting-number:       */
X    header.archive_name[0] = '\0'; /* Archive-name:         */
X    header.patch_to[0] = '\0';     /* Patch-To:             */
X}
X
Xstore_line()
X{
X    char *strchr(), *strcpy(), *strstrip(), *substr();
X    char *dp, *sp;
X    char wrk[20];
X
X    switch(line_type()) {
X
X    case PATH: /*PATH REQUIRED************************/
X        data(header.path, sizeof(header.path), "PATH:");
X        break;
X
X    case FROM: /*FROM REQUIRED************************/
X        data(header.from, sizeof(header.from), "FROM:");
X        break;
X
X    case NEWSGROUP: /*NEWSGROUP REQUIRED**************/
X        data(header.nbuf, sizeof(header.nbuf), "NEWSGROUPS:");
X        if ((sp = strchr(s,':')) != NULL) {
X             do {
X                 ++sp;
X             } while(!isalpha(*sp));
X             /* remove all crossposting labels */
X             if ((dp = strchr(sp,',')) != NULL)
X                 *dp = '\0';
X             (void) strcpy(article.newsgroup,sp);
X        }
X        break;
X
X    case SUBJECT: /*SUBJECT REQUIRED******************/
X        data(header.subject, sizeof(header.subject), "SUBJECT:");
X        /* 
X        ** Save the subject as the description for articles
X        ** that have no volume/issue format. Later in the
X        ** code, this subject line minus the volume/issue
X        ** is stored back in the .description element if
X        ** the volume/issue indicator is found.
X        */
X        (void) strcpy(article.description, header.subject);
X
X        /*
X        ** Check to see if this article is a repost of
X        ** a previously posted article.
X        */
X        if (substr(s, "REPOST") != NULL)
X            article.repost = TRUE;
X
X        /*
X        ** Time to get the filename. Assure that it is in a 
X        ** volume/issue (v01INF1 or v01i001) format.
X        */
X        if ((sp = strchr(s,'v')) == NULL) 
X            return;          /* no volume indicator */
X
X        /* 
X        ** Is there a number that follows 
X        ** the volume indicator ? 
X        */
X        if (*(sp+1) < '0' || *(sp+1) > '9')
X            return;   /* The volume number is missing */
X
X        /*
X        ** Is there a second ':' as well ?
X        */
X        (void) strcpy(article.filename,sp);
X        if ((dp = strchr(article.filename,':')) == NULL) 
X            return;   /* not in v01i001: format */
X
X        /*
X        ** terminate the article's filename and 
X        ** store the article's description 
X        */
X        *dp = '\0';
X        (void) strcpy(article.description, strstrip(++dp));
X
X        /*
X        ** Store the filename in a work 
X        ** buffer so I can stomp on it. 
X        */
X        (void) strcpy(wrk, article.filename);
X
X        /* 
X        ** This is an informational posting.
X        */
X        if ((dp = substr(wrk, "INF")) != NULL) {
X            article.rectype = INFORMATIONAL;
X            article.issue = atoi((dp+3));
X            ++sp;
X            *dp = '\0';
X            article.volume = atoi(sp);
X        }
X
X        /*
X        **  check to see if there is an issue indicator 
X        */
X        else if ((dp = strchr(++sp,'i')) == NULL) 
X            return;   /* proven guilty. not volume/issue format */
X
X        /* parse the volume from the filename */
X        *dp = '\0';
X        article.volume = atoi(sp);
X      
X        /* parse the issue from the filename */
X        sp = ++dp;
X        while (isdigit(*dp)) ++dp;
X        *dp = '\0';
X        article.issue = atoi(sp);
X
X        break;
X
X    case DATE:
X        data(header.subdate, sizeof(header.subdate), "DATE:");
X        break;
X
X    case EXPIRE:
X        data(header.expdate, sizeof(header.expdate), "EXPIRES:");
X        break;
X
X    case MSG_ID:
X        data(header.ident, sizeof(header.ident), "MESSAGE-ID:");
X        break;
X
X    case REPLY_TO:
X        data(header.replyto, sizeof(header.replyto), "REPLY-TO:");
X        break;
X
X    case REFERENCES:
X        data(header.references, sizeof(header.references), "REFERENCES:");
X        break;
X
X    case SENDER:
X        data(header.sender, sizeof(header.sender), "SENDER:");
X        break;
X
X    case FOLLOWUP_TO:
X        data(header.followup_to, sizeof(header.followup_to),"FOLLOWUP-TO:");
X        break;
X
X    case CONTROL:
X        data(header.ctlmsg, sizeof(header.ctlmsg),"CONTROL:");
X        break;
X
X    case DISTRIBUTION:
X        data(header.distribution, sizeof(header.distribution),"DISTRIBUTION:");
X        break;
X
X    case ORGANIZATION:
X        data(header.organization, sizeof(header.organization),"ORGANIZATION:");
X        break;
X
X    case NUMLINES:
X        data(header.numlines, sizeof(header.numlines),"LINES:");
X        header.intnumlines = atoi(header.numlines);
X        break;
X
X    case KEYWORDS:
X        data(header.keywords, sizeof(header.keywords), "KEYWORDS:");
X        break;
X
X    case APPROVED:
X        data(header.approved, sizeof(header.approved), "APPROVED:");
X        break;
X
X    case SUPERSEDES:
X        data(header.supersedes, sizeof(header.supersedes),"SUPERSEDES:");
X        break;
X
X    case XREF:
X        data(header.xref, sizeof(header.xref),"XREF:");
X        break;
X
X    case SUMMARY:
X        data(header.summary, sizeof(header.summary),"SUMMARY:");
X        break;
X
X    case POSTING_NUMBER:
X        data(header.posting_num, sizeof(header.posting_num), "POSTING_NUMBER:");
X        break;
X
X    case SUBMITTED_BY:
X        data(header.submitted_by, sizeof(header.submitted_by), "SUBMITTED_BY:");
X        /* 
X        ** Save the author's name and sign on if specified 
X        ** Can be in any of the following formats:
X	**	kent at ssbell.uucp 
X	**	kent at ssbell.uucp (Kent Landfield)
X	**	Kent Landfield <kent at ssbell.uucp>
X        */
X        if ((sp = strchr(s,':')) != NULL) {
X            (void) strcpy(article.author_signon,(sp+2));
X            /*
X            ** Has a name been attached to the signon ?
X            */
X            if ((dp = strchr(article.author_signon,'<')) != NULL) {
X                *(dp-1) = '\0';
X                (void) strcpy(article.author_name, article.author_signon);
X                (void) strcpy(article.author_signon, ++dp);
X                /*
X                ** Save the name, removing the <>.
X                */
X                if ((dp = strchr(article.author_signon,'>')) != NULL)
X                    *dp = '\0';
X            }
X            else if ((dp = strchr(article.author_signon,'(')) != NULL) {
X                *(dp-1) = '\0';
X                /*
X                ** Save the name, removing the ().
X                */
X                (void) strcpy(article.author_name, ++dp);
X                if ((dp = strchr(article.author_name,')')) != NULL)
X                    *dp = '\0';
X            }
X        }
X        break;
X
X    case ARCH_NAME:
X        data(header.archive_name,sizeof(header.archive_name),"ARCH_NAME:");
X        break;
X
X    case PATCH_TO:
X        data(header.patch_to,sizeof(header.patch_to),"PATCH_TO:");
X        article.rectype = PATCH;        /* set the article type */
X
X        /*
X	** Parse the initially posted article's volume and issue.
X        ** The format of the auxiliary header is
X        ** 
X        ** Patch-To: Volume 5, Issue 110
X        **
X        ** In the case of multipart initial postings, the Patch-To:
X        ** line points to the first issue.
X        */
X
X        /* 
X        ** First get the volume number.
X        */
X
X        dp = s;
X        while (*dp && (!isdigit(*dp)))
X              ++dp;
X        sp = dp;
X        while (*dp && (isdigit(*dp)))
X              ++dp;
X        *dp = '\0';
X        article.patch_volume = atoi(sp);
X
X        /* 
X        ** Now get the issue number. 
X        */
X
X        ++dp;
X        while (*dp && (!isdigit(*dp)))
X              ++dp;
X        sp = dp;
X        while (*dp && (isdigit(*dp)))
X              ++dp;
X        *dp = '\0';
X        article.patch_issue = atoi(sp);
X        break;
X    }
X    return;
X}
END_OF_FILE
if test 15302 -ne `wc -c <'header.c'`; then
    echo shar: \"'header.c'\" unpacked with wrong size!
fi
# end of 'header.c'
fi
if test -f 'rkive.cf' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive.cf'\"
else
echo shar: Extracting \"'rkive.cf'\" \(9112 characters\)
sed "s/^X//" >'rkive.cf' <<'END_OF_FILE'
X#
X#
X#	@(#)rkive.cf	1.1 6/1/89 
X#
X#	An rkive.cf template.
X#	Copy and edit this to reflect the local archive conditions.
X#	After editing, run ckconfig to display how rkive will interpret
X#	the local specifications.
X#
X#	The format of the configuration file is as follows:
X#
X######################################################################
X#
X#	Global variables
X#		SPOOLDIR - the base directory for the news subsystem
X#		PROBLEMS - The name of the base directory used to store any
X#                          duplicate or "problem" articles. All articles are
X#                          stored under this directory in a newsgroup/volume
X#                          directory.
X#	        TYPE    -  This is the archive type (or the archive key)
X#		           There are 3 possible keys:
X#			        Volume-Issue, Archive-Name or Article-Number
X#		           These are used to determine if you wish the 
X#                          articles archived in a 
X#			        /basedir/amiga/Volume1/v001i22 or
X#			        /basedir/amiga/Volume1/sitonit or
X#			        /basedir/amiga/Volume1/44 format
X#	     PATCHES     - This variable determines the way in which patches
X#                          are installed into the archive. If the PATCHES
X#                          entry is not defined either globally or within
X#                          the newsgroup, the article is handled as a regular
X#                          article and is stored according to the specified
X#                          parameters of the newsgroup. The following are
X#                          the valid possible values for the PATCHES variable:
X#                             PATCHES=Historical 
X#                                 This is the same as if no PATCHES entry
X#                                 existed at all. It is useful if Historical
X#                                 patches archiving is the default but there
X#                                 are certain newsgroups that have it specified
X#                                 differently.
X#                             PATCHES=Package 
X#                                 Package patches archiving allows the inbound
X#                                 patch to be placed with the directory with
X#                                 the initially posted articles. In this manner
X#                                 all parts and fixes of a package are together
X#                                 making it easier for software retrieval by
X#                                 uucp requests and mail request facilities
X#                                 such as netlib.
X#		MAIL	 - If specified, all actions are mailed to the
X#			   list of users specified. The user names are
X#			   a comma separated list. It is not necessary to
X#                          specify any users. 
X#	        OWNER -    The unix login name for the owner of the 
X#                          archive files after they are stored in the archive.
X#	        GROUP -    The unix group value for the group ownership of 
X#                          the archive files after they are stored in the 
X#                          archive.
X#	        MODE     - The modes of the files residing in the archive.
X#		LOG	 - The location of the master log in which all 
X#			   actions are logged. 
X#             LOG_FORMAT - The format of the records of the master log file.
X#                          See the man page for article for a discussion of
X#                          the available selection format capabilities.
X#               INDEX    - The location of the master index (if one is kept).
X#                          The index can be used to interface with the netlib 
X#                          source retrieval software facility.
X#           INDEX_FORMAT - The format of the records of the master log file.
X#                          See the man page for article for a discussion of
X#                          the available selection format capabilities.
X#               COMPRESS - The location of the compression utility if the 
X#                          files are to be reduced.
X#
X######################################################################
XSPOOLDIR=/usr/spool/news      
XPROBLEMS=/usenet/problems
XTYPE= Volume-Issue
XPATCHES=Historical
XMAIL=kent
XOWNER=src
XGROUP=archive
XMODE=0444
XLOG=/usenet/archive.log
XLOG_FORMAT= "%B %T" 
XINDEX= /usenet/index
XINDEX_FORMAT= "%B %a %T" 
X#COMPRESS=/usr/lbin/compress
X
X######################################################################
X#
X#	Each Newsgroup to be archived has an entry with the following
X#	possible variables. (Note that all variables are not necessary)
X#	
X#	BASEDIR - This is the path to the base directory of the archive
X#	TYPE    - This is the archive type (or the archive key)
X#		  There are 3 possible keys:
X#			Volume-Issue, Archive-Name or Article-Number
X#		  These are used to determine if you wish the articles
X#		  archived in a 
X#			/basedir/amiga/Volume1/v001i22 or
X#			/basedir/amiga/Volume1/sitonit or
X#			/basedir/amiga/Volume1/44 format
X#	PATCHES - This variable determines the way in which patches
X#                 are installed into the archive. If the PATCHES
X#                 entry is not defined either globally or within
X#                 the newsgroup, the article is handled as a regular
X#                 article and is stored according to the specified
X#                 parameters of the newsgroup. The following are
X#                 the valid possible values for the PATCHES variable:
X#                 PATCHES=Historical 
X#                        This is the same as if no PATCHES entry
X#                        existed at all. It is useful if Historical
X#                        patches archiving is the default but there
X#                        are certain newsgroups that have it specified
X#                        differently.
X#                 PATCHES=Package 
X#                        Package patches archiving allows the inbound
X#                        patch to be placed with the directory with
X#                        the initially posted articles. In this manner
X#                        all parts and fixes of a package are together
X#                        making it easier for software retrieval by
X#                        ftp, uucp requests and mail request facilities
X#                        such as netlib.
X#	   MAIL - If specified, all actions are mailed to the
X#		  list of users specified. The user names are
X#		  a comma separated list.
X#         OWNER - The unix login name for the owner of the archive files 
X#		  after they are stored in the archive.
X#	  GROUP - The unix group value for the group ownership of the archive 
X#		  files after they are stored in the archive.
X#	   MODE - The modes of the files residing in the archive.
X#	    LOG - The location of the log in which all actions are logged. 
X#    LOG_FORMAT - The format of the records of the master log file.
X#                 See the man page for article for a discussion of
X#                 the available selection format capabilities.
X#      INDEX    - The location of the master index (if one is kept).
X#                 The index can be used to interface with the netlib 
X#                 source retrieval software facility.
X#  INDEX_FORMAT - The format of the records of the master log file.
X#                 See the man page for article for a discussion of
X#                 the available selection format capabilities.
X#      COMPRESS - The location of the compression utility if the files 
X#		  are to be reduced.
X#		
X######################################################################
X$$comp.sources.amiga		
X	BASEDIR: /usenet/amiga 
X	TYPE: Volume-Issue
X	MAIL: rick
X	LOG: /usenet/amiga/log
X        INDEX: /usenet/amiga/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$comp.sources.atari.st
X	BASEDIR: /usenet/atari/st
X	TYPE: Volume-Issue
X	LOG: /usenet/atari/st/log
X        INDEX: /usenet/atari/st/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$comp.sources.games		
X	BASEDIR: /usenet/games
X	MAIL: rick
X	TYPE: Volume-Issue
X	LOG: /usenet/games/log
X        INDEX: /usenet/games/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$comp.sources.mac		
X	BASEDIR: /usenet/mac
X	TYPE: Article-Number
X	LOG: /usenet/mac/log
X        INDEX: /usenet/mac/index
X        INDEX_FORMAT: "%O %a %T" 
X
X$$comp.sources.misc		
X	BASEDIR: /usenet/misc
X	TYPE: Volume-Issue
X	MAIL: rick
X	LOG: /usenet/misc/log
X        INDEX: /usenet/misc/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$comp.sources.unix		
X	BASEDIR: /usenet/unix
X	TYPE: Volume-Issue
X	MAIL: rick
X	LOG: /usenet/unix/log
X        LOG_FORMAT: "%B %a %T" 
X        INDEX: /usenet/unix/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$comp.sources.x		
X	BASEDIR: /usenet/x
X	TYPE: Archive-Name
X	PATCHES: Package
X	MAIL: rick,kent,mark
X	LOG: /usenet/x/log
X        LOG_FORMAT: "%B %a %T" 
X        INDEX: /usenet/unix/index
X        INDEX_FORMAT: "%B %a %T" 
X
X$$alt.sources
X	BASEDIR: /usenet/alt/sources
X	TYPE: Article-Number
X	LOG: /usenet/alt/sources/log
X        LOG_FORMAT: "%O %S" 
X
X$$alt.sources.amiga
X	BASEDIR: /usenet/alt/sources/amiga
X	TYPE: Article-Number
X	MAIL: rick
X	LOG: /usenet/alt/sources/amiga/log
X        LOG_FORMAT: "%O %S" 
END_OF_FILE
if test 9112 -ne `wc -c <'rkive.cf'`; then
    echo shar: \"'rkive.cf'\" unpacked with wrong size!
fi
# end of 'rkive.cf'
fi
if test -f 'setup.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'setup.c'\"
else
echo shar: Extracting \"'setup.c'\" \(16190 characters\)
sed "s/^X//" >'setup.c' <<'END_OF_FILE'
X/*
X**
X** This software is Copyright (c) 1989 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**  History:
X**	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X**                                                               
X*/
X#ifndef lint
Xstatic char SID[] = "@(#)setup.c	1.1 6/1/89";
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 <dirent.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 = ARTICLE_NUMBER;
Xint default_patch_type = HISTORICAL;
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** 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** 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** index -
X** The location of the master index.
X*/
Xchar index[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
Xchar *strstrip();
Xchar *strchr();
Xchar *strcpy();
Xvoid exit();
Xstruct passwd *getpwnam();
X
Xstruct restricted_dirs {
X    char   *dirstr;            /* path of restricted directory */
X};
X
Xstatic struct restricted_dirs base_dirs[] = {
X{  "/"               },
X{  "/etc"            },
X{  "/dev"            },
X{  "/dev/dsk"        },
X{  "/dev/rdsk"       },
X{  "/lib"            },
X{  "/stand"          },
X{  "/usr/adm"        },
X{  "/usr/spool/uucp" },
X{  NULL              },
X};
X
Xsetup_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_compress();
X    char *get_users();
X    FILE *efopen();
X
X    config = efopen(config_file,"r");
X
X    num = -1; /* initialize group structure index */
X    
X    while (fgets(buffer, sizeof buffer, config) != NULL) {
X        /* ignore comments and blank lines */
X        if (*buffer == '#' || *buffer == '\n') 
X            continue;
X
X        buf = buffer;
X
X        /* strip leading spaces and tabs */
X	while(*buf == ' ' || *buf == '\t')
X             ++buf;
X
X        *(buf+(strlen(buf)-1))  = '\0'; /* remove newline */
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].logfile[0]   = '\0';
X            group[num].index[0]     = '\0';
X            group[num].logformat[0] = '\0';
X            group[num].indformat[0] = '\0';
X            group[num].compress[0]  = '\0';
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 'C': (void) strcpy(compress, get_compress(buf, sp));
X                         break;
X               case 'G': default_group = get_group(buf, sp);
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(index, 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
X                             error(buf, "invalid global assignment");
X                         break;
X               case 'O': default_owner = get_owner(buf, sp);
X                         break;
X               case 'P': if (strncmp(buf, "PROBLEMS", 8) == 0)
X                           (void) strcpy(problems_dir, strstrip(sp));
X                         else 
X                           default_patch_type = get_patch_type("Global",buf,sp);
X                         break;
X               case 'S': get_spooldir(buf, sp);
X                         break;
X               case 'T': default_type = get_archive_type("Global", buf, sp);
X                         break;
X               default : error("invalid global assignment:", 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 'B': if (strncmp(buf, "BASEDIR",7) == 0) 
X                            get_archive_basedir(sp);
X                         break;
X               case 'C': (void)strcpy(group[num].compress,get_compress(buf,sp));
X                         break;
X               case 'G': group[num].group = get_group(buf, sp);
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 
X                             GAG(buf);
X                         break;
X               case 'O': group[num].owner = get_owner(buf, sp);
X                         break;
X               case 'P': group[num].patch_type = get_patch_type(group[num].ng_name,buf,sp);
X                         break;
X               case 'T': group[num].type = get_archive_type(group[num].ng_name, buf, sp);
X                         break;
X               default : error("invalid group assignment:", buf);
X            }
X        }
X        else /* no idea what it is */
X            error("unknown line type", buf);
X    }
X    (void) fclose(config);
X}
X
Xerror(msg1,msg2)
X   char *msg1;
X   char *msg2;
X{
X    (void) fprintf(errfp,"%s: %s %s\n",progname,msg1, msg2);
X    exit(1);
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
Xget_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
Xchar *get_compress(buffer,cmd)
Xchar *buffer;
Xchar *cmd;
X{
X    static char *rp;
X
X    if (!valid_variable(buffer, "COMPRESS", 8))
X        return(NULL);
X    
X    rp = strstrip(cmd);
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 COMPRESS -", rp);
X
X    return(rp);
X}
X        
X
Xint get_group(buffer, valstr)
Xchar *buffer;
Xchar *valstr;
X{
X    char *wp;
X    struct group *grent;
X    struct group *getgrnam();
X
X    if (!valid_variable(buffer, "GROUP", 5))
X        return(default_group);
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(buffer, valstr)
Xchar *buffer;
Xchar *valstr;
X{
X    char *wp;
X
X    if (!valid_variable(buffer, "OWNER", 5))
X        return(default_owner);
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, buffer, s)
Xchar *ngname;
Xchar *buffer;
Xchar *s;
X{
X    int return_type;
X
X    if (!valid_variable(buffer, "TYPE", 4))
X        return(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, "Article-Number") == 0) 
X        return_type = ARTICLE_NUMBER;
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 or %s\n",
X                   "Archive-Name", "Volume-Issue", "Article-Number");
X        exit(1);
X    }
X
X    return(return_type);
X}
X
Xint valid_variable(buffer, variable, length)
Xchar *buffer;
Xchar *variable;
Xint length;
X{
X    if (strncmp(buffer, variable, length) != 0) {
X        GAG(buffer);
X        return(FALSE);
X    }
X    return(TRUE);
X}
X
X
Xget_spooldir(buffer,s)
Xchar *buffer;
Xchar *s;
X{
X    static char *rp;
X
X    if (!valid_variable(buffer, "SPOOLDIR", 8))
X        (void) strcpy(spooldir, SPOOLDIR);
X
X    else {
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}
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 = NULL;
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        /* check if user is found in passwd file */
X        if ((pwent = getpwnam(name)) != NULL) {
X            if (*users != NULL) {
X                (void) strcat(users, ",");
X                (void) strcat(users, name);
X            }
X            else 
X                (void) strcpy(users, name);
X        }
X        else 
X            error("Invalid user:",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,buffer, s)
Xchar *ngname;
Xchar *buffer;
Xchar *s;
X{
X    int return_type;
X
X    if (!valid_variable(buffer, "PATCHES", 7))
X        return(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,"\tTYPE Must be %s, or %s\n",
X                   "Historical", "Package");
X        exit(1);
X    }
X    return(return_type);
X}
END_OF_FILE
if test 16190 -ne `wc -c <'setup.c'`; then
    echo shar: \"'setup.c'\" unpacked with wrong size!
fi
# end of 'setup.c'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 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

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list