[comp.sources.misc] v17i020: rkive - Usenet sources archiver, Part04/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 20
Archive-name: rkive/part04

#! /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 4 (of 6)."
# Contents:  rkive/ck_name.c rkive/format.c rkive/match.y
#   rkive/nntpart.c rkive/rkive.5
# Wrapped by kent@sparky on Sun Feb 24 16:11:22 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'rkive/ck_name.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/ck_name.c'\"
else
echo shar: Extracting \"'rkive/ck_name.c'\" \(2106 characters\)
sed "s/^X//" >'rkive/ck_name.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#if !defined(lint) && !defined(SABER)
Xstatic char SID[] = "@(#)ck_name.c	2.2 2/23/91";
X#endif
X
X#include <stdio.h>
X/*
X** check_archive_name
X**
X** Assure the path specified is within the base directory
X** specified by the archive administrator by assuring that
X** a prankster could not have an article archived at a
X**     basedir/../../../etc/passwd
X** location.
X**
X** If an absoulte path is specified in the Archive-name, it
X** is of no concern since a "checked" base directory and
X** volume directory are prefixed.
X*/
X
Xvoid check_archive_name(argstr)
X    char *argstr;
X {
X    int strlen();
X    char *substr();
X    register char *rp;
X    register char *dp;
X
X    /* 
X    ** check to assure that the path specified
X    ** does not contain the '..' sequence.
X    */
X
X    while ((rp = substr(argstr, "..")) != NULL) {
X       dp = rp+2;
X       while(*dp)
X           *rp++ = *dp++;
X       *rp = '\0';
X    }
X
X    /* I know this is not necessary but what the heck.. */
X
X    while ((rp = substr(argstr, "//")) != NULL) {
X       dp = rp+2;
X       ++rp;
X       while(*dp)
X           *rp++ = *dp++;
X       *rp = '\0';
X    }
X
X    /* 
X    ** strip the string of trailing '/'s
X    */
X
X    dp = argstr+(strlen(argstr)-1);
X    while(*dp == '/' && dp > argstr)
X        *dp = '\0';
X
X    /*
X    ** Assure that there is no spaces inside
X    ** the archive-name. This is not that uncommon
X    ** alt.sources postings. "X_list/part 3"
X    */
X
X    rp = argstr;
X    while (*rp) {
X       if (*rp == ' ')
X           *rp = '-';
X       ++rp;
X    }
X
X    /*
X    ** lets get rid of leading blanks so
X    ** that "/dev/null" Archive-name: lines
X    ** work as they should... :-)
X    */
X
X    dp = argstr;
X    rp = argstr;
X
X    while(*dp == '/')
X        ++dp;
X
X    while(*dp)
X      *rp++ = *dp++;
X    *rp = '\0';
X}
END_OF_FILE
if test 2106 -ne `wc -c <'rkive/ck_name.c'`; then
    echo shar: \"'rkive/ck_name.c'\" unpacked with wrong size!
