[comp.sources.bugs] rkive patch01 - part 1 of 2

kent@ssbell.UUCP (Kent Landfield) (07/17/89)

 This is the first of a two (*2*) part patch to rkive, the "Usenet Sources
 Archiver". Rkive now supports archiving of non-sources groups better by the
 addition of Chronological archiving. It fixes some portability problems
 and few irratating "oops". :-)
              **** WARNING ******* WARNING ****
 The format of the .patchlog changed in this patch. The reason being, the 
 Patch-To: auxiliary header line was finally "nailed down" and now includes 
 the package name in it. See the README for additional info about Patch-To:
 and the .patchlog.

 *Please* assure that you have both parts since they constitute one 
 (*1*) complete patch.

 Credits:
 I want to thank the following people for their help with ideas
 and supplied bug fixes. 

     Brandon Allbery      - allbery@uunet
     Scott Anderson       - scott@Questar.MN.ORG
     Jonathan Bayer       - jbayer@ispi
     Mathieu Federspiel   - mcf@statware
     Axel Fischer         - fischer@utower
     Steven Grady         - grady@ucbvax
     Michael R. Johnston  - mikej@lilink
     Michael Kent         - mike@aleytys
     Jens Kjerte          - jk@dde.dk
     Chris Lewis          - clewis@eci386
     Robert Nelson        - robert@sysint
     Mark Peek            - mark@imagen
     Dave Rand            - dlr@daver
     Bill Randle          - billr@saab.CNA.TEK.COM
     Wayne Schlitt        - wayne@dsndata
     Jos Vos              - jos@idca.tds.PHILIPS.nl
     Andrew Worsley       - worsley@ditmela.oz.au

 Thanks again!

        As always, if you have problems or ideas, I'll
	be here... :-)
			-Kent+

