[net.sources] archive saves news articles

chip@t4test.UUCP (Chip Rosenthal) (08/27/84)

: This is a shar archive.  Extract with sh, not csh.
: This archive contains the following files
:  README archive.c archive.l
: Total number of files: 3
echo x - README [file 1 of 3]
sed 's/^X//' > README << '!-FUNKY-STUFF-!'
X
XThe `archive' program is used to archive news articles.  It is very
Xconvenient because the archived articles can be read with the mail
Xprogram.  This version is a complete rewrite of one posted several
Xmonths ago.  It is a lot cleaner, and an intermittent bus error has
Xbeen fixed.  This `shar' script contains these notes, the `archive'
Xprogram, and the manual page.  If you wish to be informed of future
Ximprovements or changes to `archive', please send me your net address.
X
X			   ----------
X
X	    Using `Archive' with the `Rn' News Reader
X
X`Archive' may be installed as the default mailbox saver for the `rn'
Xnews reader.  Two changes are required.
X
XFirst, the save command must be redefined in the `rn.h' file.  This can 
Xbe done with:
X
X    #define MBOXSAVER "archive -o < \"%d/%a\" >> \"%b\""
X
XNote that this overrides the `archive' algorithm and forces the archive
Xdirectory to be `~/News' and the filename to be the newsgroup currently
Xbeing read.  For consistency, I define my NEWSARCHIVE as:
X
X    setenv NEWSARCHIVE '~/News'
X
XThe second change involves a modification to the `ngstuff.c' file.  The
Xsection of code which must be changed is as follows:
X
X    tmpfd = open(s,0);
X    if (tmpfd == -1)
X	mailbox = FALSE;
X    else {
X	read(tmpfd,buf,1);
X	mailbox = (*buf == MBOXCHAR);
X	close(tmpfd);
X    }
X
XThe `read' should be changed to:
X
X    while ( read(tmpfd,buf,1)!=0 && !isalnum(*buf) && !ispunct(*buf) ) ;
X
XThis way `rn' will be able to recognize that the archive file is in
Xmbox format, even if it begins with blank lines, which it does.  The
Xreason is that `mail' requires blank lines between the messages, and I
Xfelt more comfortable outputting a blank line before the archived
Xarticle rather than after, and depending upon the fact that the
Xprevious article has a blank line after it.
!-FUNKY-STUFF-!
echo x - archive.c [file 2 of 3]
sed 's/^X//' > archive.c << '!-FUNKY-STUFF-!'
X/*
X * FILE:	archive
X * VERSION:	V2.01
X * DATE:	16 Aug 84
X * AUTHOR:      Chip Rosenthal/Intel Corporation
X * ADDRESS:	t4test!chip
X * DESCRIPTION:	archive USENET news articles
X *
X * REVISION NOTES:
X *
X * V1.00  Original program.
X * V2.00  Totally re-written.
X * V2.01  Replaced BSD regular expression procedures with "strncmp".
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#define FALSE 0
X#define TRUE 1
X#define BUFLEN 1024
X#define SBUFLEN 64
X#define ARCHIVE_DIR "NEWSARCHIVE"
X#define USAGE_ERROR "Usage:  %s [-g group] [-f file] [-o]\n"
X
X/*
X * Archive reads a USENET article from the standard input, and places it
X * in an archive file.  The format of the archive file is such that it
X * may be read with the "mail -f" command.  The directory which contains
X * the archive file is defined by the user by setting an environment
X * parameter to the full pathname of the archive directory.  The name
X * of this environment parameter is specified by the "ARCHIVE_DIR"
X * defination.  The file name is specified by the first newsgroup given
X * in the "Newsgroups" header line of the article.
X *
X * The "-g" option overrides the "Newsgroup" line, and allows specification
X * of a different newsgroup name for the archive file.  The "-f" overrides
X * the "Newsgroup" line and environment defination, and allows specification
X * of the full pathname of the archive file.  The "-o" option places output
X * on the standard output.
X */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    FILE *tempfp, *outfp;
X    char *tempfile="/tmp/archXXXXXX";
X    char archgroup[SBUFLEN], archdir[SBUFLEN], outfile[SBUFLEN];
X    char buf[BUFLEN];
X    int fswitch, gswitch, oswitch;
X
X    int i;
X    char *c, *d;
X
X    FILE *fopen();
X    char *mktemp(), *getenv(), *fgets(), *ctime();
X    long time();
X
X    long timenow=time(0);
X
X    /*  
X     * Decode invocation switches                                        
X     */
X    fswitch=FALSE;
X    gswitch=FALSE;
X    oswitch=FALSE;
X
X    for ( i=1 ; i<argc ; ++i ) {
X
X        if (*argv[i] != '-') {
X            fprintf(stderr,USAGE_ERROR,argv[0]);
X            exit(1);
X        }
X
X        switch (*(argv[i]+1)) {
X
X        case 'f':
X            if (++i>=argc) {
X                fprintf(stderr,USAGE_ERROR,argv[0]);
X                exit(1);
X            }
X            fswitch=TRUE;
X            strcpy(outfile,argv[i]);
X            break;
X
X        case 'g':
X            if (++i>=argc) {
X                fprintf(stderr,USAGE_ERROR,argv[0]);
X                exit(1);
X            }
X            gswitch=TRUE;
X            strcpy(archgroup,argv[i]);
X            break;
X
X        case 'o':
X            oswitch=TRUE;
X            break;
X
X        default:
X            fprintf(stderr,USAGE_ERROR,argv[0]);
X            exit(1);
X
X        }
X    }
X
X#ifdef DEBUG
X    fprintf(stderr,"%s:  argc=%d, fswitch=%d, gswitch=%d, oswitch=%d\n",
X	argv[0],argc,fswitch,gswitch,oswitch);
X    if (fswitch) fprintf(stderr,"%s:  output file is %s\n",argv[0],outfile);
X    if (gswitch) fprintf(stderr,"%s:  output group is %s\n",argv[0],archgroup);
X#endif
X
X    if ( (fswitch + gswitch + oswitch) > 1 ) {
X        fprintf(stderr,USAGE_ERROR,argv[0]);
X        exit(1);
X    }
X
X    /*
X     * Dump from std input into temp file
X     */
X    mktemp(tempfile);
X    tempfp = fopen(tempfile,"w");
X    if ( tempfp == NULL ) {
X        perror(tempfile);
X        exit(1);
X    }
X    while ( (i=getchar()) != EOF ) 
X	putc(i,tempfp);
X    fclose(tempfp);
X
X#ifdef DEBUG
X    fprintf(stderr,"%s:  tempfile %s created\n",argv[0],tempfile);
X#endif
X
X    /*  
X     * Determine where to archive article.
X     */
X
X    if (oswitch) 
X    /* archive it to the standard output */
X    {
X        strcpy(outfile,"stdout");
X        outfp=stdout;
X    } 
X    
X    else if (gswitch) 
X    /* 
X     * get directory name from environment,
X     * file was specified in command line 
X     */
X    {
X        c=getenv(ARCHIVE_DIR);
X        if ( c == NULL ) {
X            fprintf(stderr,"%s:  %s undefined\n",argv[0],ARCHIVE_DIR);
X            exit(1);
X	}
X	strcpy(archdir,c);
X        sprintf(outfile,"%s/%s",archdir,archgroup);
X    } 
X    
X    else if ( fswitch ) 
X    /* full pathname was specified in command line */
X    {
X	;
X    }
X
X    else
X    /* 
X     * get directory name from environment,
X     * get file from article header
X     */
X    {
X        c=getenv(ARCHIVE_DIR);
X        if ( c == NULL ) {
X            fprintf(stderr,"%s:  %s undefined\n",argv[0],ARCHIVE_DIR);
X            exit(1);
X	}
X	strcpy(archdir,c);
X
X        if ((tempfp = fopen(tempfile,"r")) == NULL) {
X            fprintf(stderr,"%s:  can't access %s\n",argv[0],tempfile);
X            exit(1);
X        }
X	while ( (c=fgets(buf,sizeof buf,tempfp)) != NULL && 
X	    strncmp(buf,"Newsgroups: ",12) != 0 ) ;
X
X        if ( c!=NULL ) {
X	    /* set "c" to point to the beginning of the first newsgroup */
X            c=buf; 
X            while ( *c && !isspace(*c) ) ++c;
X            while ( isspace(*c) ) ++c;
X	    /* place a null terminator at the end of this newsgroup */
X            for ( d=c ; *d && !isspace(*d) && *d!='\n' && *d!=',' ; ++d ) ;
X            *d='\0';
X	    /* store newsgroup in "archgroup" */
X            strcpy(archgroup,c);
X        } else {
X            fprintf(stderr,"%s:  no group found\n",argv[0]);
X            exit(1);
X        }
X        fclose(tempfp);
X	/* compile directory and newsgroup into full archive file pathname */
X        sprintf(outfile,"%s/%s",archdir,archgroup);
X    }
X
X    /* open output stream */
X    if (! oswitch) {
X        if ( (outfp=fopen(outfile,"a")) == NULL ) {
X            perror(outfile);
X            exit(1);
X        }
X	fprintf(stderr,"archiving article in %s\n",outfile);
X    }
X
X#ifdef DEBUG
X    if ( oswitch )
X	fprintf(stderr,"archiving article in %s\n",outfile);
X#endif
X
X
X    /*  
X     * Insert a 'mail' compatible format 'From' line at top of header
X     */
X    putc('\n',outfp);
X    tempfp = fopen(tempfile,"r");
X    if ( tempfp == NULL ) {
X	perror(tempfile);
X        exit(1);
X    }
X    while ( (c=fgets(buf,sizeof buf,tempfp))!=NULL && 
X	strncmp(buf,"From",4) != 0 ) ;
X
X    fprintf(outfp,"From");
X
X    if ( c != NULL ) {
X
X	/* print out author's name */
X        for ( c=buf ; *c && !isspace(*c) ; ++c ) ;
X	while ( *c && !isalnum(*c) ) ++c;
X	for ( d=c ; *d && (isalnum(*d) || *d=='-') ; ++d ) ;
X	i=(*d);
X	*d='\0';
X	if ( *c )
X	    fprintf(outfp," %s",c);
X
X	/* print out author's site */
X	*d=i;
X	i=(*c);
X	for ( c=d ; *c && *c!='@' ; ++c )  ;
X	if ( *c ) ++c;
X	for ( d=c ; *d && (isalnum(*d) || *d=='-') ; ++d ) ;
X	*d='\0';
X	if ( *c )
X	    fprintf(outfp,"%c%s",i ? '@' : ' ', c );
X	else if ( !i )
X	    fprintf(outfp," ??????");
X
X    } else
X	fprintf(outfp," ??????");
X
X    fprintf(outfp," %s",ctime(&timenow));
X    fclose(tempfp);
X
X    /*  
X     * Now write out article.  Mark any additional "From" lines.
X     */
X    if ((tempfp = fopen(tempfile,"r")) == NULL) {
X        fprintf(stderr,"%s:  can't access %s\n",argv[0],tempfile);
X        exit(1);
X    }
X    while ( fgets(buf,sizeof buf,tempfp) != NULL ) {
X	if ( strncmp(buf,"From",4) == 0 )
X	    putc('>',outfp);
X        fputs(buf,outfp);
X    }
X    fclose(tempfp);
X    unlink(tempfile);
X
X    fclose(outfp);
X#ifdef DEBUG
X    fprintf(stderr,"%s:  completed\n\n",argv[0]);
X#endif
X}
X
!-FUNKY-STUFF-!
echo x - archive.l [file 3 of 3]
sed 's/^X//' > archive.l << '!-FUNKY-STUFF-!'
X.TH ARCHIVE 1L 8/19/84
X.UC
X.SH NAME
Xarchive \- archive USENET articles 
X.SH SYNOPSIS
X.B archive 
X[ 
X.B \-g
Xarchgroup ] [ 
X.B \-f
Xarchfile ] [ 
X.B \-o
X]
X.SH DESCRIPTION
X.PP
X.I Archive
Xis used to save USENET articles in an archive file.
XThe format of the archive file allows articles to
Xbe perused by the `mail -f' command.
X.PP
X.I Archive
Xreads an article from the standard input and appends it to an archive file.
XThe name of the archive file is determined as follows:  
Xthe user's environment is searched for a parameter named NEWSARCHIVE.  
XThe value of this parameter is interpreted as the full pathname 
Xof an archive directory.  
XBy default, all archive files are placed in this directory.
XThe name of the archive file is the
Xfirst newsgroup given in the article's `Newsgroups' header line.
XOptions are available to modify this algorithm.  
XNo more than one of these options may be specified at a time.  
X.TP 8
X.B \-g
XThe name of the archive file is determined by
X.I archgroup
Xrather than the article's `Newsgroups' header line.
X.br
X.TP 8
X.B \-f
X.I Archfile
Xis taken to be the full pathname of the archive file.
X.br
X.TP 8
X.B \-o
XThe article is archived to the standard output.
X.PP
X.I Archive
Xis easily used from a news reader program.  
XFor example, it may be used from 
X.I readnews
Xby typing `s | archive' to the `more [ynq] ?' prompt.
XIt may be used from
X.I rn
Xby typing `| archive' to the `Last article' prompt.
X.SH FILES
X/tmp/arch*
X.br
X~/$NEWSARCHIVE/*
X.SH SEE ALSO
Xmail(1), readnews(1), rn(1)
X.SH BUGS
X.PP
XIf NEWSARCHIVE is not defined, then
X.I archive
Xwill abort with an error.  Therefore, a
X.RS 5
X.sp
Xsetenv NEWSARCHIVE 
X.I path
X.sp
X.RE
Xcommand should be placed in your
X.I .cshrc
Xfile, where
X.I path
Xis the full pathname of your archive directory.  If this directory
Xdoesn't already exist, then you must create it for
X.I archive
Xto work.
X.PP
XNo method is provided to manage and manipulate articles once
Xarchived, other than those provided through the 
X.I mail 
Xprogram. Note that
X.I archive
Xmassages the `From' line so that there is enough room to see
Xthe article's subject in the header list given by the
X.I mail
Xprogram's `headers' command.  Therefore, you can't use the
X`reply' command with an archived article.
X.SH AUTHOR
XChip Rosenthal 
X.br
Xt4test!chip
X.br
XIntel Corporation
X.br
XSC4-755
X.br
Xx6-7651
!-FUNKY-STUFF-!
exit
-- 
Chip Rosenthal, Intel/Santa Clara
{idi|intelca|icalqa|imcgpe|kremvax|qubix|ucscc}!t4test!{chip|news}