fi
# end of 'rkive/ck_name.c'
fi
if test -f 'rkive/format.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/format.c'\"
else
echo shar: Extracting \"'rkive/format.c'\" \(15279 characters\)
sed "s/^X//" >'rkive/format.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#if !defined(lint) && !defined(SABER)
Xstatic char SID[] = "@(#)format.c	2.2 2/23/91";
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "article.h"
X#include "rkive.h"
X
Xint strlen();
X
Xextern FILE *errfp;
Xextern struct group_archive *newsgrp;
X
X#ifdef RKIVE
X  extern char *config_file;
X  extern char problems_dir[];
X  extern char spooldir[];
X  extern char compress[];
X  extern char log[];
X  extern char log_format[];
X  extern char mindex[];
X  extern char index_format[];
X  extern char mail[];
X  extern char checkhash[];
X  extern char arch_command[];
X  extern int default_type;
X  extern int default_patch_type;
X  extern int default_owner;
X  extern int default_group;
X  extern int default_modes;
X# ifdef NNTP
X    extern char nntp[];
X# endif /*NNTP*/
X#endif /* RKIVE */
X
X
X/*
X** substr:
X**
X** substr(str, substr) returns a pointer to the first place in
X** str where the substring substr occurs, or NULL if substr does
X** not occur in str.
X**
X** char *substr(str, substr) char *str, *substr; { return (str); }
X*/
X
Xchar *substr(from, find)
X    char *from, *find;
X{
X    int strncmp();
X    char *strchr();
X
X    register char *sp, *np;
X    register int len;
X
X    np = from;
X    len = strlen(find);
X
X    while ((sp = strchr(np,*find)) != NULL) {
X        if (strlen(sp) < len)
X            break;
X        if (strncmp(sp,find,len) == 0) 
X            return(sp);
X        np = sp + 1;
X    }
X    return(NULL);
X}
X
Xchar *itoa(n)
Xint n;
X{
X    static char str[20];
X
X    int i, c, j, sign;
X	
X    if ((sign = n) < 0) 
X	n = -n;
X
X    i = 0;
X    do {
X        str[i++] = n % 10 + '0';
X    } while ((n /= 10) > 0);
X
X    if (sign < 0)
X        str[i++] = '-';
X    str[i] = '\0';
X
X    for (i = 0, j = strlen(str)-1; i < j; i++,j--) {
X        c = str[i];
X        str[i] = str[j];
X        str[j] = c;
X    }
X    return(str);
X}
X
Xchar *add_string(ptr, member_str)
Xchar *ptr, *member_str;
X{
X    while(*member_str)
X        *ptr++ = *member_str++;
X    return(ptr);
X}
X
X
Xchar *basename(name)
X    char *name;
X{
X    char *p;
X    char *strrchr();
X    
X    if ((p = strrchr(name,'/')) == NULL)
X        return(name);
X    return(++p);
X}
X
X
Xchar *format_output(frmptr, filename, called_from)
Xchar *frmptr;          /* Selection Format pointer              */
Xchar *filename;        /* File name the info came from          */
Xint called_from;       /* Where called from, Rkive or Article   */
X{
X    char *basename();
X
X    static char format[4*BUFSIZ];
X    register char *aptr;
X    register char *cp;
X    char c;
X 
X    /* Did the user specify a format to use   */
X    /* or should the default format be used ? */
X
X    if (frmptr == NULL) {
X       if (called_from == ARCHIVE) 
X           (void) sprintf(format,"%-s\t%-s\t%s",
X                 article.newsarticle, header.archive_name,
X                 article.description);
X       else
X           (void) sprintf(format,"%-s\t%-s", filename, header.subject);
X       return(format);
X    }
X
X    for (cp = format; cp < format + sizeof(format); cp++)
X         *cp = '\0';
X 
X    aptr = frmptr;
X    cp = format;
X
X    while ((c = *aptr++)) {
X        if (c == '%') {
X           switch (*aptr++) {
X               case '%':
X                   *cp++ = '%';
X                   continue;
X               case 'A':     /* Approved  */
X                   cp = add_string(cp, header.approved);
X                   continue;
X               case 'B':     /* Base name of the file path  */
X                   cp = add_string(cp, basename(filename));
X                   continue;
X               case 'C':     /* Control  */
X                   cp = add_string(cp, header.ctlmsg);
X                   continue;
X               case 'D':     /* Date */
X                   cp = add_string(cp, header.subdate);
X                   continue;
X               case 'E':     /* Reposted-by */
X                   cp = add_string(cp, header.reposter);
X                   continue;
X               case 'F':     /* From */
X                   cp = add_string(cp, header.from);
X                   continue;
X               case 'G':     /* newGroups disk location */
X                   /*
X                   ** The newsgroup selected and displayed is the first
X                   ** newsgroup encountered unless the calling routine 
X                   ** is rkive. This is necessary to support rkive's
X                   ** needs when the newsgroup is known ahead of time
X                   ** and article's need to display just what the news article
X                   ** contains. If this is not done then the index information
X                   ** mailed to the specified users may display a crossposted
X                   ** newsgroup as an information line. KLUDGE ALERT!!!
X                   */
X                   if (called_from == ARCHIVE) 
X                       cp = add_string(cp, newsgrp->ng_name);
X                   else
X                       cp = add_string(cp, article.newsgroup);
X                   continue;
X               case 'H':     /* Original-posting-by */
X                   cp = add_string(cp, header.orig_poster);
X                   continue;
X               case 'I':     /* Original-subject */
X                   cp = add_string(cp, header.orig_subject);
X                   continue;
X               case 'J':     /* Archive-directory */
X                   cp = add_string(cp, header.archive_dir);
X                   continue;
X               case 'K':     /* Keywords  */
X                   cp = add_string(cp, header.keywords);
X                   continue;
X               case 'L':     /* Lines */
X                   cp = add_string(cp, header.numlines);
X                   continue;
X               case 'M':     /* Message-ID */
X                   cp = add_string(cp, header.ident);
X                   continue;
X               case 'N':     /* Newsgroups */
X                   cp = add_string(cp, header.nbuf);
X                   continue;
X               case 'O':     /* Actual Archived filename */
X                   cp = add_string(cp, filename);
X                   continue;
X               case 'P':     /* Path */
X                   cp = add_string(cp, header.path);
X                   continue;
X               case 'Q':     /* Expires  */
X                   cp = add_string(cp, header.expdate);
X                   continue;
X               case 'R':     /* References */
X                   cp = add_string(cp, header.references);
X                   continue;
X               case 'S':     /* Subject */
X                   cp = add_string(cp, header.subject);
X                   continue;
X               case 'T':     /* Subject Topic */
X                   cp = add_string(cp, article.description);
X                   continue;
X               case 'V':     /* Volume-Issue article filename  */
X                   cp = add_string(cp, article.filename);
X                   continue;
X               case 'W':     /* Architecture */
X                   cp = add_string(cp, header.architecture);
X                   continue;
X               case 'X':     /* Version-number */
X                   cp = add_string(cp, header.version_number);
X                   continue;
X               case 'a':     /* Archive-name */
X                   cp = add_string(cp, header.archive_name);
X                   continue;
X               case 'b':     /* Submitted-by */
X                   cp = add_string(cp, header.submitted_by);
X                   continue;
X               case 'c':     /* Supersedes  */
X                   cp = add_string(cp, header.supersedes);
X                   continue;
X               case 'd':     /* Distribution  */
X                   cp = add_string(cp, header.distribution);
X                   continue;
X               case 'e':     /* Environment  */
X                   cp = add_string(cp, header.environment);
X                   continue;
X               case 'f':     /* Followup-to  */
X                   cp = add_string(cp, header.followup_to);
X                   continue;
X               case 'h':     /* X-Checksum-Snefru  */
X                   cp = add_string(cp, header.x_checksum_snefru);
X                   continue;
X               case 'i':     /* issue (if archive) */
X                   cp = add_string(cp,itoa(article.issue));
X                   continue;
X               case 'l':     /* Author's logon address */
X                   cp = add_string(cp, article.author_signon);
X                   continue;
X               case 'n':     /* Author's name */
X                   cp = add_string(cp, article.author_name);
X                   continue;
X               case 'o':     /* Organization */
X                   cp = add_string(cp, header.organization);
X                   continue;
X               case 'p':     /* Posting-number */
X                   cp = add_string(cp, header.posting_num);
X                   continue;
X               case 'r':     /* Reply-to */
X                   cp = add_string(cp, header.replyto);
X                   continue;
X               case 's':     /* Sender  */
X                   cp = add_string(cp, header.sender);
X                   continue;
X               case 't':     /* Patch-To  */
X                   cp = add_string(cp, header.patch_to);
X                   continue;
X               case 'u':     /* Summary */
X                   cp = add_string(cp, header.summary);
X                   continue;
X               case 'v':     /* volume (if archive) */
X                   cp = add_string(cp,itoa(article.volume));
X                   continue;
X               case 'w':     /* Archive-site */
X                   cp = add_string(cp,header.archive_site);
X                   continue;
X               case 'x':     /* Xref */
X                   cp = add_string(cp, header.xref);
X                   continue;
X	       case 'y':     /* Archive */
X		   cp = add_string(cp, header.archive);
X		   continue;
X               default:
X                  (void) fprintf(errfp, "invalid format - %c\n", *--aptr);
X                  exit(2);
X           }    /* end switch */
X        }
X        else if (c == '\134') {
X           switch (*aptr++) {
X               case 'n':
X                   *cp++ = '\n';
X                   continue;
X               case 't':
X                   *cp++ = '\t';
X                   continue;
X           }
X        }
X
X#ifdef RKIVE
X        else if (c == '$') {
X           switch (*aptr++) {
X               /*
X               **  The GLOBAL information 
X               */
X               case 'B':     /* BASEDIR */
X                   cp = add_string(cp,newsgrp->location);
X                   continue;
X               case 'E':     /* PROBLEMS - errors */
X                   cp = add_string(cp,problems_dir);
X                   continue;
X               case 'I':     /* INDEX */
X                   cp = add_string(cp, mindex);
X                   continue;
X               case 'J':     /* INDEX_FORMAT */
X                   cp = add_string(cp, index_format);
X                   continue;
X               case 'K':     /* LOG_FORMAT */
X                   cp = add_string(cp, log_format);
X                   continue;
X               case 'L':     /* LOG */
X                   cp = add_string(cp, log);
X                   continue;
X               case 'P':     /* actual disk path to file to archive */
X                   cp = add_string(cp,spooldir);
X                   cp = add_string(cp,"/");
X                   cp = add_string(cp,newsgrp->ng_path);
X                   cp = add_string(cp,"/");
X                   cp = add_string(cp, basename(filename));
X                   continue;
X               case 'S':     /* SPOOLDIR */
X                   cp = add_string(cp,spooldir);
X                   continue;
X		case 'U':     /* MAIL - users */
X                   cp = add_string(cp,mail);
X                   continue;
X               /*
X               **  Now the newgroup specific information 
X               */
X               case 'a':     /* newsgroup's .archived file path */
X                   cp = add_string(cp, newsgrp->arc_done);
X                   continue;
X               case 'b':     /* newsgroup's spool directory */
X                   cp = add_string(cp, newsgrp->ng_path);
X                   continue;
X               case 'c':     /* COMPRESS: */
X                   if (*newsgrp->compress)
X                       cp = add_string(cp, newsgrp->compress);
X                   else
X                       cp = add_string(cp, compress);
X                   continue;
X               case 'g':     /* GROUP: */
X                   cp = add_string(cp,itoa(newsgrp->group));
X                   continue;
X               case 'h':     /* CHECKHASH: */
X                   if (*newsgrp->checkhash)
X                       cp = add_string(cp, newsgrp->checkhash);
X                   else
X                       cp = add_string(cp, checkhash);
X                   continue;
X               case 'i':     /* INDEX: */
X                   cp = add_string(cp, newsgrp->index);
X                   continue;
X               case 'j':     /* INDEX_FORMAT: */
X                   cp = add_string(cp, "'");
X                   cp = add_string(cp, newsgrp->indformat);
X                   cp = add_string(cp, "'");
X                   continue;
X               case 'k':     /* LOG_FORMAT: */
X                   cp = add_string(cp, "'");
X                   cp = add_string(cp, newsgrp->logformat);
X                   cp = add_string(cp, "'");
X                   continue;
X               case 'l':     /* LOG: */
X                   cp = add_string(cp, newsgrp->logfile);
X                   continue;
X               case 'm':     /* MODE: */
X                   {
X                     char octal_str[20];
X                     (void) sprintf(octal_str,"%o",newsgrp->modes);
X                     cp = add_string(cp,octal_str);
X                     continue;
X                   }
X               case 'n':     /* $$newsgroup name */
X                   cp = add_string(cp,newsgrp->ng_name);
X                   continue;
X               case 'o':     /* OWNER: */
X                   cp = add_string(cp,itoa(newsgrp->owner));
X                   continue;
X               case 'p':     /* PATCHES: */
X                   if (newsgrp->patch_type == PACKAGE)
X                       cp = add_string(cp, "Package");
X                   else
X                       cp = add_string(cp, "Historical");
X                   continue;
X                case 'u':     /* MAIL: - users */
X                   cp = add_string(cp,newsgrp->mail_list);
X                   continue;
X#ifdef NNTP
X               case 'N':     /* NNTP */
X                   /* print out according to precedence. */
X                   if (*newsgrp->nntp)
X                       cp = add_string(cp,newsgrp->nntp);
X                   else if (*nntp)
X                       cp = add_string(cp,nntp);
X                   continue;
X#endif /* NNTP */
X               default:
X                  (void) fprintf(errfp, "invalid format - %c\n", *--aptr);
X                  exit(2);
X           }
X        }
X#endif /* RKIVE */
X
X        *cp++ = c;
X     }  /* end while */
X     return(format);
X}
END_OF_FILE
if test 15279 -ne `wc -c <'rkive/format.c'`; then
    echo shar: \"'rkive/format.c'\" unpacked with wrong size!
