amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (02/07/91)
Submitted-by: lordbah@amusing.bisco.kodak.COM (Jeff Van Epps) Posting-number: Volume 91, Issue 006 Archive-name: news/barn-2.01/part01 I am submitting to comp.sources.amiga my program, "Bah's Amiga Read News". (Originally I called it ARN, but there is already a newsreader out there called ARN so I changed the name of mine). Name: BARN Version: 2.01 Description: Usenet newsreader for the Amiga. Distribution: Source is freely distributable. A replacement for Anews which comes with AmigaUUCP 1.03D -- should also work with later versions of AmigaUUCP. The interface is modeled after "rn" from the UNIX world. Follows subject threads, has kill files, a built-in pager, etc. Probably requires SAS C 5.10 or later to compile, as well as Henry Spencer's regexp library. -------------------------------------------------------------------- Jeff Van Epps amusing!lordbah@bisco.kodak.com lordbah@cup.portal.com sun!portal!cup.portal.com!lordbah #!/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: Makefile article.c article.h barn.config configure.c # configure.h kill.c kill.h ng.c ng.h raw.c reply.c reply.h # screenstuff.h sendpacket.c standard.h trim.sksh variables.h # Wrapped by tadguy@ab20 on Wed Feb 6 20:05:19 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(782 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XCFLAGS = -c -O +filter +pure-strings +echo X#CFLAGS = -c -g3 +filter +pure-strings +echo XBARN_OBJS = arn.o article.o configure.o ng.o kill.o reply.o raw.o sendpacket.o XCC = cc X X.c.o: X $(CC) $(CFLAGS) $< X Xall: barn X Xbarn: $(BARN_OBJS) X $(CC) $(BARN_OBJS) +catch -lregexp -o barn X Xtest: main.o article.o X blink from lib:c.o+main.o+article.o to test lib lib:$(CC).lib lib:amiga.lib addsym X XInstall: barn X copy barn uucp:c X Xarn.o: arn.c standard.h article.h ng.h kill.h configure.h variables.h reply.h screenstuff.h X Xarticle.o: article.c standard.h article.h configure.h variables.h X Xconfigure.o: configure.c standard.h configure.h X Xkill.o: kill.c standard.h article.h kill.h X Xng.o: ng.c standard.h article.h ng.h X Xreply.o: reply.c standard.h configure.h variables.h article.h reply.h X END_OF_FILE if test 782 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi chmod +x 'Makefile' # end of 'Makefile' fi if test -f 'article.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'article.c'\" else echo shar: Extracting \"'article.c'\" \(9465 characters\) sed "s/^X//" >'article.c' <<'END_OF_FILE' X/* X * File Name: article.c X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Parse header fields in a news article. X * Functions: ParseArticle, GetNextHeader, DumpArticle, DestroyArticle. X * Author: Jeff Van Epps X * Created: 02 Sep 89 X * Last Modified: 05 Jan 91 X * Comments: X * History: X * 02 Sep 89/JVE Created. X * 28 Sep 89/JVE ParseArticle now stores position within file where X * headers end and text begins in article->textpos. X * 30 Dec 89/JVE Added "Sender:" to list of useful headers. This list X * will go away when there is a config file to do same. X * 18 Oct 90/JVE Use HDR_xxx defines instead of hardcoded strings. X * Added GetHeader. X * 21 Oct 90/JVE Don't end header search until blank line. X * 05 Jan 91/JVE New "subject" field in article_info initialized to X * a NULL pointer and set to point at the SUBJECT header X * fieldvalue after all headers have been read. X */ X X# include <stdio.h> X# include <stdlib.h> X# include <string.h> X# include "standard.h" X# include "article.h" X# include "configure.h" X# include "variables.h" X X X/****************************************************************************/ X/* FUNCTION: ParseArticle */ X/* */ X/* PURPOSE: Parses headers from article & creates article/header structs*/ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* filename I Name of file containing article. */ X/* */ X/* RETURNS: */ X/* (ARTICLE_INFO *) Pointer to newly allocated article structure. */ X/* NULLP(ARTICLE_INFO) Indication of failure. */ X/* */ X/* COMMENTS: */ X/* Assumes filename contains only digits and is same as article */ X/* number. */ X/* */ X/* HISTORY: */ X/* 1. 02 Sep 89 Created. */ X/* 2. 28 Sep 89 Added textpos to say where headers end. */ X/* */ X/****************************************************************************/ X XARTICLE_INFO *ParseArticle( filename ) X Xchar *filename; X X{ XFILE *fp; Xlong id; /* article number (aka filename) */ XARTICLE_INFO *article; /* ptr to article information */ XHEADER_INFO **hdr; /* handle for header field allocation */ XHEADER_INFO *h; X Xif ( ( fp = fopen( filename, "r" ) ) == NULLP( FILE ) ) X { X perror( filename ); X return NULLP( ARTICLE_INFO ); X } Xelse if ( ( id = atol( filename ) ) <= 0 ) X { X printf( "%s: Bad article number.\n", filename ); X return NULLP( ARTICLE_INFO ); X } X X/* X * Initialize article info structure. X */ X Xarticle = (ARTICLE_INFO *) malloc( sizeof( ARTICLE_INFO ) ); Xarticle->number = id; Xarticle->next = NULLP( ARTICLE_INFO ); Xarticle->headers = NULLP( HEADER_INFO ); Xarticle->beenread = FALSE; Xarticle->textpos = 0L; Xarticle->done = FALSE; Xarticle->subject = NULLP( char ); X X/* X * Get all header fields. X */ X Xhdr = &article->headers; Xwhile ( GetNextHeader( fp, &hdr ) ) X article->textpos = ftell( fp ); Xfclose( fp ); Xfor ( h = article -> headers; h != NULLP( HEADER_INFO ); h = h -> next ) X if ( strcmp( h -> fieldname, HDR_SUBJECT ) == 0 ) X { X article -> subject = h -> fieldvalue; X break; X } Xreturn article; X} X X X/****************************************************************************/ X/* FUNCTION: GetNextHeader */ X/* */ X/* PURPOSE: Parses the next header field out of an article. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* fp I FILE pointer to file containing article. */ X/* hdr I/O Where to put pointer to newly allocated */ X/* HEADER_INFO structure if we allocate one. */ X/* */ X/* RETURNS: */ X/* TRUE Successfully parsed another header from article. */ X/* FALSE Failed/no more headers in article. */ X/* */ X/* COMMENTS: */ X/* Adjusts hdr when done so next call will set correct pointer. */ X/* BBS version terminates header search on a line without a colon, */ X/* or with a space before the colon. Usenet version terminates */ X/* header search on blank line, ignoring "malformed" header lines. */ X/* */ X/* HISTORY: */ X/* 1. 02 Sep 89 Created. */ X/* 2. 30 Dec 89 Added "Sender:" to list of useful headers. */ X/* 3. 21 Oct 90 Don't end header search until blank line. */ X/* */ X/****************************************************************************/ X XGetNextHeader( fp, hdr ) X XFILE *fp; XHEADER_INFO ***hdr; X X{ Xint rc; /* return code from function */ Xchar buf[BUFSIZ]; /* holds input line from article */ Xchar *firstspace, *firstcolon, *data; /* for parsing */ X Xif ( fgets( buf, BUFSIZ, fp ) == NULL ) X rc = FALSE; Xelse X { X firstspace = strchr( buf, ' ' ); X firstcolon = strchr( buf, ':' ); X if ( ( firstcolon == NULL ) || X ( ( firstspace != NULL ) && ( firstspace < firstcolon ) ) ) X { X if ( GetVar( VAR_BBS ) || strspn( buf, " \t\r\n" ) == strlen(buf) ) X rc = FALSE; X else /* junk line, don't end header search */ X rc = TRUE; X } X else X { X *firstcolon = NULL; /* terminate fieldname string */ X# ifndef ARN_CONFIG X/* X * Until a useful way is found to restrict output to interesting headers, X * use this kluge. X * X * Don't actually allocate a header struct because we're not interested in X * other headers, but return TRUE so that we continue to try to get headers. X */ X if ( strcmp( buf, HDR_FROM ) && strcmp( buf, HDR_SUBJECT ) && X strcmp( buf, HDR_DATE ) && strcmp( buf, HDR_SENDER ) && X strcmp( buf, HDR_TO ) ) X return TRUE; X# endif X firstcolon++; /* advance past colon/NULL to value string */ X data = firstcolon + strspn( firstcolon, " \t" ); /* skip white */ X data[strlen(data)-1] = NULL; /* remove trailing newline */ X X /* X * Allocate and fill a new header structure. X */ X X **hdr = (HEADER_INFO *) malloc( sizeof( HEADER_INFO ) ); X (**hdr)->fieldname = strdup( buf ); X (**hdr)->fieldvalue = strdup( data ); X (**hdr)->next = NULLP( HEADER_INFO ); X X /* X * Reset the hdr pointer so next call will continue chain correctly. X */ X X *hdr = &((**hdr)->next); X rc = TRUE; X } X } Xreturn rc; X} X X X/****************************************************************************/ X/* FUNCTION: DumpArticle */ X/* */ X/* PURPOSE: Print article/header info for an article. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* article I Pointer to article structure to dump. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* Debugging function. */ X/* */ X/* HISTORY: */ X/* 1. 02 Sep 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid DumpArticle( article ) X XARTICLE_INFO *article; X X{ XHEADER_INFO *hdr; X Xprintf( "Article: %ld\n", article->number ); Xfor ( hdr = article->headers; hdr != NULLP( HEADER_INFO ); hdr = hdr->next ) X printf( "\t%s: %s\n", hdr->fieldname, hdr->fieldvalue ); Xprintf( "\n" ); X} X X X/****************************************************************************/ X/* FUNCTION: DestroyArticle */ X/* */ X/* PURPOSE: Free all space taken by article/header structure. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* article I The article being destroyed. */ X/* */ X/* RETURNS: */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 02 Sep 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid DestroyArticle( article ) X XARTICLE_INFO *article; X X{ XHEADER_INFO *hdr, *tmp; X Xfor ( hdr = article->headers; hdr != NULLP( HEADER_INFO ); hdr = tmp ) X { X free( hdr->fieldname ); X free( hdr->fieldvalue ); X tmp = hdr->next; X free( hdr ); X } Xfree( article ); X} X X X/****************************************************************************/ X/* FUNCTION: GetHeader */ X/* */ X/* PURPOSE: Retrieve a specific header from a message. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* headers I List of headers. */ X/* name I Name of header to retrieve. */ X/* */ X/* RETURNS: */ X/* */ X/* COMMENTS: */ X/* Makes a local copy of the header value to be returned. Gets */ X/* overwritten each call. */ X/* */ X/* HISTORY: */ X/* 1. 18 Oct 90 Created. */ X/* */ X/****************************************************************************/ X Xchar *GetHeader( headers, name ) X XHEADER_INFO *headers; Xchar *name; X X{ Xstatic char local[MAXLINE]; X Xwhile ( headers ) X { X if ( strcmp( headers -> fieldname, name ) == 0 ) X { X strcpy( local, headers -> fieldvalue ); X return local; X } X headers = headers -> next; X } Xreturn (char *) NULL; X} END_OF_FILE if test 9465 -ne `wc -c <'article.c'`; then echo shar: \"'article.c'\" unpacked with wrong size! fi chmod +x 'article.c' # end of 'article.c' fi if test -f 'article.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'article.h'\" else echo shar: Extracting \"'article.h'\" \(1949 characters\) sed "s/^X//" >'article.h' <<'END_OF_FILE' X/* X * File Name: article.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Define structure holding info for each article. X * Author: Jeff Van Epps X * Created: 02 Sep 89 X * Last Modified: 06 Jan 91 X * Comments: X * History: X * 02 Sep 89/JVE Created. X * 28 Sep 89/JVE Added textpos. X * 18 Oct 90/JVE Added HDR_xxx defines. X * 06 Jan 91/JVE Added subject pointer in article_info as a speed X * optimization. X */ X X/* X * Hold header information for an article. Example: X * X * fieldname="From" fieldvalue="foo@bar.com" X * fieldname="Subject" fieldvalue="Care and Eating of Foo Bars" X * etc. X * X */ X Xtypedef struct header_info { X char *fieldname; /* name of field (before :) */ X char *fieldvalue; /* text of field (after :) */ X struct header_info *next; /* next header in chain */ X } HEADER_INFO; X X/* X * Information for each article. X */ X Xtypedef struct article_info { X long number; /* article number within newsgroup */ X int beenread; /* has article been read? */ X long textpos; /* where headers end/text begins */ X int done; /* generic temporary marker */ X char *subject; /* points at value of Subject hdr */ X struct header_info *headers; /* top of header field chain */ X struct article_info *next; /* ptr to next article in newsgroup */ X } ARTICLE_INFO; X X/* X * Defines for common header fields. X */ X X X# define HDR_FROM "From" X# define HDR_TO "To" X# define HDR_CC "Cc" X# define HDR_SUBJECT "Subject" X# define HDR_SENDER "Sender" X# define HDR_DATE "Date" X X/* X * Declare functions. X */ X X# ifdef sun X XARTICLE_INFO *ParseArticle(); Xint GetNextHeader(); Xvoid DestroyArticle(); Xvoid DumpArticle(); Xchar *GetHeader(); X X# else X XARTICLE_INFO *ParseArticle( char *filename ); Xint GetNextHeader( FILE *fp, HEADER_INFO ***hdr ); Xvoid DestroyArticle( ARTICLE_INFO *article ); Xvoid DumpArticle( ARTICLE_INFO *article ); Xchar *GetHeader( HEADER_INFO *headers, char *name ); X X# endif END_OF_FILE if test 1949 -ne `wc -c <'article.h'`; then echo shar: \"'article.h'\" unpacked with wrong size! fi chmod +x 'article.h' # end of 'article.h' fi if test -f 'barn.config' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'barn.config'\" else echo shar: Extracting \"'barn.config'\" \(776 characters\) sed "s/^X//" >'barn.config' <<'END_OF_FILE' X# arn.config X# X# Configuration file for ARN X X# 'user' is username used when sending mail or followups X Xuser=lordbah X X# 'node' is the UUCP name of the machine we're running on X Xnode=amusing X X# 'domain' is used in constructing 'From:' line in mail. Thus: X# From: $node!$user@$domain ($name) X# X# This might be specific to our setup, but that's too bad (for now). X Xdomain=bisco.kodak.com X X# 'name' used in headers. X Xname=Lord Bah X X# Your favorite editor used to edit replies and followups. X Xeditor=stevie X X# Name of file used as .newsrc X Xnewsrc=.newsrc X X# Name of KILL file. Must start with "KILL"!! X Xkill=KILL X X# Name of signature file to append to outgoing mail and articles. X Xsignature=uulib:.signature X X# Set "bbs" to anything when reading a BBS-type repository. X X#bbs=true END_OF_FILE if test 776 -ne `wc -c <'barn.config'`; then echo shar: \"'barn.config'\" unpacked with wrong size! fi chmod +x 'barn.config' # end of 'barn.config' fi if test -f 'configure.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'configure.c'\" else echo shar: Extracting \"'configure.c'\" \(4912 characters\) sed "s/^X//" >'configure.c' <<'END_OF_FILE' X/* X * File Name: configure.c X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Configuration variable setting, retrieving. X * Functions: Configure, SetVar, GetVar. X * Author: Jeff Van Epps X * Created: 20 Oct 90 X * Last Modified: 20 Oct 90 X * Comments: X * Generic configuration file processor. Reads lines of the form: X * var=value X * from a specified configuration file and stores the names and values. X * White space WILL be considered significant, so don't put any in there X * unless you really want it. No '=' may appear anywhere else on the line. X * X * SetVar(name,value) changes an existing value or creates a new one. X * GetVar(name) returns a pointer to the value of a variable. X * Configure(filename) processes a configuration file. X * X * A line in the configuration file beginning with '#' is a comment. X * Comment lines and blank lines are skipped. X * X * Currently implemented with static limits for name and value length as X * well as number of possible variables. X * X * History: X * 20 Oct 90/JVE Created. X */ X X# include <stdio.h> X# include <string.h> X# include "standard.h" X# include "configure.h" X X# define MAX_VARS 20 X# define MAX_NAME_LEN 10 X# define MAX_VALUE_LEN 40 X Xstatic struct { X char name[MAX_NAME_LEN+1]; /* name of variable */ X char value[MAX_VALUE_LEN+1]; /* its value */ X } vars[MAX_VARS]; X Xstatic int n_vars = 0; X X X/****************************************************************************/ X/* FUNCTION: Configure */ X/* */ X/* PURPOSE: Parse ARN configuration file. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* config_file I Name of configuration file to use. */ X/* */ X/* RETURNS: */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 20 Oct 90 Created. */ X/* */ X/****************************************************************************/ X Xvoid Configure( config_file ) X Xchar *config_file; X X{ XFILE *fp; Xchar s[MAXLINE], *name, *value; X Xif ( ( fp = fopen( config_file, "r" ) ) == NULL ) X { X perror( config_file ); X exit( 1 ); X } Xwhile ( fgets( s, MAXLINE, fp ) != NULL ) X { X s[strlen(s)-1] = NULL; /* kill trailing newline */ X if ( s[0] != '\0' && s[0] != '#' ) /* skip blank and comment lines */ X { X if ( ( name = strtok( s, "=" ) ) == NULL ) X fprintf( stderr, "Can't parse '%s'\n", s ); X else X { X value = strtok( NULL, "=" ); X (void) SetVar( name, value ); X } X } X } Xfclose( fp ); X} X X X/****************************************************************************/ X/* FUNCTION: SetVar */ X/* */ X/* PURPOSE: Set the value of a configuration variable. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* name I Variable name. */ X/* value I Variable value. */ X/* */ X/* RETURNS: */ X/* OK Successful. */ X/* ERROR Unsuccessful. */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 20 Oct 90 Created. */ X/* */ X/****************************************************************************/ X XSetVar( name, value ) X Xchar *name; Xchar *value; X X{ Xint i; X Xif ( strlen( name ) > MAX_NAME_LEN ) X name[MAX_NAME_LEN-1] = NULL; Xif ( strlen( value ) > MAX_VALUE_LEN ) X value[MAX_VALUE_LEN-1] = NULL; Xfor ( i = 0; i < n_vars; i++ ) X if ( strcmp( vars[i].name, name ) == 0 ) X { X strcpy( vars[i].value, value ); X return OK; X } Xif ( n_vars >= MAX_VARS ) X { X fprintf( stderr, "Too many variables!\n" ); X return ERROR; X } Xstrcpy( vars[i].name, name ); Xstrcpy( vars[i].value, value ); Xn_vars++; Xreturn OK; X} X X X/****************************************************************************/ X/* FUNCTION: GetVar */ X/* */ X/* PURPOSE: Return value of configuration variable. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* name I Name of variable. */ X/* */ X/* RETURNS: */ X/* (char *) Pointer to value. */ X/* (char *) NULL No such variable known. */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 20 Oct 90 Created. */ X/* */ X/****************************************************************************/ X Xchar *GetVar( name ) X Xchar *name; X X{ Xint i; X Xfor ( i = 0; i < n_vars; i++ ) X if ( strcmp( vars[i].name, name ) == 0 ) X return vars[i].value; Xreturn NULLP( char ); X} END_OF_FILE if test 4912 -ne `wc -c <'configure.c'`; then echo shar: \"'configure.c'\" unpacked with wrong size! fi chmod +x 'configure.c' # end of 'configure.c' fi if test -f 'configure.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'configure.h'\" else echo shar: Extracting \"'configure.h'\" \(575 characters\) sed "s/^X//" >'configure.h' <<'END_OF_FILE' X/* X * File Name: configure.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Configuration variable setting, retrieving. X * Author: Jeff Van Epps X * Created: 20 Oct 90 X * Last Modified: 20 Oct 90 X * Comments: X * For implementation limits, see configure.c. X * X * History: X * 20 Oct 90/JVE Created. X */ X X# ifdef sun X Xextern void Configure(); Xextern int SetVar(); Xextern char * GetVar(); X X# else /* amiga */ X Xextern void Configure( char *config_file ); Xextern int SetVar( char *name, char *value ); Xextern char * GetVar( char *name ); X X# endif /* sun/amiga */ END_OF_FILE if test 575 -ne `wc -c <'configure.h'`; then echo shar: \"'configure.h'\" unpacked with wrong size! fi chmod +x 'configure.h' # end of 'configure.h' fi if test -f 'kill.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kill.c'\" else echo shar: Extracting \"'kill.c'\" \(6070 characters\) sed "s/^X//" >'kill.c' <<'END_OF_FILE' X/* X * File Name: kill.c X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Defines functions related to kill list. X * Functions: GetKillList, PutKillList, DestroyKillList. X * Author: Jeff Van Epps X * Created: 04 Sep 89 X * Last Modified: 22 Oct 90 X * Comments: X * History: X * 04 Sep 89/JVE Created. X * 30 Dec 89/JVE Implemented GetKillList and PutKillList, which were X * only stubbed previously. X * 22 Oct 90/JVE Added regular expression capability in kill files. X * A kill list is no longer just a list of HEADER_INFOs, X * it now has its own structure. X */ X X# include <stdio.h> X# include <stdlib.h> X# include <string.h> X# include <fcntl.h> X# include <regexp.h> X# include "standard.h" X# include "article.h" X# include "kill.h" X X X/****************************************************************************/ X/* FUNCTION: GetKillList */ X/* */ X/* PURPOSE: Parse the kill file which applies to all newsgroups. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* filename I Name of kill file. */ X/* */ X/* RETURNS: */ X/* (KILL_INFO *) Pointer to start of kill list. */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 30 Dec 89 Created. */ X/* */ X/****************************************************************************/ X XKILL_INFO *GetKillList( filename ) X Xchar *filename; X X{ XKILL_INFO *root = NULLP( KILL_INFO ); XKILL_INFO **ptr; XFILE *fp; X Xif ( ( fp = fopen( filename, "r" ) ) != NULLP( FILE ) ) X { X ptr = &root; X while ( GetNextKill( fp, &ptr ) ) ; X fclose( fp ); X } Xreturn root; X} X X X/****************************************************************************/ X/* FUNCTION: PutKillList */ X/* */ X/* PURPOSE: Write back a kill list to specified file. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* filename I File in which to put kill list. */ X/* root I Pointer to start of kill list. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 30 Dec 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid PutKillList( filename, root ) X Xchar *filename; XKILL_INFO *root; X X{ XFILE *fp; X Xremove( filename ); Xif ( ( fp = fopen( filename, "a" ) ) != NULLP( FILE ) ) X { X while ( root != NULLP( KILL_INFO ) ) X { X fprintf( fp, "%s: %s\n", root->fieldname, root->fieldvalue ); X root = root->next; X } X fclose( fp ); X } X} X X X/****************************************************************************/ X/* FUNCTION: DestroyKillList */ X/* */ X/* PURPOSE: Release memory consumed by construction of kill list. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* root I Pointer to start of kill list. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 04 Sep 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid DestroyKillList( root ) X XKILL_INFO *root; X X{ XKILL_INFO *tmp; X Xfor ( ; root != NULLP( KILL_INFO ); root = tmp ) X { X tmp = root->next; X free( root -> fieldname ); X free( root -> fieldvalue ); X free( (char *) ( root -> pattern ) ); X free( root ); X } X} X X/****************************************************************************/ X/* FUNCTION: GetNextKill */ X/* */ X/* PURPOSE: Parses the next kill entry from a kill file. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* fp I FILE pointer to file containing article. */ X/* hdr I/O Where to put pointer to newly allocated */ X/* KILL_INFO structure if we allocate one. */ X/* */ X/* RETURNS: */ X/* TRUE Successfully parsed another entry from file. */ X/* FALSE Failed/no more entries. */ X/* */ X/* COMMENTS: */ X/* Adjusts hdr when done so next call will set correct pointer. */ X/* */ X/* HISTORY: */ X/* 1. 22 Oct 90 Created from GetNextHeader. */ X/* */ X/****************************************************************************/ X XGetNextKill( fp, hdr ) X XFILE *fp; XKILL_INFO ***hdr; X X{ Xint rc; /* return code from function */ Xchar buf[BUFSIZ]; /* holds input line from article */ Xchar *firstspace, *firstcolon, *data; /* for parsing */ X Xif ( fgets( buf, BUFSIZ, fp ) == NULL ) X rc = FALSE; Xelse X { X firstspace = strchr( buf, ' ' ); X firstcolon = strchr( buf, ':' ); X if ( ( firstcolon == NULL ) || X ( ( firstspace != NULL ) && ( firstspace < firstcolon ) ) ) X rc = FALSE; X else X { X *firstcolon = NULL; /* terminate fieldname string */ X firstcolon++; /* advance past colon/NULL to value string */ X data = firstcolon + strspn( firstcolon, " \t" ); /* skip white */ X data[strlen(data)-1] = NULL; /* remove trailing newline */ X X /* X * Allocate and fill a new kill structure. X */ X X **hdr = (KILL_INFO *) malloc( sizeof( KILL_INFO ) ); X (**hdr)->fieldname = strdup( buf ); X (**hdr)->fieldvalue = strdup( data ); X (**hdr)->pattern = regcomp( data ); X if ( (**hdr) -> pattern == NULL ) X fprintf( stderr, "Bad kill pattern '%s'\n", data ); X (**hdr)->next = NULLP( KILL_INFO ); X X /* X * Reset the hdr pointer so next call will continue chain correctly. X */ X X *hdr = &((**hdr)->next); X rc = TRUE; X } X } Xreturn rc; X} END_OF_FILE if test 6070 -ne `wc -c <'kill.c'`; then echo shar: \"'kill.c'\" unpacked with wrong size! fi chmod +x 'kill.c' # end of 'kill.c' fi if test -f 'kill.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kill.h'\" else echo shar: Extracting \"'kill.h'\" \(918 characters\) sed "s/^X//" >'kill.h' <<'END_OF_FILE' X/* X * File Name: kill.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Define kill structures. X * Author: Jeff Van Epps X * Created: 04 Sep 89 X * Last Modified: 22 Oct 90 X * Comments: X * Include "regexp.h" before "kill.h". X * X * History: X * 04 Sep 89/JVE Created. X * 22 Oct 90/JVE New KILL_INFO structure includes regexp pattern. X */ X X/* X * A kill list is a list of kill_info structures. An article matching any X * kill structure will be "killed". X */ X Xtypedef struct kill_info { X char *fieldname; X char *fieldvalue; X struct regexp *pattern; X struct kill_info *next; /* ptr to next article in newsgroup */ X } KILL_INFO; X X/* X * Function prototypes. X */ X X# ifdef sun X XKILL_INFO *GetKillList(); Xvoid PutKillList(); Xvoid DestroyKillList(); X X# else X XKILL_INFO *GetKillList( char *filename ); Xvoid PutKillList( char *filename, KILL_INFO *root ); Xvoid DestroyKillList( KILL_INFO *root ); X X# endif END_OF_FILE if test 918 -ne `wc -c <'kill.h'`; then echo shar: \"'kill.h'\" unpacked with wrong size! fi chmod +x 'kill.h' # end of 'kill.h' fi if test -f 'ng.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ng.c'\" else echo shar: Extracting \"'ng.c'\" \(11353 characters\) sed "s/^X//" >'ng.c' <<'END_OF_FILE' X/* X * File Name: ng.c X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Defines functions related to newsgroup list. X * Functions: GetNewsRC, ReadNextMarker, PutNewsRC, DestroyNGList, X * NumberCovered, UpdateReadList, Mark. X * Author: Jeff Van Epps X * Created: 03 Sep 89 X * Last Modified: 14 Nov 90 X * Comments: X * History: X * 03 Sep 89/JVE Created. X * 21 Oct 90/JVE Moved UpdateReadList, Mark from arn.c to here where X * they belong. X * 14 Nov 90/JVE Made sure a marker for article 0 gets created if X * no other articles have been read. X */ X X# include <stdio.h> X# include <stdlib.h> X# include <string.h> X# include <fcntl.h> X# include "standard.h" X# include "article.h" X# include "ng.h" X X X/****************************************************************************/ X/* FUNCTION: GetNewsRC */ X/* */ X/* PURPOSE: Read/parse the .newsrc file. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* filename I Name of file containing read newsgroups info. */ X/* */ X/* RETURNS: */ X/* */ X/* COMMENTS: */ X/* Parses lines from user's .newsrc file to see which articles in */ X/* which newsgroups have already been read. */ X/* */ X/* HISTORY: */ X/* 1. 03 Sep 89 Created. */ X/* */ X/****************************************************************************/ X XNG_INFO *GetNewsRC( filename ) X Xchar *filename; X X{ XNG_INFO *root = NULLP( NG_INFO ); /* points to start of ng list */ XNG_INFO **ptr = &root; /* where to alloc next ng from */ XMARKER **marker; /* where to alloc next marker from */ XFILE *fp; /* pointer into .newsrc file */ Xchar buf[BUFSIZ]; Xchar *name; /* newsgroup name */ X Xif ( ( fp = fopen( filename, "r" ) ) == NULLP( FILE ) ) X perror( filename ); Xelse X { X while ( fgets( buf, BUFSIZ, fp ) != NULLP( char ) ) X { X if ( ( name = strtok( buf, " " ) ) == NULLP( char ) ) X fprintf( stderr, "Bad line in %s: %s", filename, buf ); X else X { X *ptr = (NG_INFO *) malloc( sizeof( NG_INFO ) ); X (*ptr)->next = NULLP( NG_INFO ); X (*ptr)->markers = NULLP( MARKER ); X marker = &(*ptr)->markers; X while ( ReadNextMarker( &marker ) ) ; X (*ptr)->name = strdup( name ); X ptr = &(*ptr)->next; X } X } X fclose( fp ); X } Xreturn root; X} X X X/****************************************************************************/ X/* FUNCTION: ReadNextMarker */ X/* */ X/* PURPOSE: Parse next marker from line. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* marker I/O Pointer to pointer to next marker. */ X/* */ X/* RETURNS: */ X/* TRUE Marker parsed. */ X/* FALSE No marker parsed (end of input line). */ X/* */ X/* COMMENTS: */ X/* markers = [ marker | marker + ',' + markers ] */ X/* marker = [ XXX | XXX + '-' + YYY ] */ X/* */ X/* There may be a list of markers with each marker separated by a */ X/* comma. Each marker may be either a single number or two numbers */ X/* separated by a dash indicating an inclusive range. White space */ X/* is not allowed anywhere. */ X/* */ X/* We assume that the string we are parsing has already been subject */ X/* to a strtok() call so that we can just strtok(NULL,x) to continue */ X/* parsing the same string. */ X/* */ X/* HISTORY: */ X/* 1. 03 Sep 89 Created. */ X/* */ X/****************************************************************************/ X XReadNextMarker( marker ) X XMARKER ***marker; X X{ Xint rc = FALSE; Xchar *p, *q; X Xif ( ( p = strtok( NULLP( char ), "," ) ) != NULLP( char ) ) X { X **marker = (MARKER *) malloc( sizeof( MARKER ) ); X (**marker)->next = NULLP( MARKER ); X (**marker)->from = atol( p ); X if ( ( q = strchr( p, '-' ) ) != NULLP( char ) ) X (**marker)->to = atol( ++q ); X else X (**marker)->to = 0L; X *marker = &(**marker)->next; X rc = TRUE; X } Xreturn rc; X} X X X/****************************************************************************/ X/* FUNCTION: PutNewsRC */ X/* */ X/* PURPOSE: Write read article markers to .newsrc file. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* filename I Name of file to which to write .newsrc info. */ X/* root I List of already read articles. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* Tries to save old .newsrc file as .newsrc.BAK before writing new */ X/* one. */ X/* */ X/* HISTORY: */ X/* 1. 03 Sep 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid PutNewsRC( filename, root ) X Xchar *filename; XNG_INFO *root; X X{ Xchar backup[BUFSIZ], temp[BUFSIZ]; XFILE *fp; XMARKER *ptr; X Xsprintf( backup, "%s.BAK", filename ); X(void) remove( backup ); Xif ( rename( filename, backup ) ) X { X sprintf( temp, "rename(%s,%s)", filename, backup ); X perror( temp ); X } Xelse X { X if ( ( fp = fopen( filename, "a" ) ) == NULLP( FILE ) ) X perror( filename ); X else X { X while ( root != NULLP( NG_INFO ) ) X { X fprintf( fp, "%s ", root->name ); X for ( ptr = root->markers; ptr != NULLP( MARKER ); ) X { X fprintf( fp, "%ld", ptr->from ); X if ( ptr->to > 0L ) X fprintf( fp, "-%ld", ptr->to ); X if ( ptr = ptr->next ) X fprintf( fp, "," ); X } X fprintf( fp, "\n" ); X root = root->next; X } X fclose( fp ); X } X } X} X X X/****************************************************************************/ X/* FUNCTION: DestroyNGList */ X/* */ X/* PURPOSE: Free memory taken by newsgroup list. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* root I Pointer to list of newsgroups. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 03 Sep 89 Created. */ X/* */ X/****************************************************************************/ X Xvoid DestroyNGList( root ) X XNG_INFO *root; X X{ XMARKER *ptr, *tmp; XNG_INFO *next; X Xwhile ( root != NULLP( NG_INFO ) ) X { X for ( ptr = root->markers; ptr != NULLP( MARKER ); ptr = tmp ) X { X tmp = ptr->next; X free( ptr ); X } X free( root->name ); X next = root->next; X free( root ); X root = next; X } X} X X X/****************************************************************************/ X/* FUNCTION: NumberCovered */ X/* */ X/* PURPOSE: Check whether number is covered by markers. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* markers I Marker list. */ X/* number I Number to be checked. */ X/* */ X/* RETURNS: */ X/* TRUE If number is in list. */ X/* FALSE If number is not in list. */ X/* */ X/* COMMENTS: */ X/* Markers are assumed to be sorted low->high and non-overlapping. */ X/* */ X/* HISTORY: */ X/* 1. 04 Sep 89 Created. */ X/* */ X/****************************************************************************/ X XNumberCovered( markers, number ) X XMARKER *markers; Xlong number; X X{ Xint rc = FALSE; X Xwhile ( !rc && markers != NULLP( MARKER ) ) X { X if ( markers->from > number ) X break; X else if ( markers->from == number ) X rc = TRUE; X else if ( markers->to >= number ) X rc = TRUE; X markers = markers->next; X } Xreturn rc; X} X X X/****************************************************************************/ X/* FUNCTION: UpdateReadList */ X/* */ X/* PURPOSE: Update the list of articles read due to newly read ones. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* ng I/O List of read articles. */ X/* new I List containing some newly read articles. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* Look for articles which are STILL unread, and make a list which */ X/* marks everything except those. If nothing is left unread, the list */ X/* should mark to the greater of the previously highest read article */ X/* and the highest newly read article. */ X/* */ X/* HISTORY: */ X/* 1. 04 Sep 89 Created. */ X/* 2. 16 Dec 89 Fixed bug in last mark if last article unread. */ X/* 3. 14 Nov 90 Make sure *something* gets marked, i.e. 0-0 if */ X/* nothing else. */ X/* */ X/****************************************************************************/ X Xvoid UpdateReadList( ng, new ) X XNG_INFO *ng; XARTICLE_INFO *new; X X{ Xlong beginning, ending; XMARKER **where; /* where to allocate next marker */ XMARKER *first = NULL; /* ptr to beginning of new marker list */ XMARKER *ptr, *tmp; X Xfor ( ptr = ng->markers; ptr != NULLP( MARKER ); ptr = tmp ) X { X if ( ptr->to != 0L ) X ending = ptr->to; X else X ending = ptr->from; X tmp = ptr->next; X free( ptr ); X } Xbeginning = 1L; Xwhere = &first; Xfor ( ; new != NULLP( ARTICLE_INFO ); new = new->next ) X { X if ( ! new->beenread ) X { X if ( new->number != beginning && beginning <= ending ) X { X *where = Mark( beginning, new->number - 1L ); X where = & (*where)->next; X } X beginning = new->number + 1L; X } X else if ( new->number > ending ) X ending = new->number; X } Xif ( beginning <= ending ) X *where = Mark( beginning, ending ); X/* X * If no markers have been created, create one for article # 0. X */ Xif ( first == NULL ) X *where = Mark( 0L, 0L ); Xng->markers = first; X} X X X/****************************************************************************/ X/* FUNCTION: Mark */ X/* */ X/* PURPOSE: Create a marker. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* begin I From part of marker. */ X/* end I To part of marker. */ X/* */ X/* RETURNS: */ X/* (MARKER *) Pointer to new marker. */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 05 Sep 89 Created. */ X/* */ X/****************************************************************************/ X XMARKER *Mark( begin, end ) X Xlong begin, end; X X{ XMARKER *ptr; X Xptr = (MARKER *) malloc( sizeof( MARKER ) ); Xptr->from = begin; Xif ( begin == end ) X ptr->to = 0L; Xelse X ptr->to = end; Xptr->next = NULLP( MARKER ); Xreturn ptr; X} X END_OF_FILE if test 11353 -ne `wc -c <'ng.c'`; then echo shar: \"'ng.c'\" unpacked with wrong size! fi chmod +x 'ng.c' # end of 'ng.c' fi if test -f 'ng.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ng.h'\" else echo shar: Extracting \"'ng.h'\" \(1491 characters\) sed "s/^X//" >'ng.h' <<'END_OF_FILE' X/* X * File Name: ng.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Define newsgroup structures. X * Author: Jeff Van Epps X * Created: 02 Sep 89 X * Last Modified: 21 Oct 90 X * History: X * 02 Sep 89/JVE Created. X * 21 Oct 90/JVE Added declarations for UpdateReadList, Mark. X */ X X/* X * MARKER is used to mark either a single number or a range. If to==0, X * from indicates the single number to be marked. Otherwise all numbers X * between and including from and to should be marked. X */ X Xtypedef struct marker_info { X long from, to; /* article numbers */ X struct marker_info *next; /* pointer to next marker record */ X } MARKER; X X/* X * NG_INFO records names of newsgroups and which articles have been read X * in each newsgroup. X */ X Xtypedef struct ng_info { X char *name; /* name of newsgroup */ X MARKER *markers; /* ptr to list of article #s read */ X struct ng_info *next; /* ptr to next newsgroup in list */ X } NG_INFO; X X/* X * Function prototypes. X */ X X# ifdef sun X XNG_INFO *GetNewsRC(); Xint ReadNextMarker(); Xvoid PutNewsRC(); Xvoid DestroyNGList(); Xint NumberCovered(); Xvoid UpdateReadList(); XMARKER * Mark(); X X# else X XNG_INFO *GetNewsRC( char *filename ); Xint ReadNextMarker( MARKER ***marker ); Xvoid PutNewsRC( char *filename, NG_INFO *alreadyread ); Xvoid DestroyNGList( NG_INFO *alreadyread ); Xint NumberCovered( MARKER *marker, long number ); Xvoid UpdateReadList( NG_INFO *ng, ARTICLE_INFO *new ); XMARKER * Mark( long begin, long end ); X X# endif END_OF_FILE if test 1491 -ne `wc -c <'ng.h'`; then echo shar: \"'ng.h'\" unpacked with wrong size! fi chmod +x 'ng.h' # end of 'ng.h' fi if test -f 'raw.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'raw.c'\" else echo shar: Extracting \"'raw.c'\" \(2268 characters\) sed "s/^X//" >'raw.c' <<'END_OF_FILE' X/* X * raw.c X * X * This is a routine for setting a given stream to raw or cooked mode on the X * Amiga . This is useful when you are using Lattice C to produce programs X * that want to read single characters with the "getch()" or "fgetc" call. X * X * Written : 18-Jun-87 By Chuck McManis. X */ X#include <exec/types.h> X#include <libraries/dos.h> X#include <libraries/dosextens.h> X#include <stdio.h> X X#include <ios1.h> X#include <error.h> X Xextern int errno; /* The error variable */ X X/* X * Function raw() - Convert the specified file pointer to 'raw' mode. This X * only works on TTY's and essentially keeps DOS from translating keys for X * you, also (BIG WIN) it means getch() will return immediately rather than X * wait for a return. You lose editing features though. X */ Xlong Xraw(fp) X FILE *fp; X X{ X struct MsgPort *mp; /* The File Handle message port */ X struct FileHandle *afh; X struct UFB *ufb; X long Arg[1], res; X X ufb = (struct UFB *) chkufb(fileno(fp)); /* Step one, get the file X * handle */ X afh = (struct FileHandle *) (ufb->ufbfh); X X if (!IsInteractive(afh)) { /* Step two, check to see if it's a console */ X errno = ENOTTY; X return (-1); X } X /* Step three, get it's message port. */ X mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; X Arg[0] = -1L; X res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); /* Put it in RAW: mode */ X if (res == 0) { X errno = ENXIO; X return (-1); X } X return (0); X} X X/* X * Function - cooked() this function returns the designate file pointer to X * it's normal, wait for a <CR> mode. This is exactly like raw() except that X * it sends a 0 to the console to make it back into a CON: from a RAW: X */ X Xlong Xcooked(fp) X FILE *fp; X X{ X struct MsgPort *mp; /* The File Handle message port */ X struct FileHandle *afh; X struct UFB *ufb; X long Arg[1], res; X X ufb = (struct UFB *) chkufb(fileno(fp)); X afh = (struct FileHandle *) (ufb->ufbfh); X if (!IsInteractive(afh)) { X errno = ENOTTY; X return (-1); X } X mp = ((struct FileHandle *) (BADDR(afh)))->fh_Type; X Arg[0] = 0; X res = SendPacket(mp, ACTION_SCREEN_MODE, Arg, 1); X if (res == 0) { X errno = ENXIO; X return (-1); X } X return (0); X} END_OF_FILE if test 2268 -ne `wc -c <'raw.c'`; then echo shar: \"'raw.c'\" unpacked with wrong size! fi chmod +x 'raw.c' # end of 'raw.c' fi if test -f 'reply.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'reply.c'\" else echo shar: Extracting \"'reply.c'\" \(8860 characters\) sed "s/^X//" >'reply.c' <<'END_OF_FILE' X/* X * File Name: reply.c X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Reply via email and post followup article functions. X * Functions: Reply, Followup, IncludeArticle, Sign. X * Author: Jeff Van Epps X * Created: 21 Oct 90 X * Last Modified: 05 Jan 91 X * Comments: X * History: X * 21 Oct 90/JVE Created. X * 14 Nov 90/JVE Post news by mailing article to inews@bisco rather X * than <newsgroup>@ucbvax.berkeley.edu. Only mail the X * article if the user saved his edit. Same for X * email replies. X * 05 Jan 91/JVE Use article->subject optimization. X */ X X# include <stdio.h> X# include <stdlib.h> X# include <string.h> X# include <time.h> X# include <sys/types.h> X# include <sys/stat.h> X# include "standard.h" X# include "configure.h" X# include "variables.h" X# include "article.h" X# include "reply.h" X X# ifdef sun X X# define DEFAULT_EDITOR "vi" X# define TEMPFILE "/tmp/arnreply" X X# else /* not sun */ X X# define DEFAULT_EDITOR "stevie" X# define TEMPFILE "T:arnreply" X X# endif /* sun */ X X X/****************************************************************************/ X/* FUNCTION: Reply */ X/* */ X/* PURPOSE: Send a reply to a news article via mail. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* article I Article to reply to. */ X/* include I Include article in reply? */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 17 Oct 90 Created. */ X/* 2. 14 Nov 90 Do not invoke mailer if user has not edited. */ X/* */ X/****************************************************************************/ X Xvoid Reply( article, include ) X XARTICLE_INFO *article; Xint include; X X{ XFILE *fp; Xchar *from, *address, *editor, *hdr; Xchar cmd[MAXLINE], temp[MAXLINE]; Xlong clock; /* current date & time */ Xint header_found = FALSE; /* parsed To: yet? */ Xstruct stat stats_before, stats_after; X Xremove( TEMPFILE ); Xif ( ( fp = fopen( TEMPFILE, "a" ) ) == NULL ) X { X perror( TEMPFILE ); X return; X } Xtime( &clock ); Xfprintf( fp, "From %s %24.24s remote from %s\n", GetVar( VAR_USER), X ctime( &clock ), GetVar( VAR_NODE ) ); Xfprintf( fp, "Date: %s", ctime( &clock ) ); Xfprintf( fp, "From: %s!%s@%s (%s)\n", GetVar( VAR_NODE ), GetVar( VAR_USER ), X GetVar( VAR_DOMAIN ), GetVar( VAR_NAME ) ); X/* X * Use everything after From: up to the first space. X */ Xfrom = strtok( GetHeader( article -> headers, HDR_FROM ), " \n\r" ); Xfprintf( fp, "%s: %s\n", HDR_TO, from ); Xfprintf( fp, "%s: \n", HDR_CC ); Xfprintf( fp, "%s: %s\n\n", HDR_SUBJECT, article -> subject ); Xif ( include ) X IncludeArticle( article, fp ); XSign( fp ); Xfclose( fp ); X(void) stat( TEMPFILE, &stats_before ); Xif ( ( editor = GetVar( VAR_EDITOR ) ) == NULL ) X editor = DEFAULT_EDITOR; Xsprintf( cmd, "%s %s", editor, TEMPFILE ); Xsystem( cmd ); X(void) stat( TEMPFILE, &stats_after ); Xif ( stats_after.st_mtime != stats_before.st_mtime ) X { X if ( ( fp = fopen( TEMPFILE, "r" ) ) == NULL ) X { X perror( TEMPFILE ); X return; X } X while ( ! header_found && fgets( temp, MAXLINE, fp ) != NULL ) X { X if ( ( hdr = strtok( temp, ": " ) ) != NULL && strcmp( hdr, HDR_TO ) == 0 ) X header_found = TRUE; X } X if ( ! header_found ) X { X printf( "Header messed!\n" ); X fclose( fp ); X return; X } X if ( ( address = strtok( NULL, " " ) ) == NULL ) X { X printf( "No address given!\n" ); X fclose( fp ); X return; X } X fclose( fp ); X sprintf( cmd, "rmail <%s >NULL: %s", TEMPFILE, address ); X system( cmd ); X } Xelse X { X printf( "File not modified. Mail not sent. Hit any key.\n" ); X getchar(); X } Xremove( TEMPFILE ); X} X X/****************************************************************************/ X/* FUNCTION: Followup */ X/* */ X/* PURPOSE: Post news article as a reply to a news article. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* newsgroup I Name of newsgroup. */ X/* article I Article to followup. */ X/* include I Include article in reply? */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* Changed to send mail to inews@bisco. Newsgroup name is embedded */ X/* in the article. */ X/* */ X/* The newsgroup name has all dots or slashes turned into dashes, then */ X/* mail is sent to <modified newsgroup name>@ucbvax.berkeley.edu, */ X/* which is a gateway for posting. */ X/* */ X/* HISTORY: */ X/* 1. 17 Oct 90 Created. */ X/* 2. 14 Nov 90 Mail to bisco rather than Berkeley. Only */ X/* mail the article if it has been edited by user. */ X/* */ X/****************************************************************************/ X Xvoid Followup( newsgroup, article, include ) X Xchar *newsgroup; XARTICLE_INFO *article; Xint include; X X{ XFILE *fp; Xchar *editor; Xchar cmd[MAXLINE]; Xlong clock; /* current date & time */ Xstruct stat stats_before, stats_after; X Xremove( TEMPFILE ); Xif ( ( fp = fopen( TEMPFILE, "a" ) ) == NULL ) X { X perror( TEMPFILE ); X return; X } Xtime( &clock ); Xfprintf( fp, "From %s %24.24s remote from %s\n", GetVar( VAR_USER ), X ctime( &clock ), GetVar( VAR_NODE ) ); Xfprintf( fp, "Date: %s", ctime( &clock ) ); Xfprintf( fp, "From: %s!%s@%s (%s)\n", GetVar( VAR_NODE ), GetVar( VAR_USER ), X GetVar( VAR_DOMAIN ), GetVar( VAR_NAME ) ); Xfprintf( fp, "%s: %s\n", HDR_SUBJECT, article -> subject ); Xfprintf( fp, "Newsgroups: %s\n", newsgroup ); Xfprintf( fp, "Followup-To: %s\n", newsgroup ); Xfprintf( fp, "Distribution: world\n" ); Xfprintf( fp, "Reply-To: %s!%s@%s\n", GetVar( VAR_NODE ), GetVar( VAR_USER ), X GetVar( VAR_DOMAIN ) ); Xfprintf( fp, "\n" ); /* separate headers from body of article */ Xif ( include ) X IncludeArticle( article, fp ); XSign( fp ); Xfclose( fp ); X(void) stat( TEMPFILE, &stats_before ); Xif ( ( editor = GetVar( VAR_EDITOR ) ) == NULL ) X editor = DEFAULT_EDITOR; Xsprintf( cmd, "%s %s", editor, TEMPFILE ); Xsystem( cmd ); X(void) stat( TEMPFILE, &stats_after ); Xif ( stats_after.st_mtime != stats_before.st_mtime ) X { X sprintf( cmd, "rmail <%s >NULL: inews@bisco", TEMPFILE ); X system( cmd ); X } Xelse X { X printf( "File not modified. Article not posted. Hit any key.\n" ); X getchar(); X } Xremove( TEMPFILE ); X} X X X/****************************************************************************/ X/* FUNCTION: IncludeArticle */ X/* */ X/* PURPOSE: Copy article text to file as an inclusion. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* article I Article being included. */ X/* output I File being written into. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* */ X/* HISTORY: */ X/* 1. 21 Oct 90 Created. */ X/* */ X/****************************************************************************/ X Xvoid IncludeArticle( article, output ) X XARTICLE_INFO *article; XFILE *output; X X{ Xchar filename[MAXLINE]; Xchar s[MAXLINE]; XFILE *art; X Xsprintf( filename, "%ld", article -> number ); Xif ( ( art = fopen( filename, "r" ) ) == NULL ) X printf( "CAN'T OPEN ARTICLE FOR INCLUDE!\n" ); Xelse X { X fseek( art, article -> textpos, 0 ); X while ( fgets( s, MAXLINE, art ) != NULL ) X fprintf( output, "> %s", s ); X fclose( art ); X } X} X X X/****************************************************************************/ X/* FUNCTION: Sign */ X/* */ X/* PURPOSE: Append users .signature. */ X/* */ X/* INPUT PARAMETERS: */ X/* NAME I/O DESCRIPTION */ X/* ---- --- ----------- */ X/* output I File being written to. */ X/* */ X/* RETURNS: none */ X/* */ X/* COMMENTS: */ X/* There is no default .signature file. */ X/* */ X/* HISTORY: */ X/* 1. 21 Oct 90 Created. */ X/* */ X/****************************************************************************/ X Xvoid Sign( output ) X XFILE *output; X X{ XFILE *sig; Xchar *sig_file; /* filename for .signature */ Xchar s[MAXLINE]; X Xif ( ( sig_file = GetVar( VAR_SIGN ) ) != NULL && X ( sig = fopen( sig_file, "r" ) ) != NULL ) X { X while ( fgets( s, MAXLINE, sig ) != NULL ) X fprintf( output, "%s", s ); X fclose( sig ); X } X} END_OF_FILE if test 8860 -ne `wc -c <'reply.c'`; then echo shar: \"'reply.c'\" unpacked with wrong size! fi chmod +x 'reply.c' # end of 'reply.c' fi if test -f 'reply.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'reply.h'\" else echo shar: Extracting \"'reply.h'\" \(644 characters\) sed "s/^X//" >'reply.h' <<'END_OF_FILE' X/* X * File Name: reply.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Reply and Followup functions. X * Author: Jeff Van Epps X * Created: 21 Oct 90 X * Last Modified: 21 Oct 90 X * Comments: X * History: X * 21 Oct 90/JVE Created. X */ X X# ifdef sun X Xextern void Reply(); Xextern void Followup(); Xextern void IncludeArticle(); Xextern void Sign(); X X# else /* amiga */ X Xextern void Reply( ARTICLE_INFO *article, int include ); Xextern void Followup( char *newsgroup, ARTICLE_INFO *article, int include ); Xextern void IncludeArticle( ARTICLE_INFO *article, FILE *output ); Xextern void Sign( FILE *output ); X X# endif /* sun/amiga */ END_OF_FILE if test 644 -ne `wc -c <'reply.h'`; then echo shar: \"'reply.h'\" unpacked with wrong size! fi chmod +x 'reply.h' # end of 'reply.h' fi if test -f 'screenstuff.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'screenstuff.h'\" else echo shar: Extracting \"'screenstuff.h'\" \(871 characters\) sed "s/^X//" >'screenstuff.h' <<'END_OF_FILE' X/* X * File Name: screenstuff.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Screen attribute defines. X * Author: Jeff Van Epps X * Created: 06 Jan 91 X * Last Modified: 06 Jan 91 X * Comments: X * If compiling on a Sun we try to use the System V version of the X * curses library. On the Amiga we use ANSI sequences. X * X * History: X * 06 Jan 91/JVE Created. X */ X X X# ifdef sun X X# include <curses.h> X# define Clear_Screen clear() X# define UL_ON attron( A_UNDERLINE ) X# define UL_OFF attroff( A_UNDERLINE ) X# define INVERSE_ON attron( A_REVERSE ) X# define INVERSE_OFF attroff( A_REVERSE ) X X# else /* not sun */ X X# define Clear_Screen printf("\x1b[H\x1b[2J") X# define UL_ON printf( "\x1b[4m" ) X# define UL_OFF printf( "\x1b[0m" ) X# define INVERSE_ON printf("\x9b\x37;38;40m") X# define INVERSE_OFF printf("\x9b\x30;33;40m\033[0m") X X# endif /* sun */ END_OF_FILE if test 871 -ne `wc -c <'screenstuff.h'`; then echo shar: \"'screenstuff.h'\" unpacked with wrong size! fi chmod +x 'screenstuff.h' # end of 'screenstuff.h' fi if test -f 'sendpacket.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sendpacket.c'\" else echo shar: Extracting \"'sendpacket.c'\" \(2093 characters\) sed "s/^X//" >'sendpacket.c' <<'END_OF_FILE' X/* X * Sendpacket.c X * X * An invaluable addition to your Amiga.lib file. This code sends a packet the X * given message port. This makes working around DOS lots easier. X * X * Note, I didn't write this, those wonderful folks at CBM did. I do suggest X * however that you may wish to add it to Amiga.Lib, to do so, compile it and X * say 'oml lib:amiga.lib -r sendpacket.o' X */ X X#include <exec/types.h> X#include <exec/ports.h> X#include <exec/memory.h> X#include <libraries/dos.h> X#include <libraries/dosextens.h> X X/* X * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and Andy X * Finkel. This function will send a packet of the given type to the Message X * Port supplied. X */ X Xlong XSendPacket(pid, action, args, nargs) X struct MsgPort *pid; /* process indentifier ... (handlers message X * port ) */ X long action, /* packet type ... (what you want handler to X * do ) */ X args[], /* a pointer to a argument list */ X nargs; /* number of arguments in list */ X{ X struct MsgPort *replyport; X struct StandardPacket *packet; X X long count, *pargs, res1; X X replyport = (struct MsgPort *) CreatePort(NULL, 0); X if (!replyport) X return (0); X X /* Allocate space for a packet, make it public and clear it */ X packet = (struct StandardPacket *) X AllocMem((long) sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR); X if (!packet) { X DeletePort(replyport); X return (0); X } X packet->sp_Msg.mn_Node.ln_Name = (char *) &(packet->sp_Pkt); X packet->sp_Pkt.dp_Link = &(packet->sp_Msg); X packet->sp_Pkt.dp_Port = replyport; X packet->sp_Pkt.dp_Type = action; X X /* copy the args into the packet */ X pargs = &(packet->sp_Pkt.dp_Arg1); /* address of first argument */ X for (count = 0; count < nargs; count++) X pargs[count] = args[count]; X X PutMsg(pid, packet); /* send packet */ X X WaitPort(replyport); X GetMsg(replyport); X X res1 = packet->sp_Pkt.dp_Res1; X X FreeMem(packet, (long) sizeof(struct StandardPacket)); X DeletePort(replyport); X X return (res1); X} END_OF_FILE if test 2093 -ne `wc -c <'sendpacket.c'`; then echo shar: \"'sendpacket.c'\" unpacked with wrong size! fi chmod +x 'sendpacket.c' # end of 'sendpacket.c' fi if test -f 'standard.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'standard.h'\" else echo shar: Extracting \"'standard.h'\" \(535 characters\) sed "s/^X//" >'standard.h' <<'END_OF_FILE' X/* X * File: standard.h X * Purpose: Stuff I standardly use. X * Functions: X * Created: 25 Nov 1988 X * Last Modified: 19 Oct 1990 X * Comments: X * History: X * 19 Oct 90/JVE Added ifdef sun. X */ X X/* X * NULL pointer to some type. X */ X X# define NULLP( typ ) ( (typ *) 0 ) X X# undef ERROR X# define ERROR ( -1 ) X# undef OK X# define OK 0 X X# undef TRUE X# define TRUE 1 X# undef FALSE X# define FALSE 0 X X# define MAXLINE 255 X X# ifdef sun X X/* X * Delete file. X */ X X# define remove( x ) unlink( (x) ) X X# endif END_OF_FILE if test 535 -ne `wc -c <'standard.h'`; then echo shar: \"'standard.h'\" unpacked with wrong size! fi chmod +x 'standard.h' # end of 'standard.h' fi if test -f 'trim.sksh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'trim.sksh'\" else echo shar: Extracting \"'trim.sksh'\" \(199 characters\) sed "s/^X//" >'trim.sksh' <<'END_OF_FILE' X# Delete news articles over one day old. Xlc:touch .news* arn.config trim.sksh Xlc:touch save/* Xfind uunews: -name "KILL*" -exec lc:touch "{}" ";" Xfind uunews: -mtime +1 -type f -exec delete "{}" ";" X END_OF_FILE if test 199 -ne `wc -c <'trim.sksh'`; then echo shar: \"'trim.sksh'\" unpacked with wrong size! fi chmod +x 'trim.sksh' # end of 'trim.sksh' fi if test -f 'variables.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'variables.h'\" else echo shar: Extracting \"'variables.h'\" \(635 characters\) sed "s/^X//" >'variables.h' <<'END_OF_FILE' X/* X * File Name: variables.h X * Project: BARN - Bah's Amiga ReadNews. X * Purpose: Define names of configuration variables. X * Author: Jeff Van Epps X * Created: 20 Oct 90 X * Last Modified: 25 Nov 90 X * Comments: X * History: X * 20 Oct 90/JVE Created. X * 25 Nov 90/JVE Added noscroll. X */ X X# define VAR_USER "user" X# define VAR_NODE "node" X# define VAR_DOMAIN "domain" X# define VAR_EDITOR "editor" X# define VAR_NAME "name" X# define VAR_NEWSRC "newsrc" X# define VAR_KILL "kill" X# define VAR_SIGN "signature" X# define VAR_BBS "bbs" X# define VAR_LINES "lines" X# define VAR_COLS "columns" X# define VAR_NOSCROLL "noscroll" END_OF_FILE if test 635 -ne `wc -c <'variables.h'`; then echo shar: \"'variables.h'\" unpacked with wrong size! fi chmod +x 'variables.h' # end of 'variables.h' 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 -- Mail submissions (sources or binaries) to <amiga@uunet.uu.net>. Mail comments to the moderator at <amiga-request@uunet.uu.net>. Post requests for sources, and general discussion to comp.sys.amiga.misc.