------------  Cut, snip, rip, tear, slice, dice ... -------------
#! /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 1 (of 2)."
# Contents:  Patch1-p2of2
# Wrapped by kent@ssbell on Sun Jul 16 16:20:26 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Patch1-p2of2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Patch1-p2of2'\"
else
echo shar: Extracting \"'Patch1-p2of2'\" \(44988 characters\)
sed "s/^X//" >'Patch1-p2of2' <<'END_OF_FILE'
X*** O.news_arc.c	Fri Jul 14 21:30:34 1989
X--- news_arc.c	Sun Jul 16 13:42:51 1989
X***************
X*** 11,19 ****
X  **  History:
X  **	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X  **                                                               
X  */
X  #ifndef lint
X! static char SID[] = "@(#)news_arc.c	1.1 6/1/89";
X  #endif
X  
X  #include <sys/types.h>
X--- 11,34 ----
X  **  History:
X  **	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X  **                                                               
X+ **      Patch #1:
X+ **          Added the code to support Chronological archiving in 
X+ **          save_article and the new function chronpath. Added
X+ **          more forgiveness for multiple blank lines between the
X+ **          News header and the Auxiliary headers. Added the ifdef
X+ **          NO_MONTH_DIR to decide which way the Chronological archiving
X+ **          is to be done. Copy_article was written to reduce the
X+ **          duplicated code at the end of save_article and do_problem.
X+ **          Split out compression suffix manipulation routines suffix,
X+ **          remove_suffix, and expand_name and check_archive_name for
X+ **          use in other related software. Added DIR_MODE define for 
X+ **          the modes of the directories when created. Moved write_patch_log
X+ **          into a new function, copy_article. Reformated the .patchlog 
X+ **          to meet the finally stable Patch-To: format. Cleaned up a 
X+ **          typo that was duplicated in Problem error messages.
X  */
X  #ifndef lint
X! static char SID[] = "@(#)news_arc.c	1.4 7/16/89";
X  #endif
X  
X  #include <sys/types.h>
X***************
X*** 20,25 ****
X--- 35,41 ----
X  #include <sys/stat.h>
X  #include <dirent.h>
X  #include <stdio.h>
X+ #include <time.h>
X  #include <ctype.h>
X  #include "article.h"
X  #include "cfg.h"
X***************
X*** 34,39 ****
X--- 50,56 ----
X  #define TYPE_PROB   3
X  
X  int test = 0;
X+ int inum = 0;
X  int problem_article;
X  
X  extern struct group_archive *newsgrp;
X***************
X*** 45,50 ****
X--- 62,69 ----
X  char *do_problem();
X  char *basename();
X  char *suffix();
X+ char *expand_name();
X+ char *copy_article();
X  FILE *efopen();
X  void exit();
X  
X***************
X*** 53,58 ****
X--- 72,78 ----
X  {
X      char *dp;
X      int header_ok = 0;
X+     int last = TEXT;
X      FILE *gfp;
X  
X      init_article();
X***************
X*** 67,77 ****
X  
X          if (!isalpha(*s) || (strchr(s,':') == NULL)) {
X             header_ok++;
X!            if (header_ok == 2) 
X                 break;
X             continue;
X          }
X  
X          dp = s;
X          while (*++dp)
X             if (*dp == '\n')
X--- 87,105 ----
X  
X          if (!isalpha(*s) || (strchr(s,':') == NULL)) {
X             header_ok++;
X!            if (header_ok >= 2) {
X!                if (*s == '\n' && last == BLANK)
X!                    continue;
X                 break;
X+            }
X+            if (*s == '\n')
X+               last = BLANK;
X+            else 
X+               last = TEXT;
X             continue;
X          }
X  
X+         last = TEXT;
X          dp = s;
X          while (*++dp)
X             if (*dp == '\n')
X***************
X*** 85,227 ****
X          dump_article();
X  }
X  
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- 
X- check_archive_name(argstr)
X-     char *argstr;
X-  {
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- /*
X- ** IF YOU USE A COMPRESSION ROUTINE OTHER THAN COMPRESS
X- ** OR PACK, ADD YOUR COMPRESSION SPECIFIC INFORMATION
X- ** TO THE cprgs COMPRESS_TABLE ......
X- */
X- 
X- struct compress_tab {
X-     char     *com_name;
X-     char     *com_suffix;
X- };
X- 
X- struct compress_tab cprgs[] = {
X- {    "compress",        ".Z"    },
X- {    "pack",            ".z"    },
X- {    NULL,            0    },
X- };
X- 
X- char *suffix(compression)
X-     char *compression;
X-  {
X-     struct compress_tab *ct;
X- 
X-     ct = &cprgs[0];
X-     while ((ct->com_name) != NULL) {
X-         if (strcmp(compression, ct->com_name) == 0) 
X-             return(ct->com_suffix);
X-         ct++;
X-     }
X-     return("");
X- }
X- 
X- int remove_suffix(path_str)
X- char *path_str;
X-  {
X-     char *ss;
X-     struct compress_tab *ct;
X- 
X-     /*
X-     ** need to compare the filename passed in to 
X-     ** the compression suffix table in order to
X-     ** determine if the file has a recognized,
X-     ** compression suffix attached.
X-     */
X-     
X-     ss = path_str + (strlen(path_str) -2);
X- 
X-     ct = &cprgs[0];
X-     while ((ct->com_name) != NULL) {
X-         if (strcmp(ss, ct->com_suffix) == 0) {
X-             *ss = '\0';
X-             return(TRUE);
X-         }
X-         ct++;
X-     }
X-     return(FALSE);
X- }
X- 
X- char *expand_name(filename,ng)
X- char *filename;
X- struct group_archive *ng;
X- {
X-     char *comp_cmd;
X-     static char compress_path[MAXNAMLEN];
X- 
X-     (void) strcpy(compress_path, filename);
X- 
X-     /*
X-     ** Check to see if a group specific compress was specified.      
X-     ** If so, then attach the suffix and return.                    
X-     ** Else check to see if a global compress was specified. If so,
X-     ** then attach the suffix and return.                         
X-     ** If both are NULL, return filename.                        
X-     */
X- 
X-     if (*(ng->compress)) {
X-         comp_cmd = basename(ng->compress);
X-         (void) strcat(compress_path, suffix(comp_cmd));
X-     }
X-     else if (*compress) {
X-         comp_cmd = basename(compress);
X-         (void) strcat(compress_path, suffix(comp_cmd));
X-     }
X-     return(compress_path);
X- }
X- 
X  #ifdef REDUCE_HEADERS
X  
X  struct hdrstokeep {
X--- 113,118 ----
X***************
X*** 235,240 ****
X--- 126,132 ----
X  {	"Subject:",		(sizeof "Subject:")	},
X  {	"Message-ID:",		(sizeof "Message-ID:")	},
X  {	"Date:",		(sizeof "Date:")	},
X+ {	"Approved:",		(sizeof "Approved:")	},
X  {	NULL,			0			},
X  };
X  
X***************
X*** 380,391 ****
X  
X      (void) mkparents(b);
X  
X!     if ((rc = makedir(b, 0755, newsgrp->owner, newsgrp->group)) != 0) 
X          error("makedir failed attempting to make", b);
X  
X      return(rc);
X  }
X  
X  
X  char *save_article (filename,ng)
X  char *filename;
X--- 272,315 ----
X  
X      (void) mkparents(b);
X  
X!     if ((rc = makedir(b, DIR_MODE, newsgrp->owner, newsgrp->group)) != 0) 
X          error("makedir failed attempting to make", b);
X  
X      return(rc);
X  }
X  
X+ char *copy_article(ng, filename,path)
X+ struct group_archive *ng;
X+ char *filename;
X+ char *path;
X+ {
X+     if (copy(filename,path) != 0) {  
X+         (void) fprintf(errfp,"copy failed for %s to %s\n",filename,path);
X+         return(NULL);
X+     }  
X+ 
X+     /* 
X+     ** Write the filename to the .archived file in the newsgroup's
X+     ** BASEDIR directory since we do not want it rearchived tomorrow.
X+     */
X+     write_archived(filename, path);
X+ 
X+     /*
X+     ** Check if the file is a patch. If so, log
X+     ** the patch information into the patch log
X+     ** in a *non-configurable* format so that
X+     ** applications can be written to access the
X+     ** file's "known format".
X+     */
X+ 
X+     if (article.rectype == PATCH)
X+         write_patch_log(ng,path);
X+ 
X+     /*
X+     ** Return the path to the archived file.
X+     */
X+     return(path);
X+ }
X  
X  char *save_article (filename,ng)
X  char *filename;
X***************
X*** 466,471 ****
X--- 390,412 ----
X              */
X              (void) sprintf(path,"%s/%s", ng->location, filename);
X              break;
X+     case CHRONOLOGICAL:
X+             /*
X+             ** The chronpath() is called to create a path for an article
X+             ** to be stored in chronological ordering. We need to be sure
X+             ** that the issue number is not in use. This is necessary to
X+             ** handle multiple runs of the program on the same day.
X+             **
X+             ** The idea here is to have the program check to see if the
X+             ** issue number to be used is available. 
X+             ** There should be no duplicates here ever... :-)
X+             ** [ just don't blow away your .archived file... :-( ]
X+             */
X+             do {
X+                 ++inum;
X+ 		chronpath(ng->location, path, inum);
X+             } while (stat(path ,&sb) == 0); 
X+             break;
X      default:
X              /*
X              ** We have got problems....
X***************
X*** 473,489 ****
X              return(do_problem(TYPE_PROB,ng,filename,path));
X      }
X  
X-     /*
X-     ** Check if the file is a patch. If so, log
X-     ** the patch information into the patch log
X-     ** in a *non-configurable* format so that
X-     ** applications can be written to access the
X-     ** file's "known format".
X-     */
X- 
X-     if (article.rectype == PATCH)
X-         write_patch_log(ng,path);
X- 
X  #ifdef ADD_REPOST_SUFFIX
X      if (article.repost == TRUE)
X          /*
X--- 414,419 ----
X***************
X*** 532,555 ****
X      if ((stat(final_path ,&sb) == 0) && !overwrite)  /* duplicate found */
X          return(do_problem(DUP_PROB,ng, filename, final_path));
X  
X!     if (copy(filename,path) != 0) {  
X!         (void) fprintf(errfp,"copy failed for %s to %s\n",filename,path);
X!         return(NULL);
X!     }  
X!     /* 
X!     ** Write the filename to the .archived file in the newsgroup's
X!     ** BASEDIR directory since we do not want it rearchived tomorrow.
X!     */
X!     write_archived(filename, path);
X! 
X!     /*
X!     ** Return the path to the archived file.
X!     */
X!     return(path);
X  }
X  
X  
X- 
X  char *do_problem(type_of_problem, ng, file, path)
X  int type_of_problem;
X  struct group_archive *ng;
X--- 462,471 ----
X      if ((stat(final_path ,&sb) == 0) && !overwrite)  /* duplicate found */
X          return(do_problem(DUP_PROB,ng, filename, final_path));
X  
X!     return(copy_article(ng, filename, path));
X  }
X  
X  
X  char *do_problem(type_of_problem, ng, file, path)
X  int type_of_problem;
X  struct group_archive *ng;
X***************
X*** 556,562 ****
X  char *file;
X  char *path;
X  {
X- 
X  #ifdef MV_ORIGINAL
X      char crnt_path[MAXNAMLEN];
X  #endif /*MV_ORIGINAL */
X--- 472,477 ----
X***************
X*** 578,590 ****
X  
X      switch( type_of_problem ) {
X         case NAME_PROB:
X!           (void) strcat(pmess,"does not support Archive-Name Archiving\n.");
X            break;
X         case VOL_PROB:
X!           (void) strcat(pmess,"does not support Volume-Issue Archiving\n.");
X            break;
X         case TYPE_PROB:
X!           (void) strcat(pmess,"has an invalid archive TYPE specified\n.");
X            break;
X         case DUP_PROB:
X            if (article.repost != TRUE) 
X--- 493,505 ----
X  
X      switch( type_of_problem ) {
X         case NAME_PROB:
X!           (void) strcat(pmess,"does not support Archive-Name Archiving.\n");
X            break;
X         case VOL_PROB:
X!           (void) strcat(pmess,"does not support Volume-Issue Archiving.\n");
X            break;
X         case TYPE_PROB:
X!           (void) strcat(pmess,"has an invalid archive TYPE specified.\n");
X            break;
X         case DUP_PROB:
X            if (article.repost != TRUE) 
X***************
X*** 652,658 ****
X              return(NULL);
X          }
X  
X!         set_ownership(path, ng);
X  
X          /* restore the destination path for inbound article */
X          (void) strcpy(path,crnt_path);
X--- 567,573 ----
X              return(NULL);
X          }
X  
X!         set_ownership(path, path, ng);
X  
X          /* restore the destination path for inbound article */
X          (void) strcpy(path,crnt_path);
X***************
X*** 688,759 ****
X      /* Make any necessary directories along the way. */
X      (void) mkparents(path);
X  
X!     if (copy(file,path) != 0) {  
X!         (void) fprintf(errfp,"copy failed for %s to %s\n", file, path);
X!         return(NULL);
X!     }  
X  
X-     /* 
X-     ** Write the filename to the .archived file in the newsgroup's
X-     ** BASEDIR directory since we do not want it rearchived tomorrow.
X-     */
X-     write_archived(file, path);
X  
X      /*
X!     ** Return the path to the stored problem file.
X      */
X!     return(path);
X  }
X- 
X  write_patch_log(ng, path)
X! 	struct group_archive *ng;
X! 	char *path;
X  {
X!         char *sp;
X! 	FILE *plfp;
X! 	struct stat sb;
X!         int hn;
X! 
X! 	/* 
X! 	** The .patchlog file is used to record the
X! 	** information specific to patches that come
X! 	** through the newsgroup.
X! 	**
X! 	** The format of the .patchlog file is:
X! 	**
X! 	** path-to-patch  initial-volume  initial-issue  volume issue 
X! 	** bb/patch01          22              105         23    77
X! 	** v47i022             22              105         23    77
X! 	*/
X! 
X!         /*
X!         ** If this is the first time that an entry is written to the
X!         ** patch log, add a header on top of the file for informational
X!         ** purposes only...
X!         */
X! 	if ((stat(ng->patchlog ,&sb) != 0)) {
X! 	    plfp = efopen(ng->patchlog,"a+");
X  
X! 	    (void) fprintf(plfp,"#\n#\tPatch log for %s\n#\n",
X!                     ng->ng_name);
X! 
X! 	    (void) fprintf(plfp,"# %-30s%-11s%-13s%-6s%10s\n", 
X!                     "Path To", "Initial", "Initial",
X!                     "Current", "Current");
X  
X! 	    (void) fprintf(plfp,"# %-30s%-11s%6s%13s%10s\n#\n", 
X!                     "Patchfile", "Volume", "Issue", "Volume", "Issue");
X! 	    (void) fclose(plfp);
X!         }
X  
X!         /* 
X!         ** Get rid of the base directory.
X!         */
X!         sp = path + (strlen(ng->location)+1);
X  
X! 	plfp = efopen(ng->patchlog,"a+");
X! 	(void) fprintf(plfp,"%-24s%12d%12d%12d%11d\n", sp,
X! 			article.patch_volume, article.patch_issue,
X! 			article.volume, article.issue);
X! 	(void) fclose(plfp);
X  }
X--- 603,713 ----
X      /* Make any necessary directories along the way. */
X      (void) mkparents(path);
X  
X!     return(copy_article(ng, file, path));
X! }
X  
X  
X+ #ifndef NO_MONTH_DIR
X+ static char *month[] = {	
X+ 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
X+ 	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 
X+ };
X+ #endif /* NO_MONTH_DIR */
X+ 
X+ chronpath(dirloc, path, seqnum)
X+     char *dirloc;
X+     char *path;
X+     int seqnum;
X+ {
X+     long time();
X+     struct tm *localtime();
X+ 
X+     long clk;
X+     struct tm *crnt;
X+     static struct tm now;
X+     static int no_time = 1;
X+ 
X+     if (no_time) {
X+        clk = time((long *)0);
X+        crnt = localtime(&clk); 
X+        no_time = 0;
X+        now = *crnt;
X+     }
X+ #ifdef NO_MONTH_DIR
X+     /*
X+     ** Format:
X+     ** 	/usenet/alt/sources/volume89/890629.01
X+     */
X+     (void) sprintf(path,"%s/%s%d/%.02d%.02d%.02d.%.02d",dirloc, 
X+                      VOLUME, now.tm_year,
X+                      now.tm_year,now.tm_mon+1,now.tm_mday,seqnum);
X+ #else
X      /*
X!     ** Format:
X!     ** 	/usenet/alt/sources/volume89/Jun/890629.01
X      */
X!     (void) sprintf(path,"%s/%s%d/%s/%.02d%.02d%.02d.%.02d",dirloc, 
X!                      VOLUME, now.tm_year, month[now.tm_mon],
X!                      now.tm_year,now.tm_mon+1,now.tm_mday,seqnum);
X! #endif /* NO_MONTH_DIR */
X  }
X  write_patch_log(ng, path)
X!     struct group_archive *ng;
X!     char *path;
X  {
X!     char *sp;
X!     FILE *plfp;
X!     struct stat sb;
X  
X!     if (test)
X!         return;
X  
X!     /* 
X!     ** The .patchlog file is used to record the
X!     ** information specific to patches that come
X!     ** through the newsgroup.
X!     **
X!     ** The format of the .patchlog file is:
X!     ** #
X!     ** #    Patch log for comp.sources.whatever
X!     ** #
X!     ** # Path To                   Patch       Package     Initial
X!     ** # Patchfile             Volume  Issue     Name   Volume   Issue
X!     ** #
X!     ** volume4/conquer4/Part04    6     86    conquer4     4      42-49
X!     ** volume4/conquer4/Part06    6     88    tests3       4      42,47,51
X!     ** volume6/conquer4/Part07    6     89    Unknown      6      89
X!     */
X! 
X!     /*
X!     ** If this is the first time that an entry is written to the
X!     ** patch log, add a header on top of the file for informational
X!     ** purposes only... Output in the patch log is not intended
X!     ** to be centered under these columns... :-) I'm laaaazy.
X!     */
X!     if ((stat(ng->patchlog ,&sb) != 0)) {
X!         plfp = efopen(ng->patchlog,"a+");
X! 
X!         (void) fprintf(plfp,"#\n#\tPatch log for %s\n#\n", ng->ng_name);
X! 
X!         (void) fprintf(plfp,"# %-27s%-12s%-15s%-s\n", 
X!                     "Path To", "Patch", "Package", "Initial");
X! 
X!         (void) fprintf(plfp,"# %-22s%-18s%-10s%-15s\n#\n", 
X!                     "Patchfile", "Volume  Issue", "Name",
X!                     "Volume  Issue");
X!         (void) fclose(plfp);
X!     }
X  
X!     /* 
X!     ** Get rid of the base directory.
X!     */
X!     sp = path + (strlen(ng->location)+1);
X  
X!     plfp = efopen(ng->patchlog,"a+");
X!     (void) fprintf(plfp,"%-25s %3d   %5d  %-14s  %3d  %s\n", sp,
X!             article.volume, article.issue, article.package_name,
X!             article.patch_volume, article.patch_issue);
X!     (void) fclose(plfp);
X!     return;
X  }
X*** O.patchlevel.h	Fri Jul 14 21:29:26 1989
X--- patchlevel.h	Sun Jul 16 13:42:52 1989
X***************
X*** 1,4 ****
X  /*
X! **    @(#)patchlevel.h	1.1 6/1/89
X  */
X! #define PATCHLEVEL 0
X--- 1,4 ----
X  /*
X! **    @(#)patchlevel.h	1.2 7/15/89
X  */
X! #define PATCHLEVEL 1
X*** O.rkive.1	Fri Jul 14 21:29:31 1989
X--- rkive.1	Sun Jul 16 13:42:56 1989
X***************
X*** 1,4 ****
X! 'br "@(#)rkive.1	1.1 6/1/89"
X  .TH RKIVE 1
X  .SH NAME
X  rkive \- archive USENET source groups
X--- 1,4 ----
X! 'br "@(#)rkive.1	1.2 7/15/89"
X  .TH RKIVE 1
X  .SH NAME
X  rkive \- archive USENET source groups
X***************
X*** 9,15 ****
X  .I rkive
X  is used to archive the USENET sources groups to an alternate
X  location as specified in an rkive configuration file. Archives can
X! be maintained in one of three ways:
X  .PP 
X  .I Archive-Name -
X  The moderators of most sources groups assign an official Archive-Name 
X--- 9,15 ----
X  .I rkive
X  is used to archive the USENET sources groups to an alternate
X  location as specified in an rkive configuration file. Archives can
X! be maintained in one of four ways:
X  .PP 
X  .I Archive-Name -
X  The moderators of most sources groups assign an official Archive-Name 
X***************
X*** 32,37 ****
X--- 32,50 ----
X  recommended for any site that will be doing massive searches of the 
X  individual volumes since it keeps the quadratic nature of directory searches 
X  from making your life miserable. 
X+ .PP 
X+ .I Chronological -
X+ This type of archiving can be used to store articles that do not have the
X+ auxiliary headers. The articles are stored by the date the article is 
X+ archived. The articles are stored in a format of
X+ .PP
X+ 	newsgroup/volume89/Jun/890627.01 or
X+ 	newsgroup/volumeYY/MOY/YYMMDD.II
X+ .PP 
X+ where YY is the year, MM is the month, DD is the day, and II is the 
X+ issue number archived that day. Depending on how the archive administrator
X+ has configured the rkive software, the MOY (month of year) may or may
X+ not be used. 
X  .PP 
X  .I Article Number -
X  The news software stores the articles locally by naming the news article 
X*** O.rkive.5	Fri Jul 14 21:30:02 1989
X--- rkive.5	Sun Jul 16 13:42:58 1989
X***************
X*** 1,4 ****
X! 'br "@(#)rkive.5	1.1 6/1/89"
X  .TH RKIVE 5
X  .SH NAME
X  rkive.cf \- USENET Source Archiver Configuration File.
X--- 1,4 ----
X! 'br "@(#)rkive.5	1.2 7/15/89"
X  .TH RKIVE 5
X  .SH NAME
X  rkive.cf \- USENET Source Archiver Configuration File.
X***************
X*** 65,71 ****
X  in which to archive USENET sources,
X  .RS
X  .IP
X! Volume-Issue, Archive-Name or Article Number.
X  .RE
X  .IP
X  These are used to determine if you wish the articles archived in a 
X--- 65,71 ----
X  in which to archive USENET sources,
X  .RS
X  .IP
X! Volume-Issue, Archive-Name,             Chronological, or Article Number.
X  .RE
X  .IP
X  These are used to determine if you wish the articles archived in a 
X***************
X*** 72,78 ****
X  .RS
X  .IP
X  /basedir/amiga/Volume1/v001i22 or /basedir/amiga/Volume1/sitonit or
X! /basedir/amiga/Volume1/44 format.
X  .RE
X  .IP "PATCHES ="
X  This variable determines the way in which patches are installed into 
X--- 72,78 ----
X  .RS
X  .IP
X  /basedir/amiga/Volume1/v001i22 or /basedir/amiga/Volume1/sitonit or
X! /basedir/amiga/Volume89/Jun/890628.01 or /basedir/amiga/Volume1/44 format.
X  .RE
X  .IP "PATCHES ="
X  This variable determines the way in which patches are installed into 
X***************
X*** 164,170 ****
X  in which to archive USENET sources,
X  .RS
X  .IP
X! Volume-Issue, Archive-Name or Article Number.
X  .RE
X  .IP "PATCHES ="
X  This variable determines the way in which patches are installed into 
X--- 164,170 ----
X  in which to archive USENET sources,
X  .RS
X  .IP
X! Volume-Issue, Archive-Name,             Chronological, or Article Number.
X  .RE
X  .IP "PATCHES ="
X  This variable determines the way in which patches are installed into 
X*** O.rkive.c	Fri Jul 14 21:30:39 1989
X--- rkive.c	Sun Jul 16 13:43:01 1989
X***************
X*** 31,38 ****
X  **  History:
X  **    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X  **                                                               
X  */
X! char sccsid[] = "@(#)rkive.c	1.1 6/1/89";
X  
X  #include <sys/types.h>
X  #include <sys/stat.h>
X--- 31,49 ----
X  **  History:
X  **    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X  **                                                               
X+ **    Patch #1:
X+ **        Added a check to verify the file is not zero bytes in length.
X+ **        Added Chronological archiving support.  Added check for "test"
X+ **        in logit. In set_ownership, added a "CYA" in the event that 
X+ **        compression fails because no saving is produced. Set_ownership
X+ **        attempts the filename without the suffix added when the attempt 
X+ **        on the filename with the suffix failed.  In this manner, file 
X+ **        permissions get set even if the compression routine fails.
X+ **        Also in set_ownership, moved the chmod before the chown/chgrp so
X+ **        that you need not be root to run rkive and give away files.
X+ **        Changed index to mindex so as to make the BSD getopt happy.
X  */
X! char sccsid[] = "@(#)rkive.c	1.3 7/16/89";
X  
X  #include <sys/types.h>
X  #include <sys/stat.h>
X***************
X*** 75,80 ****
X--- 86,92 ----
X  extern int debug;
X  extern int verbose;
X  extern int test;
X+ extern int inum;
X  extern int problem_article;
X  
X  main(argc, argv)
X***************
X*** 190,195 ****
X--- 202,209 ----
X      }
X  #endif
X  
X+     inum = 0;  /* initialize chronological issue counter */
X+ 
X      /* Remove any existing temporary mail file */
X  
X      (void) unlink(tmp_mailfile);
X***************
X*** 283,289 ****
X  
X         else if ((sbuf.st_mode & S_IFMT) != S_IFREG) 
X             continue; 
X!         
X         /* 
X         ** If the user has specified that a quick status 
X         ** listing should be produced then hop to it....
X--- 297,313 ----
X  
X         else if ((sbuf.st_mode & S_IFMT) != S_IFREG) 
X             continue; 
X! 
X!        /* Check to assure that the file has a size greater that 0 */
X!        /* Maybe I'm nuts but I don't see any reason to archive    */
X!        /* files unless they contain something.. :-)               */
X! 
X!        else if (sbuf.st_size == 0) {
X!            (void) fprintf(errfp, "%s/%s is a Zero length file - SKIPPING\n",
X!                           newsgroup_directory, dp->d_name);
X!            continue;
X!        }
X! 
X         /* 
X         ** If the user has specified that a quick status 
X         ** listing should be produced then hop to it....
X***************
X*** 311,317 ****
X             
X         if ((new_member = save_article(dp->d_name,newsgrp)) != NULL) {
X             archived_file = compress_file(new_member,newsgrp);
X!            set_ownership(archived_file,newsgrp);
X             
X             /*
X             ** If a problem has been encountered,
X--- 335,341 ----
X             
X         if ((new_member = save_article(dp->d_name,newsgrp)) != NULL) {
X             archived_file = compress_file(new_member,newsgrp);
X!            set_ownership(archived_file,new_member,newsgrp);
X             
X             /*
X             ** If a problem has been encountered,
X***************
X*** 437,472 ****
X  {
X      FILE *fp, *fopen();
X  
X!     if ( *(filename) ) {   /* Is a logfile specified ? */
X!         if ((fp = fopen(filename,"a")) != NULL) {
X!             format_output(fp, format_of_log, arch_file, ARCHIVE);
X!             (void) fclose(fp);
X          }
X      }
X  }    
X  
X  
X! set_ownership(filename,ng)
X! char *filename;
X  struct group_archive *ng;
X  {
X!     if (verbose) {  /* Print out the actions about to be preformed */
X!         (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
X!         (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
X!     }
X  
X!     if (!test) {    /* chown the owner/group to the desired values */
X!         if (chown(filename,ng->owner, ng->group) != 0)
X!             error("Can't change ownership of", filename);
X      }
X  
X      if (verbose) {  /* Print out the actions about to be preformed */
X!         (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
X      }
X  
X!     if (!test) {    /* change the file modes to the specified modes */
X!         if (chmod(filename,ng->modes) != 0)
X!             error("Can't change modes of", filename);
X      }
X  }
X  
X--- 461,516 ----
X  {
X      FILE *fp, *fopen();
X  
X!     if (!test) {
X!         if ( *(filename) ) {   /* Is a logfile specified ? */
X!             if ((fp = fopen(filename,"a")) != NULL) {
X!                 format_output(fp, format_of_log, arch_file, ARCHIVE);
X!                 (void) fclose(fp);
X!             }
X          }
X      }
X  }    
X  
X+ /*
X+ ** Set_ownership
X+ **
X+ **      This functions is responsible for setting the owner, group
X+ **      and modes of a file just put into the archive. Two file names
X+ **      are passed to this function. "filename" contains the compression
X+ **      suffix if the file is to be compressed. "flname" is the name of
X+ **      the file without the compression suffix. If the ownership or
X+ **      modes can not be set on the target "filename", this function
X+ **      then tries to set the original file, "flname". In this manner,
X+ **      the file permissions get set even if the compression routine fails.
X+ */     
X  
X! set_ownership(filename,flname,ng)
X! char *filename;             /* filename with compression suffix    */ 
X! char *flname;               /* filename without compression suffix */
X  struct group_archive *ng;
X  {
X!     if (verbose)    /* Print out the actions about to be preformed */
X!         (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
X  
X!     if (!test) {    /* change the file modes to the specified modes */
X!         if (chmod(filename,ng->modes) != 0) {
X!             /* Assume the compress failed and try the original... */
X!             if (chmod(flname,ng->modes) != 0) 
X!                 error("Can't change modes of", filename);
X!         }
X      }
X  
X      if (verbose) {  /* Print out the actions about to be preformed */
X!         (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
X!         (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
X      }
X  
X!     if (!test) {    /* chown the owner/group to the desired values */
X!         if (chown(filename, ng->owner, ng->group) != 0) {
X!             /* Assume the compress failed and try the original... */
X!             if (chown(flname, ng->owner, ng->group) != 0) 
X!                 error("Can't change ownership of", filename);
X!         }
X      }
X  }
X  
X***************
X*** 524,532 ****
X              logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
X      }
X  
X!     if (*index) {            /* Is there a global index file ?       */
X          if (*index_format)   /* Yes, Is there a global file format ? */
X!             logit(index, index_format, filename);
X          else                 /* No, so use the default index format  */
X              logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
X      }
X--- 568,576 ----
X              logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
X      }
X  
X!     if (*mindex) {            /* Is there a global index file ?       */
X          if (*index_format)   /* Yes, Is there a global file format ? */
X!             logit(mindex, index_format, filename);
X          else                 /* No, so use the default index format  */
X              logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
X      }
X*** O.rkive.cf	Fri Jul 14 21:30:20 1989
X--- rkive.cf	Sun Jul 16 13:43:05 1989
X***************
X*** 1,6 ****
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--- 1,6 ----
X  #
X  #
X! #	@(#)rkive.cf	1.2 7/15/89 
X  #
X  #	An rkive.cf template.
X  #	Copy and edit this to reflect the local archive conditions.
X***************
X*** 18,29 ****
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--- 18,31 ----
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 4 possible keys:
X! #			        Volume-Issue, Archive-Name 
X! #                               Chronological 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/Volume89/890619001 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***************
X*** 92,103 ****
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--- 94,107 ----
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 4 possible keys:
X! #			Volume-Issue, Archive-Name 
X! #                       Chronological 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/Volume89/890619001 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***************
X*** 167,173 ****
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--- 171,177 ----
X  
X  $$comp.sources.mac		
X  	BASEDIR: /usenet/mac
X! 	TYPE: Chronological
X  	LOG: /usenet/mac/log
X          INDEX: /usenet/mac/index
X          INDEX_FORMAT: "%O %a %T" 
X***************
X*** 201,207 ****
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--- 205,211 ----
X  
X  $$alt.sources
X  	BASEDIR: /usenet/alt/sources
X! 	TYPE: Chronological
X  	LOG: /usenet/alt/sources/log
X          LOG_FORMAT: "%O %S" 
X  
X*** O.rkive.h	Fri Jul 14 21:30:08 1989
X--- rkive.h	Sun Jul 16 13:43:06 1989
X***************
X*** 1,5 ****
X  /*
X! ** 	@(#)rkive.h	1.1 6/1/89 
X  **
X  **	This is the rkive source configuration header file. 
X  **	Please examine and change to suite your own site's needs..
X--- 1,5 ----
X  /*
X! ** 	@(#)rkive.h	1.3 7/15/89 
X  **
X  **	This is the rkive source configuration header file. 
X  **	Please examine and change to suite your own site's needs..
X***************
X*** 15,20 ****
X--- 15,21 ----
X  #define OWNER    0
X  #define GROUP    3
X  #define MODES    0444
X+ #define DIR_MODE 0755         /* directory creation modes */
X  
X  /* 
X  ** If you have a smart mailer that supports a "-s subject" command
X***************
X*** 113,119 ****
X  ** If you wish to have the headers "trimmed" when the file is archived,
X  ** assure that REDUCE_HEADERS is defined. Currenlty all header lines that
X  ** are not either;
X! **	 From:, Newsgroups:, Subject:, Message-ID:, and Date:
X  ** will be removed. See news_arc.c if you wish to add or subtract header
X  ** lines to keep. This can produce a savings of between 200 to 500 bytes
X  ** per archived article.
X--- 114,120 ----
X  ** If you wish to have the headers "trimmed" when the file is archived,
X  ** assure that REDUCE_HEADERS is defined. Currenlty all header lines that
X  ** are not either;
X! **    From:, Newsgroups:, Subject:, Message-ID: Approved:, and Date:
X  ** will be removed. See news_arc.c if you wish to add or subtract header
X  ** lines to keep. This can produce a savings of between 200 to 500 bytes
X  ** per archived article.
X***************
X*** 181,186 ****
X--- 182,189 ----
X  #define VOLUME_ISSUE     1	/* Archive as "v16i003"     */
X  #define ARTICLE_NUMBER   2	/* Archive with same name   */
X  				/* as the file to archive   */
X+ #define CHRONOLOGICAL    3	/* Archive as "890619002"   */
X+                                 /* or YYMMDDIII format      */
X  
X  /*
X  ** patch handling type defines 
X***************
X*** 203,208 ****
X--- 206,212 ----
X  				/*        0 = Archive-Name           */
X                                  /*        1 = Volume-Issue           */
X                                  /*        2 = Article-Number         */
X+                                 /*        3 = Chronological          */
X      int patch_type;             /* Method of handling patches.       */
X                                  /*        0 = Historical             */
X                                  /*        1 = Package                */
X*** O.setup.c	Fri Jul 14 21:30:25 1989
X--- setup.c	Sun Jul 16 13:43:09 1989
X***************
X*** 10,19 ****
X  **
X  **  History:
X  **	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X! **                                                               
X  */
X  #ifndef lint
X! static char SID[] = "@(#)setup.c	1.1 6/1/89";
X  #endif
X  
X  #include <sys/types.h>
X--- 10,26 ----
X  **
X  **  History:
X  **	Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
X! **
X! **      Patch #1:
X! **          Added Chronological archiving support. Changed the default 
X! **          archive type to Chronological. Corrected error message for 
X! **          invalid PATCHES type. Added CHECK_LOGNAME ifdef around getpwnam
X! **          so as to all for remote mail addresses. Changed index to mindex 
X! **          so as to make the BSD getopt happy. Corrected pointer check
X! **          in get_users.
X  */
X  #ifndef lint
X! static char SID[] = "@(#)setup.c	1.3 7/16/89";
X  #endif
X  
X  #include <sys/types.h>
X***************
X*** 33,39 ****
X  int default_owner = OWNER;
X  int default_group = GROUP;
X  int default_modes = MODES;
X! int default_type = ARTICLE_NUMBER;
X  int default_patch_type = HISTORICAL;
X  
X  /*
X--- 40,46 ----
X  int default_owner = OWNER;
X  int default_group = GROUP;
X  int default_modes = MODES;
X! int default_type = CHRONOLOGICAL;
X  int default_patch_type = HISTORICAL;
X  
X  /*
X***************
X*** 65,74 ****
X  char log_format[BUFSIZ] = { '\0' };
X  
X  /*
X! ** index -
X  ** The location of the master index.
X  */
X! char index[MAXNAMLEN] = { '\0' };
X  
X  /*
X  ** index_format -
X--- 72,81 ----
X  char log_format[BUFSIZ] = { '\0' };
X  
X  /*
X! ** mindex -
X  ** The location of the master index.
X  */
X! char mindex[MAXNAMLEN] = { '\0' };
X  
X  /*
X  ** index_format -
X***************
X*** 183,189 ****
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--- 190,196 ----
X                 case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
X                              (void) strcpy(index_format, sav_format(sp));
X                           else if (strncmp(buf, "INDEX", 3) == 0)
X!                             (void) strcpy(mindex, strstrip(sp));
X                           else
X                              GAG(buf);
X                           break;
X***************
X*** 455,467 ****
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--- 462,477 ----
X          return_type = ARCHIVE_NAME;
X      else if (strcmp(s, "Volume-Issue") == 0) 
X          return_type = VOLUME_ISSUE;
X+     else if (strcmp(s, "Chronological") == 0) 
X+         return_type = CHRONOLOGICAL;
X      else if (strcmp(s, "Article-Number") == 0) 
X          return_type = ARTICLE_NUMBER;
X      else {
X          (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X                     ngname, "Invalid Archive Type:", s);
X!         (void) fprintf(errfp,"\tTYPE Must be %s, %s, %s or %s\n",
X!                    "Archive-Name",  "Volume-Issue", 
X!                    "Chronological", "Article-Number");
X          exit(1);
X      }
X  
X***************
X*** 528,538 ****
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--- 538,548 ----
X            ++cp;
X      }
X        
X!     /* Need to check the specified user list */
X!     /* to assure that all users are valid.   */
X  
X      (void) strcpy(tmp_users, users);
X!     *users = '\0';
X  
X      name = tmp_users;
X  
X***************
X*** 543,559 ****
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--- 553,570 ----
X               *(list-1) = '\0';
X          }
X  
X+ #ifdef CHECK_LOGNAME 
X          /* check if user is found in passwd file */
X!         if ((pwent = getpwnam(name)) == NULL) 
X!             error("Invalid user:",name);
X! #endif /* CHECK_LOGNAME */
X! 
X!         if (*users != '\0') {
X!             (void) strcat(users, ",");
X!             (void) strcat(users, name);
X          }
X          else 
X!             (void) strcpy(users, name);
X          name = list;
X      }
X      return(users);
X***************
X*** 596,602 ****
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--- 607,613 ----
X      else {
X          (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X                     ngname, "Invalid Patches Type:", s);
X!         (void) fprintf(errfp,"\tPATCHES Must be %s, or %s\n",
X                     "Historical", "Package");
X          exit(1);
X      }
X*** O.suffix.c	Sat Jul 15 00:40:12 1989
X--- suffix.c	Sun Jul 16 13:43:11 1989
X***************
X*** 0 ****
X--- 1,95 ----
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: Thu Jun 22 18:44:35 CST 1989 due to necessity.
X+ **                                                               
X+ */
X+ #ifndef lint
X+ static char SID[] = "@(#)suffix.c	1.1 7/15/89";
X+ #endif
X+ 
X+ #include <stdio.h>
X+ #include <sys/types.h>
X+ #include <dirent.h>
X+ #include "rkive.h"
X+ #include "suffix.h"
X+ 
X+ char *basename();
X+ extern char compress[];
X+ 
X+ char *suffix(compression)
X+     char *compression;
X+  {
X+     struct compress_tab *ct;
X+ 
X+     ct = &cprgs[0];
X+     while ((ct->com_name) != NULL) {
X+         if (strcmp(compression, ct->com_name) == 0) 
X+             return(ct->com_suffix);
X+         ct++;
X+     }
X+     return("");
X+ }
X+ 
X+ int remove_suffix(path_str)
X+ char *path_str;
X+  {
X+     char *ss;
X+     struct compress_tab *ct;
X+ 
X+     /*
X+     ** need to compare the filename passed in to 
X+     ** the compression suffix table in order to
X+     ** determine if the file has a recognized,
X+     ** compression suffix attached.
X+     */
X+     
X+     ss = path_str + (strlen(path_str) -2);
X+ 
X+     ct = &cprgs[0];
X+     while ((ct->com_name) != NULL) {
X+         if (strcmp(ss, ct->com_suffix) == 0) {
X+             *ss = '\0';
X+             return(TRUE);
X+         }
X+         ct++;
X+     }
X+     return(FALSE);
X+ }
X+ 
X+ char *expand_name(filename,ng)
X+ char *filename;
X+ struct group_archive *ng;
X+ {
X+     char *comp_cmd;
X+     char *strcpy();
X+     char *strcat();
X+     static char compress_path[MAXNAMLEN];
X+ 
X+     (void) strcpy(compress_path, filename);
X+ 
X+     /*
X+     ** Check to see if a group specific compress was specified.      
X+     ** If so, then attach the suffix and return.                    
X+     ** Else check to see if a global compress was specified. If so,
X+     ** then attach the suffix and return.                         
X+     ** If both are NULL, return filename.                        
X+     */
X+ 
X+     if (*(ng->compress)) {
X+         comp_cmd = basename(ng->compress);
X+         (void) strcat(compress_path, suffix(comp_cmd));
X+     }
X+     else if (*compress) {
X+         comp_cmd = basename(compress);
X+         (void) strcat(compress_path, suffix(comp_cmd));
X+     }
X+     return(compress_path);
X+ }
X*** O.suffix.h	Sat Jul 15 00:40:17 1989
X--- suffix.h	Sun Jul 16 13:43:12 1989
X***************
X*** 0 ****
X--- 1,22 ----
X+ /*
X+ ** 	@(#)suffix.h	1.1 7/15/89 
X+ **
X+ */
X+ 
X+ /*
X+ ** IF YOU USE A COMPRESSION ROUTINE OTHER THAN COMPRESS
X+ ** OR PACK, ADD YOUR COMPRESSION SPECIFIC INFORMATION
X+ ** TO THE cprgs COMPRESS_TABLE BELOW......
X+ */
X+ 
X+ struct compress_tab {
X+     char     *com_name;
X+     char     *com_suffix;
X+ };
X+ 
X+ struct compress_tab cprgs[] = {
X+ {    "compress",        ".Z"    },
X+ {    "pack",            ".z"    },
X+ {    NULL,                0     },
X+ };
X+ 
END_OF_FILE
if test 44988 -ne `wc -c <'Patch1-p2of2'`; then
    echo shar: \"'Patch1-p2of2'\" unpacked with wrong size!
fi
# end of 'Patch1-p2of2'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both 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