fi
# end of 'rkive/format.c'
fi
if test -f 'rkive/match.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/match.y'\"
else
echo shar: Extracting \"'rkive/match.y'\" \(9346 characters\)
sed "s/^X//" >'rkive/match.y' <<'END_OF_FILE'
X%{
X
X/*
X** Copyright Heikki Suonsivu 1989
X**
X** Kent, you owe me a beer, if you use it and meet me some day. No other
X** limitations. You can use, sell, put your name in it, print it out and
X** eat the printout, or use it any other way. I take no responsibility
X** for the consequences.
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#if !defined(lint) && !defined(SABER)
Xstatic char SID[] = "@(#)match.y	2.2 2/23/91";
X#endif
X
X#define YYDEBUG 1
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#include "rkive.h"
X#include "article.h"
X
Xextern FILE *logfp;
Xextern FILE *errfp;
Xextern int yydebug;
Xint parser_return_value;
X
X%}
X
X%union {
X  int integer;
X  char *string;
X  char *header;	/* Must be different for parser, no "" around header names */
X}
X
X%token <string> STRING
X%token <header> HEADER
X%left OR AND
X%left NOT
X%left INCLUDES GLOB_MATCHES
X%type <integer> exp
X  
X/* Tries to understand some expressions. */
X%%
X
Xexpression:	/* Empty */	{ return 1; } /* Empty always matches */
X|	exp	{ parser_return_value = $1; }
X  
Xexp:	exp OR exp	{ $$ = $1 || $3; }
X|	exp AND exp	{ $$ = $1 && $3; }
X|	NOT exp	{ $$ = ! $2; }
X|	'(' exp ')'	{ $$ = $2; }
X|	HEADER INCLUDES STRING	{ $<integer>$ = substr($1, $3); }
X|	STRING INCLUDES HEADER	{ $<integer>$ = substr($1, $3); }
X|	HEADER GLOB_MATCHES STRING { $<integer>$ = match_str($1, $3); }
X%%
X
Xtypedef struct {
X  char *keyword;
X  int key;
X} KEYWORD;
X
XKEYWORD keys[] = {
X  "and", AND,
X  "or", OR,
X  "includes", INCLUDES,
X  "glob-matches", GLOB_MATCHES,
X  "not", NOT,
X  NULL, 0
X  };
X
XKEYWORD headers[] = {
X  "from", FROM,
X  "path", PATH,
X  "newsgroup", NEWSGROUP,
X  "subject", SUBJECT,
X  "message-id", MSG_ID,
X  "reply-to", REPLY_TO,
X  "references", REFERENCES,
X  "date", DATE,
X  "expire", EXPIRE,
X  "control", CONTROL,
X  "sender", SENDER,
X  "followup-to", FOLLOWUP_TO,
X  "distribution", DISTRIBUTION,
X  "organization", ORGANIZATION,
X  "numlines", NUMLINES,
X  "keywords", KEYWORDS,
X  "summary", SUMMARY,
X  "approved", APPROVED,
X  "supersedes", SUPERSEDES,
X  "xref", XREF,
X  "posting-number", POSTING_NUMBER,
X  "submitted-by", SUBMITTED_BY,
X  "archive-name", ARCH_NAME,
X  "articleid", ARTICLEID,
X  "patch-to", PATCH_TO,
X  "environment", ENVIRONMENT,
X  NULL, 0
X  };
X
X/* Global, copy matching-expression here, then call yyparse */
X
Xchar inputstring[MAXMATCHLEN];
X
X/* Parser for expression */
X
Xyylex()
X{
X  static char input_buffer[MAXMATCHLEN];
X  static char string_buffer[MAXMATCHLEN];
X  static char *p;
X  register char *s, *string;
X  register KEYWORD *keyword;
X  
X  if (*inputstring) {
X      if (strlen(inputstring) >= MAXMATCHLEN) {
X          (void) fprintf(logfp, "Match string too long, max %d characters",
X		       MAXMATCHLEN);
X          exit (1);
X      }
X	  
X      (void) strcpy(input_buffer, inputstring);
X      p = input_buffer;
X      *inputstring = 0;	/* We got it */
X  }
X
X  /* Skip whitespace separating tokens */
X  
X  while (*p && isspace(*p)) p++;
X  
X  if (!*p) {
X      if (yydebug) 
X          (void) fprintf(logfp, "yylex: return eof\n");
X      return 0; /* Eof */
X  }
X
X  if (*p == '"') {
X      string = string_buffer;
X      
X      /* Collect the string, try to be intelligent with escaped '"'.
X      ** Trailing " is not needed. 
X      */
X      
X      for (p++; *p && *p != '"'; p++) {
X	if (*p == '\\') {
X	    *string++ = *p++;
X	    if (*p) *string++ = *p; /* Skip the next char, whatever it is */
X	}
X	else
X	  *string++ = *p;
X      }
X
X      p++; /* Disgard trailing '"' */
X      
X      *string = 0;
X
X      yylval.string = string_buffer;
X      if (yydebug) 
X         (void) fprintf(logfp, "yylex: return string <%s>\n", string_buffer);
X      return STRING;
X  }
X  else if (isalpha(*p)) {
X      string = string_buffer;
X
X      /* Collect keyword/header */
X
X      for (; *p && (isalpha(*p) || !isspace(*p)); p++)
X	*string++ = isupper(*p) ? tolower(*p) : *p;
X      
X      *string = 0;
X      
X      /* Any of the operands? */
X  
X      for (keyword = keys; keyword->keyword; keyword++) {
X	if (!strcmp(keyword->keyword, string_buffer)) {
X	    if (yydebug)
X                (void) fprintf(logfp, "yylex: return keyword %d (%s)\n",
X				 keyword->key, keyword->keyword);
X	    return keyword->key;
X	}
X      }
X      
X      /* A header? */
X      
X      for (keyword = headers; keyword->keyword; keyword++)
X	if (!strcmp(keyword->keyword, string_buffer)) {
X	    yylval.header = header.header[keyword->key];
X	    if (yydebug) 
X                (void) fprintf(logfp, "yylex: return header %s <%s>\n",
X				 keyword->keyword, yylval.header);
X	    return HEADER;
X	}
X
X      /* Nope, maybe its a string without "". Note, it converts
X	 the string to lower-case. */
X
X      yylval.string = string_buffer;
X      if (yydebug) 
X          (void) fprintf(logfp,"yylex: return unquoted string <%s>\n",string_buffer);
X      return STRING;
X  }
X  else if (strchr("()", *p))
X    return *p++;
X  else {
X      if (yydebug) 
X          (void) fprintf(logfp, "yylex: Bad character '%c'\n", *p);
X      return 0; /* Eof, could be something else, but I'm too tired now */
X  }
X    /* Never here... (?) */
X}
X      
Xyyerror(s)
X     char *s;
X{
X  (void) fprintf(errfp,"Cannot parse match pattern: %s\n",s);
X  exit (1);
X}
X
X/*
X** int match_str( char *string, char *format ) {  return(0); }
X**
X** Search the "string" to see if it matches the format specified.
X** 
X** The characters `[', `]', `*', `?', `^', `-', and `\' are considered
X** special metacharacters and have the following meanings...
X**    `*'   matches any set of characters,
X**    `?'   matches any one character,
X**   [..]   matches any character specified in the brackets,
X**   [^..]  matches any character that is *not* specified in the brackets.
X**          The use of the brackets is suppose to work in much the same
X**          manner as the shell in that you can use [a-z] notation as well.
X** 
X** If there is a need to match one of the special metacharacters characters
X** the character must be prefixed with a backslash (`\') to negate its 
X** special meaning.
X** 
X** This function returns 1 if there is a match and 0 otherwise.
X** 
X*/ 
X
Xint match_str(string, format)
Xchar *string;
Xchar *format;
X{
X   register char *s = string;
X   register char *f = format;
X   register char ch;
X   register char nextch;
X   register int negate;
X
X   while ((ch = *f++)) {
X       switch (ch) {
X           case '*':
X                  /*
X                  ** Now let's match against what is left...
X                  */
X     
X                  while ((ch = *f++) == '?' || ch == '*') {
X                     if (ch == '?' && *s++ == 0)
X                        return 0;
X                  }
X     
X                  if (ch == 0)   /* at the end of the format ? */
X                     return 1;
X     
X                  if (ch == '\\') 
X                      nextch = *f;
X                  else
X                      nextch = ch;
X     
X                  for (;;) {
X                     if ((ch == '[' || *s == nextch)) {
X                         if (match_str (s, f - 1))
X                            return 1;
X                     }
X                     if (*s++ == 0)
X                        return 0;
X                  }
X     
X           case '?':
X              if (!*s)
X                  return 0;
X              else
X                  ++s;
X              break;
X
X           case '\\':
X                 if (*f++ != *s++) 
X                     return 0;
X                 break;
X     
X           case '[':
X                 nextch = *s++;
X     
X                 if (*f == '^') {
X                     negate = 1;
X                     f++;
X                 }
X                 else
X                     negate = 0;
X     
X                 for(ch = *f++;;) {
X                    register char sp = ch, rp = ch;
X
X                    sp = ch;
X                    rp = ch;
X     
X                    if (ch == '\\') {
X                       sp = *f++; 
X                       rp = sp;
X                    }
X     
X                    if (!ch)
X                        return (0);
X     
X                    ch = *f++;
X     
X                    if (ch == '-') {
X                       rp = *f++;
X                       if (rp == '\\')
X                          rp = *f++;
X                       if (!rp)
X                          return (0);
X                       ch = *f++;
X                    }
X                    if (nextch >= sp && nextch <= rp) {
X                       /*
X                       ** Ignore the rest of [...] previously matched.  
X                       */
X                       while (ch != ']') {
X                          if (!ch || !(ch = *f++)) 
X                              return (0);
X                          if (ch == '\\') 
X                              f++;
X                       }
X                       if (negate) 
X                           return 0;
X                    }
X                    if (ch == ']')
X                       break;
X                 }
X                 if (!negate) 
X                    return 0;
X                 break;
X              
X           default:
X              if (ch != *s++)
X                  return 0;
X              break;
X       }
X   }
X   return(*s ? 0 : 1); 
X}
END_OF_FILE
if test 9346 -ne `wc -c <'rkive/match.y'`; then
    echo shar: \"'rkive/match.y'\" unpacked with wrong size!
fi
# end of 'rkive/match.y'
fi
if test -f 'rkive/nntpart.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/nntpart.c'\"
else
echo shar: Extracting \"'rkive/nntpart.c'\" \(8989 characters\)
sed "s/^X//" >'rkive/nntpart.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 = "@(#)nntpart.c	2.1 2/21/91";
X#endif
X
X/*LINTLIBRARY*/
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <nntp.h>
X#include "cfg.h"
X
X#define TMPDIR "/usr/tmp"
X
Xchar *nntp_server;
X
Xint     server_init();
Xvoid    put_server();
Xint     get_server();
Xvoid    close_server();
X
Xint atoi();
Xint fputs();
X
Xextern int verbose;
X
X/*
X *
X * First digit:
X *
X *	1xx	Informative message
X *	2xx	Command ok
X *	3xx	Command ok so far, continue
X *	4xx	Command was correct, but couldn't be performed
X *		for some specified reason.
X *	5xx	Command unimplemented, incorrect, or a
X *		program error has occured.
X *
X * Second digit:
X *
X *	x0x	Connection, setup, miscellaneous
X *	x1x	Newsgroup selection
X *	x2x	Article selection
X *	x3x	Distribution
X *	x4x	Posting
X */
X
Xstruct nntp_resp {
X    int     resp;
X    char    *msg;
X};
X
Xstruct nntp_resp resps[] = {
X{	INF_HELP,	"Help text on way"			},
X{	INF_DEBUG,	"Debug output"				},
X{	OK_CANPOST,	"Hello; you can post"			},
X{	OK_NOPOST,	"Hello; you can't post"			},
X{	OK_SLAVE,	"Slave status noted"			},
X{	OK_GOODBYE,	"Closing connection"			},
X{	OK_GROUP,	"Group selected"			},
X{	OK_GROUPS,	"Newsgroups follow"			},
X{	OK_ARTICLE,	"Article (head & body) follows"		},
X{	OK_HEAD,	"Head follows"				},
X{	OK_BODY,	"Body follows"				},
X{	OK_NOTEXT,	"No text sent -- stat, next, last"	},
X{	OK_NEWNEWS,	"New articles by message-id follow"	},
X{	OK_NEWGROUPS,	"New newsgroups follow"			},
X{	OK_XFERED,	"Article transferred successfully"	},
X{	OK_POSTED,	"Article posted successfully"		},
X{	CONT_XFER,	"Continue to send article"		},
X{	CONT_POST,	"Continue to post article"		},
X{	ERR_GOODBYE,	"Have to hang up for some reason"	},
X{	ERR_NOGROUP,	"No such newsgroup"			},
X{	ERR_NCING,	"Not currently in newsgroup"		},
X{	ERR_NOCRNT,	"No current article selected"		},
X{	ERR_NONEXT,	"No next article in this group"		},
X{	ERR_NOPREV,	"No previous article in this group"	},
X{	ERR_NOARTIG,	"No such article in this group"		},
X{	ERR_NOART,	"No such article at all"		},
X{	ERR_GOTIT,	"Already got that article, don't send"	},
X{	ERR_XFERFAIL,	"Transfer failed"			},
X{	ERR_XFERRJCT,	"Article rejected, don't resend"	},
X{	ERR_NOPOST,	"Posting not allowed"			},
X{	ERR_POSTFAIL,	"Posting failed"			},
X{	ERR_COMMAND,	"Command not recognized"		},
X{	ERR_CMDSYN,	"Command syntax error"			},
X{	ERR_ACCESS,	"Access to server denied"		},
X{	ERR_FAULT,	"Program fault, command not performed"	},
X{	-1,	        NULL					},
X};
X
Xchar *get_nntpstr(resp_line,number)
X    char *resp_line;
X    int *number;
X {
X    struct nntp_resp *ct;
X
X    *number = atoi(resp_line);
X
X    ct = &resps[0];
X    while ((ct->resp) != -1) {
X        if (*number == ct->resp)
X            return(ct->msg);
X        ct++;
X    }
X    return(NULL);
X}
X
Xvoid print_server_response(line)
Xchar *line;
X{
X	int rrc;
X	static char *str;
X
X        /*
X        ** Verify the first character as a valid response code.
X        */
X        if ((*line != CHAR_INF) && (*line != CHAR_OK) 
X            && (*line != CHAR_CONT) && (*line != CHAR_ERR)
X            && (*line != CHAR_FATAL))  {
X            (void) fprintf(logfp,"[%s]: Xxx : unknown response\n",line);
X            return;
X        }
X
X        /*
X        ** Verify the last two characters are 
X        ** within range of valid responses.
X        */
X        
X        if ((*(line+1) < '0') || (*(line+1) > '9')) {
X            (void) fprintf(logfp,"[%s]: xXx : unknown response\n",line);
X            return;
X        }
X        if ((*(line+2) < '0') || (*(line+2) > '9')) {
X            (void) fprintf(logfp,"[%s]: xxX : unknown response\n",line);
X            return;
X        }
X
X        if ((str = get_nntpstr(line,&rrc)) != NULL) 
X            (void) fprintf(logfp,"%d: %s\n", rrc, str);
X        else
X            (void) fprintf(logfp,"%d: unknown response\n", rrc);
X
X        /* If the response in within a range (190-199) it is not handled.. */
X        /* fix later, I am too lazy now....*/
X        return;
X}
X
X
Xint nntp_retrieve_article(filename,which_time)
Xchar *filename;
Xint which_time;
X{
X     int sscanf();
X     int fclose();
X     int chdir();
X
X     char buf[256];
X     char ser_line[512];
X     int  response;
X     int  rc;               /* response code */
X     FILE *tfp;             /* transfer file pointer */ 
X     static int n;          /* extimated number of articles */
X     static int f;          /* first article number */
X     static int l;          /* last article number */
X   
X     if (which_time == 1) {
X         if (chdir(TMPDIR) != 0) {
X             (void) fprintf(errfp,"can't cd to %s.\n",TMPDIR);
X             return(ERROR_ENCOUNTERED);
X         }
X
X         /* 
X         ** Need to establish the connection with the nntp_server.
X         */
X
X         if ((response = server_init(nntp_server)) < 0) {
X             (void) fprintf(errfp,"can't connect to %s.\n",nntp_server);
X             return(ERROR_ENCOUNTERED);
X         }
X
X         /* 
X         ** Assure that the connection succeeded...
X         */
X
X         if (response == ERR_ACCESS) {
X             (void) fprintf(errfp,
X                       "Connection permission to the %s news server denied.\n",
X                       nntp_server);
X             return(ERROR_ENCOUNTERED);
X         }
X         else if ((response != OK_NOPOST) && (response != OK_CANPOST)) {
X             (void) fprintf(errfp,
X                       "Unexpected response code from %s news server: %d\n",
X                       nntp_server, response);
X             return(ERROR_ENCOUNTERED);
X         }
X
X         /* 
X         ** Need to tell the server which newsgroup to process.
X         */
X
X         (void) sprintf(buf,"GROUP %s", newsgrp->ng_name);
X         put_server(buf);    /* tell server we want to select the group */
X
X         if (get_server(ser_line, sizeof(ser_line)) < 0) {
X             (void) fprintf(errfp,
X               "Unexpected close of %s connection\n", nntp_server);
X             return(ERROR_ENCOUNTERED);
X         }
X
X         if (*ser_line != CHAR_OK) {      /* and then see if that's ok */
X             print_server_response(ser_line);
X             return(ERROR_ENCOUNTERED);
X         }
X
X         /* 
X         ** Get the newsgroup article information from the returned buffer 
X         ** 
X         ** rc    = response code (211 or 411)
X         **  n    = estimated number of articles in group,
X         **  f    = first article number in the group,
X         **  l    = last article number in the group,
X         **  smsg = name of the group.)
X         */
X
X         (void) sscanf(ser_line,"%d%d%d%d%s",  &rc, &n, &f, &l, buf);
X         if (verbose) {
X             print_server_response(ser_line);
X     	     (void) fprintf(logfp,"Newsgroup\t%s\n",buf);
X     	     (void) fprintf(logfp,"First\t%d\tLast \t%d\n",f,l);
X     	     (void) fprintf(logfp,"Est. No. Articles\t%d\n",n);
X         }
X     }
X        
X     while (f <= l) {
X        /* 
X        ** Store the article number as the file name for the
X        ** temporary file transfer. This is mainly to support
X        ** the Article-Number form of archiving.
X        */
X        (void) sprintf(filename,"%d",f);
X
X        /* 
X        ** Build the nntp command string 
X        ** designating which article to transfer.
X        */
X        (void) sprintf(buf,"ARTICLE %ld", f);
X        put_server(buf);    /* tell server we want the article */
X        (void) get_server(ser_line, sizeof(ser_line));
X        if (verbose)
X 	   (void) fprintf(logfp,"Retrieving <%d> from %s\n",f, nntp_server);
X        ++f;
X        if (*ser_line != CHAR_OK) {      /* and then see if that's ok */
X            if ((rc = atoi(ser_line)) != ERR_NOART && rc != ERR_NOARTIG) {
X               if (verbose)
X                  print_server_response(ser_line);
X            }
X            continue;
X        }
X
X        /* 
X        ** Here we have a valid article. Create a temporary file
X        ** to transfer the article from the nntp server to the
X        ** local system into.
X        */
X        if ((tfp = fopen(filename, "w+")) == NULL)
X             return(ERROR_ENCOUNTERED);
X
X        /* 
X        ** Read a line from the server and write it out to
X        ** the file to be used for archiving. This file is
X        ** removed when it is no longer needed.
X        */
X        while (get_server(ser_line, sizeof(ser_line)) >= 0) {  /* while */
X            if (ser_line[0] == '.' && ser_line[1] == '\0')  /* valid input */
X                break;                          /* get it and write it  */
X            (void) fputs(ser_line, tfp);        /* to standard output.  */
X            (void) fputs("\n", tfp);
X        }
X        (void) fclose(tfp);
X        return(RETRIEVED);
X     }
X     close_server();
X     return(DONE);
X}
END_OF_FILE
if test 8989 -ne `wc -c <'rkive/nntpart.c'`; then
    echo shar: \"'rkive/nntpart.c'\" unpacked with wrong size!
fi
# end of 'rkive/nntpart.c'
fi
if test -f 'rkive/rkive.5' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rkive/rkive.5'\"
else
echo shar: Extracting \"'rkive/rkive.5'\" \(15730 characters\)
sed "s/^X//" >'rkive/rkive.5' <<'END_OF_FILE'
X'br "@(#)rkive.5	2.3 2/24/91"
X.TH RKIVE 5
X.SH NAME
Xrkive.cf \- USENET Source Archiver Configuration File.
X.SH DESCRIPTION
X.I rkive.cf
Xallows the administrator to configure the way in which USENET sources
Xare archived.
X.PP
XThe configuration file is used to indicate where the archives are
Xto be located, who will own the archive members, etc. The configuration 
Xfile is divided into two sections, a global section and the individual 
Xnewsgroup specifications.
X.PP
XThe syntax of the individual line types are as follows:
X.RS
X.IP "Global Variable Line"
XVariable = value
X.IP "Newsgroup Identifier"
X$$comp.source.whatever
X.IP "Newsgroup Variable Line"
XVariable : value
X.RE
X.LP
XNote that the '=' is used to designate a global variable and
Xthat the ':' is used to determine a newsgroup variable.
X.PP
XThe global variables are divided up into variables that pertain to
Xall archiving as well as defaults to be used in the event that the
Xarchive administrator has not set a specific value for a "defaultable"
Xvariable.
X.PP
X.SH "GLOBAL VARIABLES"
X.PP
X.IP "SPOOLDIR =" 15
XThis is the base directory for the news subsystem.
X.IP "PROBLEMS ="
XThe name of the base directory used to store any duplicate or "problem"
Xarticles that rkive(1) cannot deal with. All articles are stored under 
Xthis directory in a newsgroup / volume directory structure.
X.IP "LOG ="
XThe location of the master log in which actions are logged. 
XIf this variable is not set, no global logging takes place.
X.IP "LOG_FORMAT ="
XThe format of the records of the master log file.  This variable only
Xpertains to the global log file format. The actual format specification
Xmust be enclosed in "". See article(1) for a discussion of the available 
Xselection format capabilities.
X.IP "INDEX =" 
XThe location of the master index file (if one is to be kept).  The index 
Xcan be used to interface with the netlib source retrieval software facility.
X.IP "INDEX_FORMAT ="
XThe format of the records of the master index file. The actual format
Xspecification must be enclosed in "".   See article(1) for a
Xdiscussion of the available selection format capabilities.
X.IP "MAIL ="
XIf specified, logged actions are mailed to the users listed. 
XThe user names are a comma separated list. It is not necessary to
Xspecify any users. 
X.PP
XThe following values are used if the administrator has not
Xset a value for a corresponding newsgroup configuration item.
X.IP "TYPE =" 15
XThis is the default archive type.  There are 7 possible ways
Xin which to archive USENET sources,
X.PP
X                  Volume-Issue, 
X                  Archive-Name, 
X                  Chronological, 
X                  Article Number,
X                  Comp-Archives,
X                  External-Command or
X                  Only-Archive-Name.
X
X.IP
XThese are used to determine if you wish the articles archived in a 
X.PP
X           /basedir/amiga/Volume1/v001i22 or
X           /basedir/amiga/Volume1/sitonit or
X           /basedir/amiga/Volume89/Jun/890628.01 or
X           /basedir/amiga/Volume1/44 format.
X.IP
XComp-Archives is used only for the comp.archives newsgroup or newsgroups 
Xthat supply Archive-name: but do not supply a volume number. External-Command 
Xis used if you want to have an external program/script deal with the article. 
XThe External-Command type must be accompanied with an ARCHIVE_CMD entry with 
Xspecifies the external program for rkive to use.
X.LP
X.IP "PATCHES =" 15
XThis variable determines the way in which patches are installed into 
Xthe archive. If the PATCHES entry is not defined either globally or within
Xthe newsgroup, the article is handled as a regular article and is stored 
Xaccording to the specified parameters of the newsgroup. The following are
Xthe valid possible values for the PATCHES variable:
X.RS
X.IP "PATCHES=Historical" 6 
XThis is the same as if no PATCHES entry existed at all. It is useful 
Xif Historical patches archiving is the default but there are certain 
Xnewsgroups that have it specified differently.
X.IP "PATCHES=Package"
XPackage patches archiving allows the inbound patch to be placed with 
Xthe directory with the initially posted articles. In this manner
Xall parts and fixes of a package are together making it easier for 
Xsoftware retrieval by uucp requests and mail request facilities
Xsuch as netlib.
X.RE
X.IP "OWNER ="
XThe owner of the archive files after they are stored in the archive.
X.IP "GROUP ="
XThe group ownership of the archive files after they are stored in the archive.
X.IP "MODE ="
XThe default modes of the files residing in the archive.
X.IP "COMPRESS =" 
XThe location of the compression utility if the files are to be reduced.
XIf this variable is specified, it must contain the full path to the command
Xused to perform the compression.
X.IP "CHECKHASH =" 
XThe location of the checkhash utility if the files are to be tested for
Xtransit damage.  Currently, only comp.sources.unix and comp.sources.misc
Xsupports this test with the X-Checksum-Snerfu: header.  If this variable 
Xis specified, it must contain the full path to the command used to perform 
Xthe test.
X.IP "NNTP =" 
XThe location of the NNTP server where the articles are to be archived from. 
XThis can be specified globally if all or most newsgroups are archived
Xfrom a single NNTP server. 
X.IP "ARCHIVE_CMD =" 
XThis is the path to an external command to pass all articles to that are 
Xin need of archiving.  This is used when with the archive specification
XTYPE=External-Command.  This command line may be augmented with variables 
Xspecified in the rkive.cf file. See article.1 for a description of the 
Xformat specification characters available.
X.IP "MATCH =" 
Xrkive allows you to use globbing to determine if an article is to be 
Xarchived or not. This is the specification by which articles must match 
Xto be archived. The match specification may span multiple lines. A \ at 
Xthe end of a line is used to indicate that the specification is continued on 
Xanother line. 
X.PP
XThe following is a sample global variable section.
X.PP
XSPOOLDIR=/usr/spool/news      
X.br
XPROBLEMS=/usenet/problems
X.br
XLOG=/usenet/archive.log
X.br
XLOG_FORMAT= "%O %T %l" 
X.br
XINDEX= /usenet/index
X.br
XINDEX_FORMAT= "%a %T" 
X.br
XMAIL=kent,rick,chris
X.br
XTYPE= Archive-Name
X.br
XPATCHES= Package
X.br
XOWNER=src
X.br
XGROUP=archive
X.br
XMODE=0444
X.br
X#COMPRESS=/usr/local/bin/compress
X.br
X#CHECKHASH=/usr/local/bin/checkhash -s
X.br
X.PP
XIn the above sample, if any of the individual newsgroups had not
Xhad the type of the archive specified, the type would have defaulted
Xto an Archive-Name (if the newsgroup had the auxiliary headers required
Xto support Archive-Name). By default, no compression was to be done. All
Xresults would have been mailed to the accounts of kent, rick and chris.
XIf a newsgroup had not specified the ownership and modes of the destination
Xarchive members, the values specified in the global OWNER, GROUP, and MODE
Xwould have been used.
X.LP
X.SH "NEWSGROUP SPECIFICATIONS"
X.PP
X.PP
XAn individual newsgroup entry is identified by a $$ as the first two
Xcharacters of the line. The name of the newsgroup (in newsgroup format)
Xfollows such as
X.IP
X$$comp.sources.unix		
X.LP
X.IP "BASEDIR :" 15
XThis is the base directory for the archive.
X.IP "LOG :"
XThe location of the log file in which actions are logged. 
XIf this variable is not set, no logging takes place.
X.IP "LOG_FORMAT :"
XThe format of the records of the log file.  The actual format
Xspecification must be enclosed in "".  See article(1) for a 
Xdiscussion of the available selection format capabilities.
X.IP "INDEX :" 
XThe location of the index file (if one is to be kept).  The index can be 
Xused to interface with the netlib source retrieval software facility.
X.IP "INDEX_FORMAT :"
XThe format of the records of the index file.  The actual format
Xspecification must be enclosed in "".  See article(1) for a
Xdiscussion of the available selection format capabilities.
X.IP "MAIL :"
XIf specified, logged actions are mailed to the list of users specified. 
XThe user names are a comma separated list. It is not necessary to
Xspecify any users. 
X.IP "TYPE :" 
XThis is the archive type.  There are 7 possible ways
Xin which to archive USENET sources,
X.PP
X                  Volume-Issue, 
X                  Archive-Name, 
X                  Chronological, 
X                  Article Number,
X                  Comp-Archives,
X                  External-Command or
X                  Only-Archive-Name.
X.IP
XComp-Archives is used only for the comp.archives newsgroup or newsgroups 
Xthat supply Archive-name: but do not supply a volume number. External-Command 
Xis used if you want to have an external program/script deal with the article. 
XThe External-Command type must be accompanied with an ARCHIVE_CMD entry with 
Xspecifies the external program for rkive to use. Only-Archive-Name is used
Xwhen the only articles that should be archived are articles that contain
XArchive-name: lines.  The difference between Comp-Archives and 
XOnly-Archive-Name is that Comp-Archives expects all articles in the newsgroup
Xhave valid Archive-name: header lines and those that do not generate an error 
Xcondition.  Only-Archive-Name usage expects that only a few articles in the 
Xnewsgroup have Archive-name: headers lines and silently ignores those that
Xdo not have the header line.
X.IP "PATCHES :"
XThis variable determines the way in which patches are installed into 
Xthe newsgroup's archive. If the PATCHES entry is not defined either 
Xglobally or within the newsgroup, the article is handled as a regular 
Xarticle and is stored according to the specified parameters of the 
Xnewsgroup. The following are the valid possible values for the 
XPATCHES variable:
X.RS
X.IP "PATCHES: Historical" 6 
XThis is the same as if no PATCHES entry existed at all. It is useful 
Xif Historical patches archiving is the default but there are certain 
Xnewsgroups that have it specified differently.
X.IP "PATCHES: Package"
XPackage patches archiving allows the inbound patch to be placed with 
Xthe directory with the initially posted articles. In this manner
Xall parts and fixes of a package are together making it easier for 
Xsoftware retrieval by uucp requests and mail request facilities
Xsuch as netlib.
X.RE
X.IP "OWNER :"
XThe the owner of the files after they are stored in the archive 
Xdirectory for the newsgroup.
X.IP "GROUP :"
XThe group ownership of the archive files after they are stored in the 
Xarchive directory for the newsgroup.
X.IP "MODE :"
XThe default modes of the files residing in the archive directory.
X.IP "COMPRESS :" 
XThe location of the compression utility if the files are to be reduced.
XIf this variable is specified, it must contain the full path to the command
Xused to perform the compression.
X.IP "CHECKHASH :" 
XThe location of the checkhash utility if the files are to be tested for
Xtransit damage.  Currently, only comp.sources.unix supports this test with
Xthe X-Checksum-Snerfu: header.  If this variable is specified, it must contain
Xthe full path to the command used to perform the test.
X.IP "NNTP :" 
XThe location of the NNTP server where the articles are to be archived from. 
XThis can be specified globally if all or most newsgroups are archived
Xfrom a single NNTP server, or on a by newsgroup basis.  If NNTP is specified 
Xglobally and you wish to archive a newsgroup from your local system, add the 
Xfollowing entry to the newsgroup specifications. 
X.RS
X.IP "NNTP: local"
X.RE
X.IP
XThis tells rkive to negate the global value. Case does not matter in the 
Xspecification of local.
X.IP "ARCHIVED_LOG :"
Xrkive requires that it be able to determine if an article has been previously 
Xarchived. By default, rkive uses a file named .archived ($BASEDIR/.archived) 
Xwhich stores the message-id of the previously archived articles. If it is
Xinconvient to store the .archived file in the base directory of the archive, 
Xa alternate path/location can be specified by the use of ARCHIVED_LOG.
X.IP "PATCHLOG :"
Xrkive writes an entry to a file called .patchlog when it it encounters a 
XPatch-To: line.  By default, rkive uses a file named .patchlog 
X($BASEDIR/.patchlog). If it is inconvient to store the .patchlog file in the 
Xbase directory of the archive, a alternate path/location can be specified
Xby the use of PATHLOG.
X.IP "ARCHIVE_CMD :" 
XThis is the path to an external command to pass all articles to that are 
Xin need of archiving.  This is used when with the archive specification
XTYPE=External-Command.  This command line may be augmented with variables 
Xspecified in the rkive.cf file. The additional format specification characters 
Xthat can be used to build a command line with the information that is configured
Xin the rkive.cf file.  The specification character '$' is used to indicate that
Xthere is a variable that needs to be filled in.  After the $, a character 
Xfollows that indicates the type of information that is to supplied.
XThe indicator characters and their meanings are:
X.IP
X
XGlobal rkive.cf indicator characters:
X.br
X   
XE - PROBLEMS - Path to the problems directory.
X.br
XI - INDEX    - Location of the master index.
X.br
XJ - INDEX_FORMAT - Format of the master index records.
X.br
XK - LOG_FORMAT - Format of the master log file records.
X.br
XL - LOG - Disk location of the master log file.
X.br
XS - SPOOLDIR - Base location of the news subsystem.
X.br
XU - MAIL - List of users to mail messages to.
X.br
X                  
XNewgroup specific indicator characters:
X.br
X                  
Xa - ARCHIVED_LOG - Newsgroup's .archived file path
X.br
XB - BASEDIR - Base directory of the archive.
X.br
Xc - COMPRESS - Path to compression program to be used.
X.br
Xg - GROUP - Group id specified.
X.br
Xh - CHECKHASH - Path to the checkhash utility.
X.br
Xi - INDEX - Location of the newsgroup index.
X.br
Xj - INDEX_FORMAT - Format of newsgroup index records.
X.br
Xk - LOG_FORMAT - Format of newsgroup log file records.
X.br
Xl - LOG - Disk location of the newsgroup log file.
X.br
Xm - MODE - Modes of the archived files.
X.br
Xo - OWNER - Owner of the archived files.
X.br
Xp - PATCHES - Type of patches archiving to be done.
X.br
Xu - MAIL - List of newsgroup users to mail messages to.
X.br
XN - NNTP - NNTP Server Host for the newsgroup.
X.br
X   
XGeneral indicator characters:
X.br
X   
Xb - Newsgroup's spool directory path.
X.br
Xn - Newsgroup name.
X.br
XP - Actual disk path to the file to be archived.
X.br
X.IP "MATCH :" 
Xrkive allows you to use globbing to determine if an article is to be 
Xarchived or not. This is the specification by which articles must match 
Xto be archived. The match specification may span multiple lines. A \ at 
Xthe end of a line is used to indicate that the specification is continued on 
Xanother line. 
X.PP
XA sample entry for comp.sources.unix might look like:
X.PP
X$$comp.sources.unix		
X.br
X	BASEDIR: /usenet/unix 
X.br
X	TYPE: Volume-Issue
X.br
X	PATCHES: Historical
X.br
X	OWNER: kent
X.br
X	GROUP: support
X.br
X	MODE: 0664
X.br
X	INDEX: /usenet/unix/index
X.br
X	INDEX_FORMAT: "%O %a %S" 
X.br
X	COMPRESS: /usr/local/bin/compress
X.br
X	CHECKHASH: /usr/local/bin/checkhash -s
X.br
X	MAIL: kent,bob,sally
X.br
X.PP
XIn the above sample, comp.sources.unix would be archived in /usenet/unix.
XThe individual volume directories would be created there. All files would
Xbe owned by kent and the group support. The files would be writable by the
Xgroup as well as the owner. (Not a smart idea but just for examples sake.)
XLogging is not being done although an index entry is being generated for
Xeach article archived. All files stored in the archive for this newsgroup
Xare to be compressed using the compress program in /usr/local/bin. Mail is
Xsent to kent, bob and sally when the archiving of comp.sources.unix has been
Xcompleted. All files are tested with the checkhash command for validity
Xbefore archiving.
X.SH "SEE ALSO"
Xrkive(1), article(1), ckconfig(1), checkhash(1), snefru(1)
X.LP
END_OF_FILE
if test 15730 -ne `wc -c <'rkive/rkive.5'`; then
    echo shar: \"'rkive/rkive.5'\" unpacked with wrong size!
fi
# end of 'rkive/rkive.5'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
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.