v23i062: Complete reposting of TRN at patchlevel 1, Part03/14
Rich Salz
rsalz at bbn.com
Fri Jan 4 04:54:03 AEST 1991
Submitted-by: Wayne Davison <0004475895 at mcimail.com>
Posting-number: Volume 23, Issue 62
Archive-name: trn/part03
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents: makekit ng.c rcstuff.c
# Wrapped by rsalz at litchi.bbn.com on Thu Dec 27 11:34:00 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 3 (of 14)."'
if test -f 'makekit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'makekit'\"
else
echo shar: Extracting \"'makekit'\" \(745 characters\)
sed "s/^X//" >'makekit' <<'END_OF_FILE'
X#!/bin/sh
X# $Header: makekit,v 4.3 85/05/01 11:42:38 lwall Exp $
X#
X# $Log: makekit,v $
X# Revision 4.3 85/05/01 11:42:38 lwall
X# Baseline for release with 4.3bsd.
X#
X
Xnumkits=$#
Xfor kitlist in $*; do
X kit=`basename $kitlist .list`
X kitnum=`expr "$kit" : 'kit\([0-9][0-9]*\)'`
X echo "*** Making $kit ***"
X kitleader "$kit" "$kitnum" "$numkits"
X for file in `/bin/cat $kitlist`; do
X echo $file
X echo "echo Extracting $file" >> $kit
X if egrep '^\.$' $file; then
X echo "sed >$file <<'!STUFFY!FUNK!' -e 's/X//'" >> $kit
X sed <$file >>$kit -e 's/^/X/'
X else
X echo "cat >$file <<'!STUFFY!FUNK!'" >> $kit
X /bin/cat $file >> $kit
X fi
X echo "!STUFFY!FUNK!" >> $kit
X done
X kittrailer "$kit" "$kitnum" "$numkits"
Xdone
END_OF_FILE
if test 745 -ne `wc -c <'makekit'`; then
echo shar: \"'makekit'\" unpacked with wrong size!
fi
chmod +x 'makekit'
# end of 'makekit'
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'\" \(34937 characters\)
sed "s/^X//" >'ng.c' <<'END_OF_FILE'
X/* $Header: ng.c,v 4.3.3.2 90/08/20 16:03:45 davison Trn $
X *
X * $Log: ng.c,v $
X * Revision 4.3.3.2 90/08/20 16:03:45 davison
X * Fixed bug in backpage code.
X *
X * Revision 4.3.3.1 90/07/21 20:27:17 davison
X * Initial Trn Release
X *
X * Revision 4.3.2.7 90/04/21 14:44:23 sob
X * Revised previous patch insure that it does not decrement below zero.
X *
X * Revision 4.3.2.6 90/03/22 23:04:49 sob
X * Fixes provided by Wayne Davison <drivax!davison>
X *
X * Revision 4.3.2.5 89/12/09 01:18:42 sob
X * Fixed a bad call to nntpopen().
X *
X * Revision 4.3.2.4 89/11/28 01:51:20 sob
X * Removed redundant #include directive.
X *
X * Revision 4.3.2.3 89/11/27 01:31:03 sob
X * Altered NNTP code per ideas suggested by Bela Lubkin
X * <filbo at gorn.santa-cruz.ca.us>
X *
X * Revision 4.3.2.2 89/11/26 22:53:35 sob
X * Add new patches to make RRN be faster.
X *
X * Revision 4.3.2.1 89/11/06 00:54:27 sob
X * Added RRN support from NNTP 1.5
X *
X * Revision 4.3.1.6 85/09/10 11:03:42 lwall
X * Improved %m in in_char().
X *
X * Revision 4.3.1.5 85/09/05 12:34:37 lwall
X * Catchup command could make unread article count too big.
X *
X * Revision 4.3.1.4 85/07/23 18:19:46 lwall
X * Added MAILCALL environment variable.
X *
X * Revision 4.3.1.3 85/05/16 16:48:09 lwall
X * Fixed unsubsubscribe.
X *
X * Revision 4.3.1.2 85/05/13 09:29:28 lwall
X * Added CUSTOMLINES option.
X *
X * Revision 4.3.1.1 85/05/10 11:36:00 lwall
X * Branch for patches.
X *
X * Revision 4.3 85/05/01 11:43:43 lwall
X * Baseline for release with 4.3bsd.
X *
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "rn.h"
X#include "term.h"
X#include "final.h"
X#include "util.h"
X#include "artsrch.h"
X#include "cheat.h"
X#include "help.h"
X#include "kfile.h"
X#include "rcstuff.h"
X#include "head.h"
X#include "bits.h"
X#include "art.h"
X#include "artio.h"
X#include "ngstuff.h"
X#include "intrp.h"
X#include "respond.h"
X#include "ngdata.h"
X#include "backpage.h"
X#include "rcln.h"
X#include "last.h"
X#include "search.h"
X#ifdef SERVER
X#include "server.h"
X#endif
X#ifdef USETHREADS
X#include "rthreads.h"
X#endif
X#include "uudecode.h"
X#include "INTERN.h"
X#include "ng.h"
X#include "artstate.h" /* somebody has to do it */
X
X/* art_switch() return values */
X
X#define AS_NORM 0
X#define AS_INP 1
X#define AS_ASK 2
X#define AS_CLEAN 3
X
XART_NUM recent_art = -1; /* previous article # for '-' command */
XART_NUM curr_art = -1; /* current article # */
Xint exit_code = NG_NORM;
X
Xvoid
Xng_init()
X{
X
X#ifdef KILLFILES
X open_kfile(KF_GLOBAL);
X#endif
X#ifdef CUSTOMLINES
X init_compex(&hide_compex);
X init_compex(&page_compex);
X#endif
X}
X
X/* do newsgroup on line ng with name ngname */
X
X/* assumes that we are chdir'ed to SPOOL, and assures that that is
X * still true upon return, but chdirs to SPOOL/ngname in between
X *
X * If you can understand this routine, you understand most of the program.
X * The basic structure is:
X * for each desired article
X * for each desired page
X * for each line on page
X * if we need another line from file
X * get it
X * if it's a header line
X * do special things
X * for each column on page
X * put out a character
X * end loop
X * end loop
X * end loop
X * end loop
X *
X * (Actually, the pager is in another routine.)
X *
X * The chief problem is deciding what is meant by "desired". Most of
X * the messiness of this routine is due to the fact that people want
X * to do unstructured things all the time. I have used a few judicious
X * goto's where I thought it improved readability. The rest of the messiness
X * arises from trying to be both space and time efficient. Have fun.
X */
X
Xint
Xdo_newsgroup(start_command)
Xchar *start_command; /* command to fake up first */
X{
X#ifdef SERVER
X char ser_line[256];
X char artname[32];
X static long our_pid;
X#endif /* SERVER */
X char oldmode = mode;
X register long i; /* scratch */
X int skipstate; /* how many unavailable articles */
X /* have we skipped already? */
X
X char *whatnext = "%sWhat next? [%s]";
X
X#ifdef SERVER
X if (our_pid == 0) /* Agreed, this is gross */
X our_pid = getpid();
X#endif /* SERVER */
X
X#ifdef ARTSEARCH
X srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0);
X /* did they say -S? */
X#endif
X
X mode = 'a';
X#ifdef USETHREADS
X recent_p_art = curr_p_art = Nullart;
X#endif
X recent_art = curr_art = -1;
X exit_code = NG_NORM;
X
X#ifdef SERVER
X sprintf(ser_line, "GROUP %s", ngname);
X put_server(ser_line);
X if (get_server(ser_line, sizeof(ser_line)) < 0) {
X fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X finalize(1);
X }
X if (*ser_line != CHAR_OK) {
X if (atoi(ser_line) != ERR_NOGROUP)
X fprintf(stderr, "rrn: server response to GROUP %s:\n%s\n",
X ngname, ser_line);
X return (-1);
X }
X#else /* not SERVER */
X if (eaccess(ngdir,5)) { /* directory read protected? */
X if (eaccess(ngdir,0)) {
X#ifdef VERBOSE
X IF(verbose)
X printf("\nNewsgroup %s does not have a spool directory!\n",
X ngname) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\nNo spool for %s!\n",ngname) FLUSH;
X#endif
X#ifdef CATCHUP
X catch_up(ng);
X#endif
X toread[ng] = TR_NONE;
X }
X else {
X#ifdef VERBOSE
X IF(verbose)
X printf("\nNewsgroup %s is not currently accessible.\n",
X ngname) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\n%s not readable.\n",ngname) FLUSH;
X#endif
X toread[ng] = TR_NONE; /* make this newsgroup invisible */
X /* (temporarily) */
X }
X mode = oldmode;
X return -1;
X }
X
X /* chdir to newsgroup subdirectory */
X
X if (chdir(ngdir)) {
X printf(nocd,ngdir) FLUSH;
X mode = oldmode;
X return -1;
X }
X#endif /* SERVER */
X
X#ifdef CACHESUBJ
X subj_list = Null(char **); /* no subject list till needed */
X#endif
X
X /* initialize control bitmap */
X
X if (initctl()) {
X mode = oldmode;
X return -1;
X }
X
X /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
X
X /* grab threaded data */
X
X#ifdef USETHREADS
X if (ThreadedGroup && (ThreadedGroup = use_data(thread_name(ngname)))) {
X /* check if thread file is newer than the active2 entry (this is
X ** possible when mthreads is still running.) */
X if (total.last > lastart) {
X grow_ctl(total.last); /* sets lastart */
X }
X else if (total.last < lastart) {
X /* If the active2 entry is newer than the data file, something
X ** bad is going on. Forget using the thread data. */
X unuse_data(0);
X ThreadedGroup = FALSE;
X }
X }
X#endif
X
X in_ng = TRUE; /* tell the world we are here */
X forcelast = TRUE; /* if 0 unread, do not bomb out */
X
X /* remember what newsgroup we were in for sake of posterity */
X
X writelast();
X
X /* see if there are any special searches to do */
X
X#ifdef KILLFILES
X open_kfile(KF_LOCAL);
X#ifdef VERBOSE
X IF(verbose)
X kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE);
X ELSE
X#endif
X#ifdef TERSE
X kill_unwanted(firstart,"Killing...\n\n",TRUE);
X#endif
X#endif
X#ifdef USETHREADS
X first_art();
X#else
X art=firstart;
X#endif
X
X /* do they want a special top line? */
X
X firstline = getval("FIRSTLINE",Nullch);
X
X /* custom line suppression, custom page ending */
X
X#ifdef CUSTOMLINES
X if (hideline = getval("HIDELINE",Nullch))
X compile(&hide_compex,hideline,TRUE,TRUE);
X if (pagestop = getval("PAGESTOP",Nullch))
X compile(&page_compex,pagestop,TRUE,TRUE);
X#endif
X
X /* now read each unread article */
X
X rc_changed = doing_ng = TRUE; /* enter the twilight zone */
X skipstate = 0; /* we have not skipped anything (yet) */
X checkcount = 0; /* do not checkpoint for a while */
X do_fseek = FALSE; /* start 1st article at top */
X if (art > lastart)
X#ifdef USETHREADS
X first_art();
X#else
X art=firstart; /* init the for loop below */
X#endif
X for (; art<=lastart+1; ) { /* for each article */
X
X /* do we need to "grow" the newsgroup? */
X
X#ifdef USETHREADS
X if (ThreadedGroup) {
X if ((art > lastart || forcegrow) && getngsize(ng) > total.last) {
X unuse_data(1); /* free data with selections saved */
X if ((ThreadedGroup = use_data(thread_name(ngname))) != 0) {
X grow_ctl(total.last); /* sets lastart */
X find_article(art);
X curr_p_art = p_art;
X }
X forcegrow = FALSE;
X }
X }
X else
X#endif
X if (art > lastart || forcegrow)
X grow_ctl(getngsize(ng));
X check_first(art); /* make sure firstart is still 1st */
X if (start_command) { /* fake up an initial command? */
X prompt = whatnext;
X strcpy(buf,start_command);
X free(start_command);
X start_command = Nullch;
X#ifdef USETHREADS
X p_art = Nullart;
X#endif
X art = lastart+1;
X goto article_level;
X }
X if (art>lastart) { /* are we off the end still? */
X ART_NUM ucount = 0; /* count of unread articles left */
X
X for (i=firstart; i<=lastart; i++)
X if (!(ctl_read(i)))
X ucount++; /* count the unread articles */
X#ifdef DEBUGGING
X /*NOSTRICT*/
X if (debug && ((ART_NUM)toread[ng]) != ucount)
X printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount)
X FLUSH;
X#endif
X /*NOSTRICT*/
X toread[ng] = (ART_UNREAD)ucount; /* this is perhaps pointless */
X art = lastart + 1; /* keep bitmap references sane */
X if (art != curr_art) {
X#ifdef USETHREADS
X recent_p_art = curr_p_art;
X find_article(art);
X curr_p_art = p_art;
X#endif
X recent_art = curr_art;
X /* remember last article # (for '-') */
X curr_art = art; /* remember this article # */
X }
X if (erase_screen)
X clear(); /* clear the screen */
X else
X fputs("\n\n",stdout) FLUSH;
X#ifdef VERBOSE
X IF(verbose)
X printf("End of newsgroup %s.",ngname);
X /* print pseudo-article */
X ELSE
X#endif
X#ifdef TERSE
X printf("End of %s",ngname);
X#endif
X if (ucount) {
X#ifdef USETHREADS
X if (selected_root_cnt)
X printf(" (%ld + %ld articles still unread)",
X (long)selected_count,(long)ucount-selected_count);
X else
X#endif
X printf(" (%ld article%s still unread)",
X (long)ucount,ucount==1?nullstr:"s");
X }
X else {
X if (!forcelast)
X goto cleanup; /* actually exit newsgroup */
X }
X prompt = whatnext;
X#ifdef ARTSEARCH
X srchahead = 0; /* no more subject search mode */
X#endif
X fputs("\n\n",stdout) FLUSH;
X skipstate = 0; /* back to none skipped */
X }
X else if (!reread && was_read(art)) {
X /* has this article been read? */
X#ifdef USETHREADS
X follow_thread('n');
X#else
X art++; /* then skip it */
X#endif
X continue;
X }
X else if
X (!reread && !was_read(art)
X#ifdef SERVER
X && nntpopen(art,GET_HEADER) == Nullfp) {
X#else
X && artopen(art) == Nullfp) { /* never read it, & cannot find it? */
X if (errno != ENOENT) { /* has it not been deleted? */
X#ifdef VERBOSE
X IF(verbose)
X printf("\n(Article %ld exists but is unreadable.)\n",
X (long)art) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
X#endif
X skipstate = 0;
X sleep(2);
X }
X#endif
X switch(skipstate++) {
X case 0:
X clear();
X#ifdef VERBOSE
X IF(verbose)
X fputs("Skipping unavailable article",stdout);
X ELSE
X#endif
X#ifdef TERSE
X fputs("Skipping",stdout);
X#endif
X for (i = just_a_sec/3; i; --i)
X putchar(PC);
X fflush(stdout);
X sleep(1);
X break;
X case 1:
X fputs("..",stdout);
X fflush(stdout);
X break;
X default:
X putchar('.');
X fflush(stdout);
X#ifndef SERVER
X#define READDIR
X#ifdef READDIR
X { /* fast skip patch */
X ART_NUM newart;
X
X if (! (newart=getngmin(".",art)))
X newart = lastart+1;
X for (i=art; i<newart; i++)
X oneless(i);
X art = newart - 1;
X }
X#endif
X#else
X {
X char ser_line[256];
X ART_NUM newart;
X
X put_server("NEXT");
X if (get_server(ser_line, sizeof (ser_line)) < 0) {
X fprintf(stderr,
X "rrn: unexpected close of server socket.\n");
X finalize(1);
X }
X if (ser_line[0] != CHAR_OK)
X newart = lastart + 1;
X else
X newart = atoi(ser_line+4);
X for (i=art; i<newart; i++)
X oneless(i);
X art = newart - 1;
X }
X#endif /* SERVER */
X break;
X }
X oneless(art); /* mark deleted as read */
X#ifdef USETHREADS
X count_roots(FALSE); /* Keep selected_count accurate */
X find_article(art);
X follow_thread('n');
X#else
X art++; /* try next article */
X#endif
X continue;
X }
X else { /* we have a real live article */
X skipstate = 0; /* back to none skipped */
X if (art != curr_art) {
X#ifdef USETHREADS
X recent_p_art = curr_p_art;
X find_article(art);
X curr_p_art = p_art;
X#endif
X recent_art = curr_art;
X /* remember last article # (for '-') */
X curr_art = art; /* remember this article # */
X }
X if (!do_fseek) { /* starting at top of article? */
X artline = 0; /* start at the beginning */
X topline = -1; /* and remember top line of screen */
X /* (line # within article file) */
X }
X clear(); /* clear screen */
X if (!artopen(art)) { /* make sure article is found & open */
X#ifdef USETHREADS
X char tmpbuf[256];
X /* see if we have tree data for this article anyway */
X init_tree();
X sprintf(tmpbuf,"%s #%ld is not available.",ngname,(long)art);
X tree_puts(tmpbuf,0,0);
X vwtary((ART_LINE)0,(ART_POS)0);
X finish_tree(1);
X prompt = whatnext;
X#else
X printf("Article %ld of %s is not available.\n\n",
X (long)art,ngname) FLUSH;
X prompt = whatnext;
X#endif
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X }
X else { /* found it, so print it */
X switch (do_article()) {
X case DA_CLEAN: /* quit newsgroup */
X goto cleanup;
X case DA_TOEND: /* do not mark as read */
X goto reask_article;
X case DA_RAISE: /* reparse command at end of art */
X goto article_level;
X case DA_NORM: /* normal end of article */
X break;
X }
X }
X if (art >= absfirst) /* don't mark non-existant articles */
X mark_as_read(); /* mark current article as read */
X reread = FALSE;
X do_hiding = TRUE;
X#ifdef ROTATION
X rotate = FALSE;
X#endif
X }
X
X/* if these gotos bother you, think of this as a little state machine */
X
Xreask_article:
X#ifdef MAILCALL
X setmail();
X#endif
X setdfltcmd();
X#ifdef CLEAREOL
X if (erase_screen && can_home_clear)
X clear_rest();
X#endif /* CLEAREOL */
X unflush_output(); /* disable any ^O in effect */
X standout(); /* enter standout mode */
X printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
X un_standout(); /* leave standout mode */
X putchar(' ');
X fflush(stdout);
Xreinp_article:
X eat_typeahead();
X#ifdef PENDING
X look_ahead(); /* see what we can do in advance */
X if (!input_pending())
X collect_subjects(); /* loads subject cache until */
X /* input is pending */
X#endif
X getcmd(buf);
X if (errno || *buf == '\f') {
X if (LINES < 100 && !int_count)
X *buf = '\f'; /* on CONT fake up refresh */
X else {
X putchar('\n') FLUSH; /* but only on a crt */
X goto reask_article;
X }
X }
Xarticle_level:
X
X /* parse and process article level command */
X
X switch (art_switch()) {
X case AS_INP: /* multichar command rubbed out */
X goto reinp_article;
X case AS_ASK: /* reprompt "End of article..." */
X goto reask_article;
X case AS_CLEAN: /* exit newsgroup */
X goto cleanup;
X case AS_NORM: /* display article art */
X break;
X }
X } /* end of article selection loop */
X
X/* shut down newsgroup */
X
Xcleanup:
X uud_end();
X#ifdef KILLFILES
X kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
X /* do cleanup from KILL file, if any */
X#endif
X#ifdef USETHREADS
X if (ThreadedGroup)
X unuse_data(0); /* free article thread data */
X#endif
X in_ng = FALSE; /* leave newsgroup state */
X if (artfp != Nullfp) { /* article still open? */
X fclose(artfp); /* close it */
X artfp = Nullfp; /* and tell the world */
X#ifdef SERVER
X sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
X UNLINK(artname);
X#endif /* SERVER */
X openart = 0;
X }
X putchar('\n') FLUSH;
X yankback(); /* do a Y command */
X restore_ng(); /* reconstitute .newsrc line */
X doing_ng = FALSE; /* tell sig_catcher to cool it */
X free(ctlarea); /* return the control area */
X#ifdef CACHESUBJ
X if (subj_list) {
X for (i=OFFSET(lastart); i>=0; --i)
X if (subj_list[i])
X free(subj_list[i]);
X#ifndef lint
X free((char*)subj_list);
X#endif /* lint */
X }
X#endif
X write_rc(); /* and update .newsrc */
X rc_changed = FALSE; /* tell sig_catcher it is ok */
X if (chdir(spool)) {
X printf(nocd,spool) FLUSH;
X sig_catcher(0);
X }
X#ifdef KILLFILES
X if (localkfp) {
X fclose(localkfp);
X localkfp = Nullfp;
X }
X#endif
X mode = oldmode;
X return exit_code;
X} /* Whew! */
X
X/* decide what to do at the end of an article */
X
Xint
Xart_switch()
X{
X register ART_NUM i;
X
X setdef(buf,dfltcmd);
X#ifdef VERIFY
X printcmd();
X#endif
X
X switch (*buf) {
X#ifdef USETHREADS
X case '<': /* goto previous thread */
X if (!ThreadedGroup) {
X goto group_unthreaded;
X }
X prev_root();
X return AS_NORM;
X case '>': /* goto next thread */
X if (!ThreadedGroup) {
X goto group_unthreaded;
X }
X next_root();
X return AS_NORM;
X case 'U': { /* unread some articles */
X char *u_prompt, *u_help_thread;
X
X if (!ThreadedGroup) {
X dfltcmd = "a";
X u_help_thread = nullstr;
X#ifdef VERBOSE
X IF(verbose)
X u_prompt = "\nSet unread: all articles? [an] ";
X ELSE
X#endif
X#ifdef TERSE
X u_prompt = "\nUnread? [an] ";
X#endif
X }
X else if (!p_art || art > lastart) {
X dfltcmd = "+";
X u_help_thread = nullstr;
X#ifdef VERBOSE
X IF(verbose)
X u_prompt = "\nSet unread: +select or all? [+an] ";
X ELSE
X#endif
X#ifdef TERSE
X u_prompt = "\nUnread? [+an] ";
X#endif
X }
X else {
X dfltcmd = "t";
X#ifdef VERBOSE
X IF(verbose) {
X u_prompt = "\n\
XSet unread: thread, subthread, +select, or all? [ts+an] ";
X u_help_thread = "\
XType t or SP to mark this thread's articles as unread.\n\
XType s to mark the current article and its descendants as unread.\n";
X }
X ELSE
X#endif
X#ifdef TERSE
X {
X u_prompt = "\nUnread? [ts+an] ";
X u_help_thread = "\
Xt or SP to mark thread unread.\n\
Xs to mark subthread unread.\n";
X }
X#endif
X }
X reask_unread:
X in_char(u_prompt,'u');
X putchar('\n') FLUSH;
X setdef(buf,dfltcmd);
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X fputs(u_help_thread,stdout);
X#ifdef VERBOSE
X IF(verbose)
X {
X if (ThreadedGroup)
X fputs("\
XType + to enter select thread mode using all the unread articles.\n\
X(The selected threads will be marked as unread and displayed as usual.)\n\
X",stdout) FLUSH;
X fputs("\
XType a to mark all articles in this group as unread.\n\
XType n to change nothing.\n\
X",stdout) FLUSH;
X }
X ELSE
X#endif
X#ifdef TERSE
X {
X if (ThreadedGroup)
X fputs("\
X+ to select threads from the unread.\n\
X",stdout) FLUSH;
X fputs("\
Xa to mark all articles unread.\n\
Xn to change nothing.\n\
X",stdout) FLUSH;
X }
X#endif
X goto reask_unread;
X }
X else if (*buf == 'n' || *buf == 'q') {
X return AS_ASK;
X }
X else if (*buf == 't' && *dfltcmd == 't')
X follow_thread('u');
X else if (*buf == 's' && *dfltcmd == 't') {
X follow_thread('U');
X }
X else if (*buf == 'a') {
X check_first(absfirst);
X for (i = absfirst; i <= lastart; i++) {
X onemore(i); /* mark as unread */
X }
X scan_all_roots = FALSE;
X count_roots(FALSE);
X if (art > lastart) {
X first_art();
X }
X }
X else if (ThreadedGroup && *buf == '+') {
X *buf = 'U';
X goto select_threads;
X }
X else {
X fputs(hforhelp,stdout) FLUSH;
X settle_down();
X goto reask_unread;
X }
X return AS_NORM;
X }
X case '[': /* goto parent article */
X case '{': /* goto thread's root article */
X if (p_art) {
X if (!p_art->parent) {
X if (p_art == p_articles + p_roots[p_art->root].articles) {
X register char *cp = (*buf=='['?"parent":"root");
X#ifdef VERBOSE
X IF(verbose)
X fprintf(stdout,"\n\
XThere is no %s article prior to this one.\n",cp) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fprintf(stdout,"\nNo prior %s.\n",cp) FLUSH;
X#endif
X return AS_ASK;
X }
X *buf = '{';
X p_art--;
X }
X else
X p_art += p_art->parent;
X
X if (*buf == '{')
X while (p_art->parent)
X p_art += p_art->parent;
X
X art = p_art->num;
X reread = TRUE;
X return AS_NORM;
X }
Xnot_threaded:
X if (ThreadedGroup) {
X#ifdef VERBOSE
X IF(verbose)
X fputs("\nThis article is not threaded.\n",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("\nUnthreaded article.\n",stdout) FLUSH;
X#endif
X return AS_ASK;
X }
Xgroup_unthreaded:
X#ifdef VERBOSE
X IF(verbose)
X fputs("\nThis group is not threaded.\n",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("\nUnthreaded group.\n",stdout) FLUSH;
X#endif
X return AS_ASK;
X case ']': /* goto child article */
X case '}': /* goto thread's leaf article */
X if (p_art) {
X if (!(p_art++)->child_cnt) {
X PACKED_ARTICLE *root_limit = upper_limit(p_art-1,FALSE);
X
X if (p_art == root_limit) {
X#ifdef VERBOSE
X IF(verbose)
X fputs("\n\
XThis is the last leaf in this tree.\n",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("\nLast leaf.\n",stdout) FLUSH;
X#endif
X p_art--;
X return AS_ASK;
X }
X if (*buf == ']')
X *buf = '}';
X else {
X while (++p_art != root_limit && p_art->parent)
X ;
X p_art--;
X *buf = ' ';
X }
X }
X if( *buf == '}' )
X while (p_art->child_cnt)
X p_art++;
X
X art = p_art->num;
X reread = TRUE;
X return AS_NORM;
X }
X goto not_threaded;
X case 'T':
X if (p_art) {
X sprintf(buf,"T%ld\t# %s",(long)p_roots[p_art->root].root_num,
X subject_ptrs[p_art->subject]);
X fputs(buf,stdout);
X kf_append(buf);
X *buf = 'J';
X goto follow_threads;
X }
X goto not_threaded;
X case 'K':
X if (p_art) {
X /* first, write kill-subject command */
X (void)art_search(buf, (sizeof buf), TRUE);
X art = curr_art;
X p_art = curr_p_art;
X *buf = 'k'; /* then take care of any prior subjs */
X goto follow_threads;
X }
X goto normal_search;
X case ',': /* kill this node and all descendants */
X mark_as_read();
X *buf = 'K';
X case 'k': /* kill current subject # (e.g. [1]) */
X case 'J': /* Junk all nodes in this thread */
X if (!ThreadedGroup) {
X *buf = 'k';
X goto normal_search;
X }
Xfollow_threads:
X follow_thread(*buf);
X if (!reread && !toread[ng])
X return AS_CLEAN;
X if (!reread && selected_root_cnt && !selected_count)
X goto select_threads;
X return AS_NORM;
X case 't':
X carriage_return();
X#ifndef CLEAREOL
X erase_eol(); /* erase the prompt */
X#else
X if (erase_screen && can_home_clear)
X clear_rest();
X else
X erase_eol(); /* erase the prompt */
X#endif /* CLEAREOL */
X fflush(stdout);
X page_line = 1;
X p_art = curr_p_art;
X entire_tree();
X return AS_ASK;
X case ':': /* execute command on selected articles */
X if (!ThreadedGroup) {
X goto group_unthreaded;
X }
X page_line = 1;
X if (!use_selected())
X return AS_INP;
X putchar('\n');
X art = curr_art;
X p_art = curr_p_art;
X return AS_ASK;
X#endif /* USETHREADS */
X case 'p': /* find previous unread article */
X#ifdef USETHREADS
X if (ThreadedGroup) {
X goto backtrack_threads;
X }
X#endif
X do {
X if (art <= firstart)
X break;
X art--;
X#ifdef SERVER
X } while (was_read(art) || nntpopen(art,GET_HEADER) == Nullfp);
X#else
X } while (was_read(art) || artopen(art) == Nullfp);
X#endif
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X case 'P': /* goto previous article */
X#ifdef USETHREADS
X if (ThreadedGroup) {
Xbacktrack_threads:
X backtrack_thread( *buf );
X art++; /* prepare for art-- below */
X }
X#endif
X if (art > absfirst)
X art--;
X else {
X#ifdef VERBOSE
X IF(verbose)
X fprintf(stdout,"\n\
XThere are no%s articles prior to this one.\n\
X",*buf=='P'?nullstr:" unread") FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fprintf(stdout,"\n\
XNo previous%s articles\n\
X",*buf=='P'?nullstr:" unread") FLUSH;
X#endif
X art = curr_art;
X#ifdef USETHREADS
X p_art = curr_p_art;
X#endif
X return AS_ASK;
X }
X reread = TRUE;
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X case '-':
X if (recent_art >= 0) {
X#ifdef USETHREADS
X p_art = recent_p_art;
X#endif
X art = recent_art;
X reread = TRUE;
X#ifdef ARTSEARCH
X srchahead = -(srchahead != 0);
X#endif
X return AS_NORM;
X }
X else {
X exit_code = NG_MINUS;
X return AS_CLEAN;
X }
X case 'n': /* find next unread article? */
X#ifdef USETHREADS
X if (ThreadedGroup) {
X goto follow_threads;
X }
X#endif
X if (art > lastart) {
X if (!toread[ng])
X return AS_CLEAN;
X art = firstart;
X }
X#ifdef ARTSEARCH
X else if (scanon && srchahead) {
X *buf = Ctl('n');
X goto normal_search;
X }
X#endif
X else
X art++;
X
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X case 'N': /* goto next article */
X#ifdef USETHREADS
X if (ThreadedGroup) {
X goto follow_threads;
X }
X#endif
X if (art > lastart)
X art = absfirst;
X else
X art++;
X if (art <= lastart)
X reread = TRUE;
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X case '$':
X art = lastart+1;
X forcelast = TRUE;
X#ifdef USETHREADS
X p_art = Nullart;
X#endif
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X case '1': case '2': case '3': /* goto specified article */
X case '4': case '5': case '6': /* or do something with a range */
X case '7': case '8': case '9': case '.':
X forcelast = TRUE;
X switch (numnum()) {
X case NN_INP:
X return AS_INP;
X case NN_ASK:
X return AS_ASK;
X case NN_REREAD:
X reread = TRUE;
X#ifdef ARTSEARCH
X if (srchahead)
X srchahead = -1;
X#endif
X break;
X case NN_NORM:
X if (was_read(art)) {
X#ifdef USETHREADS
X first_art();
X#else
X art = firstart;
X#endif
X pad(just_a_sec/3);
X }
X else {
X putchar('\n');
X return AS_ASK;
X }
X break;
X }
X return AS_NORM;
X case Ctl('k'):
X edit_kfile();
X return AS_ASK;
X#ifndef USETHREADS
X case 'K':
X case 'k':
X#endif
X case Ctl('n'): /* search for next article with same subject */
X#ifdef USETHREADS
X if (ThreadedGroup) {
X goto follow_threads;
X }
X#endif
X case Ctl('p'): /* search for previous article with same subject */
X#ifdef USETHREADS
X if (ThreadedGroup) {
X goto backtrack_threads;
X }
X#endif
X case '/': case '?':
Xnormal_search:
X#ifdef ARTSEARCH
X { /* search for article by pattern */
X char cmd = *buf;
X
X reread = TRUE; /* assume this */
X page_line = 1;
X switch (art_search(buf, (sizeof buf), TRUE)) {
X case SRCH_ERROR:
X art = curr_art;
X return AS_ASK;
X case SRCH_ABORT:
X art = curr_art;
X return AS_INP;
X case SRCH_INTR:
X#ifdef VERBOSE
X IF(verbose)
X printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\n(Intr at %ld)\n",(long)art) FLUSH;
X#endif
X art = curr_art;
X /* restore to current article */
X return AS_ASK;
X case SRCH_DONE:
X fputs("done\n",stdout) FLUSH;
X pad(just_a_sec/3); /* 1/3 second */
X if (!srchahead) {
X art = curr_art;
X return AS_ASK;
X }
X#ifdef USETHREADS
X first_art();
X#else
X art = firstart;
X#endif
X reread = FALSE;
X return AS_NORM;
X case SRCH_SUBJDONE:
X#ifdef UNDEF
X fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
X pad(just_a_sec/3); /* 1/3 second */
X#endif
X#ifdef USETHREADS
X first_art();
X#else
X art = firstart;
X#endif
X reread = FALSE;
X return AS_NORM;
X case SRCH_NOTFOUND:
X fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
X art = curr_art; /* restore to current article */
X return AS_ASK;
X case SRCH_FOUND:
X if (cmd == Ctl('n') || cmd == Ctl('p'))
X oldsubject = TRUE;
X break;
X }
X return AS_NORM;
X }
X#else
X buf[1] = '\0';
X notincl(buf);
X return AS_ASK;
X#endif
X case 'u': /* unsubscribe from this newsgroup? */
X rcchar[ng] = NEGCHAR;
X return AS_CLEAN;
X case 'M':
X#ifdef DELAYMARK
X if (art <= lastart) {
X delay_unmark(art);
X printf("\nArticle %ld will return.\n",(long)art) FLUSH;
X }
X#else
X notincl("M");
X#endif
X return AS_ASK;
X case 'm':
X if (art <= lastart) {
X unmark_as_read();
X printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
X }
X return AS_ASK;
X case 'c': /* catch up */
X reask_catchup:
X#ifdef VERBOSE
X IF(verbose)
X in_char("\nDo you really want to mark everything as read? [yn] ",
X 'C');
X ELSE
X#endif
X#ifdef TERSE
X in_char("\nReally? [ynh] ", 'C');
X#endif
X putchar('\n') FLUSH;
X setdef(buf,"y");
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X#ifdef VERBOSE
X IF(verbose)
X fputs("\
XType y or SP to mark all articles as read.\n\
XType n to leave articles marked as they are.\n\
XType u to mark everything read and unsubscribe.\n\
X",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("\
Xy or SP to mark all read.\n\
Xn to forget it.\n\
Xu to mark all and unsubscribe.\n\
X",stdout) FLUSH;
X#endif
X goto reask_catchup;
X }
X else if (*buf == 'n' || *buf == 'q') {
X return AS_ASK;
X }
X else if (*buf != 'y' && *buf != 'u') {
X fputs(hforhelp,stdout) FLUSH;
X settle_down();
X goto reask_catchup;
X }
X for (i = firstart; i <= lastart; i++) {
X oneless(i); /* mark as read */
X }
X#ifdef USETHREADS
X selected_root_cnt = selected_count = 0;
X#endif
X#ifdef DELAYMARK
X if (dmfp)
X yankback();
X#endif
X if (*buf == 'u') {
X rcchar[ng] = NEGCHAR;
X return AS_CLEAN;
X }
X#ifdef USETHREADS
X p_art = Nullart;
X selected_count = 0;
X#endif
X art = lastart+1;
X forcelast = FALSE;
X return AS_NORM;
X case 'Q':
X exit_code = NG_ASK;
X /* FALL THROUGH */
X case 'q': /* go back up to newsgroup level? */
X return AS_CLEAN;
X case 'j':
X putchar('\n') FLUSH;
X if (art <= lastart)
X mark_as_read();
X return AS_ASK;
X case 'h': { /* help? */
X int cmd;
X
X if ((cmd = help_art()) > 0)
X pushchar(cmd);
X return AS_ASK;
X }
X case '&':
X if (switcheroo()) /* get rest of command */
X return AS_INP; /* if rubbed out, try something else */
X return AS_ASK;
X case '#':
X#ifdef VERBOSE
X IF(verbose)
X printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\n%ld\n",(long)lastart) FLUSH;
X#endif
X return AS_ASK;
X#ifdef USETHREADS
X case '+': /* enter thread selection mode */
X if (ThreadedGroup) {
Xselect_threads:
X *buf = select_thread(*buf);
X if (*buf == 'q') {
X putchar( '\n' ) FLUSH;
X return AS_ASK;
X }
X if (*buf == 'Q') {
X exit_code = NG_ASK;
X return AS_CLEAN;
X }
X if (*buf == 'N' || !toread[ng])
X return AS_CLEAN;
X return AS_NORM;
X }
X /* FALLTHROUGH */
X#endif
X case '=': { /* list subjects */
X char tmpbuf[256];
X ART_NUM oldart = art;
X int cmd;
X char *subjline = getval("SUBJLINE",Nullch);
X#ifndef CACHESUBJ
X char *s;
X#endif
X
X page_init();
X#ifdef CACHESUBJ
X if (!subj_list)
X fetchsubj(art,TRUE,FALSE);
X#endif
X for (i=firstart; i<=lastart && !int_count; i++) {
X#ifdef CACHESUBJ
X if (!was_read(i) &&
X (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
X *subj_list[OFFSET(i)] ) {
X sprintf(tmpbuf,"%5ld ", i);
X if (subjline) {
X art = i;
X interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
X }
X else
X safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
X (sizeof tmpbuf) - 6);
X if (cmd = print_lines(tmpbuf,NOMARKING)) {
X if (cmd > 0)
X pushchar(cmd);
X break;
X }
X }
X#else
X if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
X sprintf(tmpbuf,"%5ld ", i);
X if (subjline) { /* probably fetches it again! */
X art = i;
X interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
X }
X else
X safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
X if (cmd = print_lines(tmpbuf,NOMARKING)) {
X if (cmd > 0)
X pushchar(cmd);
X break;
X }
X }
X#endif
X }
X int_count = 0;
X art = oldart;
X return AS_ASK;
X }
X case '^':
X#ifdef USETHREADS
X first_art();
X#else
X art = firstart;
X#endif
X#ifdef ARTSEARCH
X srchahead = 0;
X#endif
X return AS_NORM;
X#if defined(CACHESUBJ) && defined(DEBUGGING)
X case 'D':
X printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
X if (!subj_list)
X fetchsubj(art,TRUE,FALSE);
X if (subj_list != Null(char **)) {
X for (i=1; i<=lastart && !int_count; i++) {
X if (subj_list[OFFSET(i)])
X printf("%5ld %c %s\n",
X i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
X }
X }
X int_count = 0;
X return AS_ASK;
X#endif
X case 'v':
X if (art <= lastart) {
X reread = TRUE;
X do_hiding = FALSE;
X }
X return AS_NORM;
X#ifdef ROTATION
X case Ctl('x'):
X#endif
X case Ctl('r'):
X#ifdef ROTATION
X rotate = (*buf==Ctl('x'));
X#endif
X if (art <= lastart)
X reread = TRUE;
X return AS_NORM;
X#ifdef ROTATION
X case 'X':
X rotate = !rotate;
X /* FALL THROUGH */
X#else
X case Ctl('x'):
X case 'x':
X case 'X':
X notincl("x");
X return AS_ASK;
X#endif
X case 'l': case Ctl('l'): /* refresh screen */
X if (art <= lastart) {
X reread = TRUE;
X clear();
X do_fseek = TRUE;
X artline = topline;
X if (artline < 0)
X artline = 0;
X }
X return AS_NORM;
X case 'b': case Ctl('b'): /* back up a page */
X if (art <= lastart) {
X ART_LINE target;
X
X reread = TRUE;
X clear();
X do_fseek = TRUE;
X target = topline - (LINES - 2);
X artline = topline;
X if (artline >= 0) do {
X artline--;
X } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
X topline = artline;
X if (artline < 0)
X artline = 0;
X }
X return AS_NORM;
X case '!': /* shell escape */
X if (escapade())
X return AS_INP;
X return AS_ASK;
X case 'C': {
X cancel_article();
X return AS_ASK;
X }
X case 'R':
X case 'r': { /* reply? */
X reply();
X return AS_ASK;
X }
X case 'F':
X case 'f': { /* followup command */
X followup();
X forcegrow = TRUE; /* recalculate lastart */
X return AS_ASK;
X }
X case '|':
X case 'w': case 'W':
X case 's': case 'S': /* save command */
X case 'e': /* extract command */
X if (save_article() == SAVE_ABORT)
X return AS_INP;
X int_count = 0;
X return AS_ASK;
X case 'E':
X if (uu_out != Nullfp) {
X uud_end();
X }
X return AS_ASK;
X#ifdef DELAYMARK
X case 'Y': /* yank back M articles */
X yankback();
X#ifdef USETHREADS
X first_art();
X#else
X art = firstart; /* from the beginning */
X#endif
X return AS_NORM; /* pretend nothing happened */
X#endif
X#ifdef STRICTCR
X case '\n':
X fputs(badcr,stdout) FLUSH;
X return AS_ASK;
X#endif
X default:
X printf("\n%s",hforhelp) FLUSH;
X settle_down();
X return AS_ASK;
X }
X}
X
X#ifdef MAILCALL
X/* see if there is any mail */
X
Xvoid
Xsetmail()
X{
X if (! (mailcount++)) {
X char *mailfile = filexp(getval("MAILFILE",MAILFILE));
X
X if (stat(mailfile,&filestat) < 0 || !filestat.st_size
X || filestat.st_atime > filestat.st_mtime)
X mailcall = nullstr;
X else
X mailcall = getval("MAILCALL","(Mail) ");
X }
X mailcount %= 10; /* check every 10 articles */
X}
X#endif
X
Xvoid
Xsetdfltcmd()
X{
X#ifdef USETHREADS
X if (toread[ng] == unthreaded) {
X#else
X if (!toread[ng]) {
X#endif
X if (art > lastart)
X dfltcmd = "qnp";
X else
X dfltcmd = "npq";
X }
X else {
X#ifdef USETHREADS
X if (selected_root_cnt && !selected_count)
X dfltcmd = "+npq";
X else
X# ifdef ARTSEARCH
X if (!ThreadedGroup && srchahead)
X dfltcmd = "^Nnpq";
X else
X# endif
X#else
X# ifdef ARTSEARCH
X if (srchahead)
X dfltcmd = "^Nnpq";
X else
X# endif
X#endif
X dfltcmd = "npq";
X }
X}
END_OF_FILE
if test 34937 -ne `wc -c <'ng.c'`; then
echo shar: \"'ng.c'\" unpacked with wrong size!
fi
# end of 'ng.c'
fi
if test -f 'rcstuff.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rcstuff.c'\"
else
echo shar: Extracting \"'rcstuff.c'\" \(23291 characters\)
sed "s/^X//" >'rcstuff.c' <<'END_OF_FILE'
X/* $Header: rcstuff.c,v 4.3.3.2 90/08/20 16:47:44 davison Trn $
X *
X * $Log: rcstuff.c,v $
X * Revision 4.3.3.2 90/08/20 16:47:44 davison
X * Removed ngmax array.
X *
X * Revision 4.3.3.1 90/06/20 22:39:28 davison
X * Initial Trn Release
X *
X * Revision 4.3.2.5 90/05/04 00:44:07 sob
X * Fixes to add_newsgroup() from lar at usl.edu.
X *
X * Revision 4.3.2.4 90/04/23 00:25:45 sob
X * Changed atoi to atol.
X *
X * Revision 4.3.2.3 89/12/20 23:25:04 sob
X * Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
X *
X * Revision 4.3.2.2 89/11/26 18:22:26 sob
X * Added changes to addnewgroup() to cause rn to ask once and only once
X * to add a new group to .newsrc.
X * Fix provided by Fletcher Mattox <fletcher at cs.utexas.edu>
X *
X * Revision 4.3.2.1 89/11/06 00:58:29 sob
X * Added RRN support from NNTP 1.5
X *
X * Revision 4.3.1.5 86/07/24 14:09:10 lwall
X * Removed check for spool directory existence in get_ng.
X *
X * Revision 4.3.1.4 85/09/10 11:04:44 lwall
X * Improved %m in in_char().
X *
X * Revision 4.3.1.3 85/05/29 09:13:25 lwall
X * %d that should be %ld.
X *
X * Revision 4.3.1.2 85/05/17 11:40:08 lwall
X * Sped up "rn -c" by not mallocing unnecessarily.
X *
X * Revision 4.3.1.1 85/05/10 11:37:18 lwall
X * Branch for patches.
X *
X * Revision 4.3 85/05/01 11:45:56 lwall
X * Baseline for release with 4.3bsd.
X *
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "ngdata.h"
X#include "term.h"
X#include "final.h"
X#include "rn.h"
X#include "intrp.h"
X#include "only.h"
X#include "rcln.h"
X#ifdef SERVER
X#include "server.h"
X#endif
X#include "INTERN.h"
X#include "rcstuff.h"
X
Xchar *rcname INIT(Nullch); /* path name of .newsrc file */
Xchar *rctname INIT(Nullch); /* path name of temp .newsrc file */
Xchar *rcbname INIT(Nullch); /* path name of backup .newsrc file */
Xchar *softname INIT(Nullch); /* path name of .rnsoft file */
XFILE *rcfp INIT(Nullfp); /* .newsrc file pointer */
X
X#ifdef HASHNG
X short hashtbl[HASHSIZ];
X#endif
X
Xbool
Xrcstuff_init()
X{
X register NG_NUM newng;
X register char *s;
X register int i;
X register bool foundany = FALSE;
X char *some_buf;
X long length;
X#ifdef SERVER
X char *cp;
X#endif /* SERVER */
X
X#ifdef HASHNG
X for (i=0; i<HASHSIZ; i++)
X hashtbl[i] = -1;
X#endif
X
X /* make filenames */
X
X#ifdef SERVER
X
X if (cp = getenv("NEWSRC"))
X rcname = savestr(filexp(cp));
X else
X rcname = savestr(filexp(RCNAME));
X
X#else /* not SERVER */
X
X rcname = savestr(filexp(RCNAME));
X
X#endif /* SERVER */
X
X rctname = savestr(filexp(RCTNAME));
X rcbname = savestr(filexp(RCBNAME));
X softname = savestr(filexp(SOFTNAME));
X
X /* make sure the .newsrc file exists */
X
X newsrc_check();
X
X /* open .rnsoft file containing soft ptrs to active file */
X
X tmpfp = fopen(softname,"r");
X if (tmpfp == Nullfp)
X writesoft = TRUE;
X
X /* read in the .newsrc file */
X
X for (nextrcline = 0;
X (some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch;
X nextrcline++) {
X /* for each line in .newsrc */
X char tmpbuf[10];
X
X newng = nextrcline; /* get it into a register */
X length = len_last_line_got; /* side effect of get_a_line */
X if (length <= 1) { /* only a newline??? */
X nextrcline--; /* compensate for loop increment */
X continue;
X }
X if (newng >= MAXRCLINE) { /* check for overflow */
X fputs("Too many lines in .newsrc\n",stdout) FLUSH;
X finalize(1);
X }
X if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
X softptr[newng] = atol(tmpbuf);
X else
X softptr[newng] = 0;
X some_buf[--length] = '\0'; /* wipe out newline */
X if (checkflag) /* no extra mallocs for -c */
X rcline[newng] = some_buf;
X else if (some_buf == buf) {
X rcline[newng] = savestr(some_buf);
X /* make a semipermanent copy */
X }
X else {
X /*NOSTRICT*/
X#ifndef lint
X some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
X#endif /* lint */
X rcline[newng] = some_buf;
X }
X#ifdef NOTDEF
X if (strnEQ(some_buf,"to.",3)) { /* is this a non-newsgroup? */
X nextrcline--; /* destroy this line */
X continue;
X }
X#endif
X if (*some_buf == ' ' ||
X *some_buf == '\t' ||
X strnEQ(some_buf,"options",7)) { /* non-useful line? */
X toread[newng] = TR_JUNK;
X rcchar[newng] = ' ';
X rcnums[newng] = 0;
X continue;
X }
X for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ;
X if (!*s && !checkflag) {
X#ifndef lint
X rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
X#endif /* lint */
X s = rcline[newng] + length;
X *s = ':';
X *(s+1) = '\0';
X }
X rcchar[newng] = *s; /* salt away the : or ! */
X rcnums[newng] = (char)(s - rcline[newng]);
X rcnums[newng]++; /* remember where it was */
X *s = '\0'; /* null terminate newsgroup name */
X#ifdef HASHNG
X if (!checkflag)
X sethash(newng);
X#endif
X if (rcchar[newng] == NEGCHAR) {
X toread[newng] = TR_UNSUB;
X continue;
X }
X
X /* now find out how much there is to read */
X
X if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
X toread[newng] = TR_NONE; /* no need to calculate now */
X else
X set_toread(newng);
X#ifdef VERBOSE
X if (!checkflag && softmisses == 1) {
X softmisses++; /* lie a little */
X fputs("(Revising soft pointers--be patient.)\n",stdout) FLUSH;
X }
X#endif
X if (toread[newng] > TR_NONE) { /* anything unread? */
X if (!foundany) {
X starthere = newng;
X foundany = TRUE; /* remember that fact*/
X }
X if (suppress_cn) { /* if no listing desired */
X if (checkflag) { /* if that is all they wanted */
X finalize(1); /* then bomb out */
X }
X }
X else {
X#ifdef VERBOSE
X IF(verbose)
X printf("Unread news in %-40s %5ld article%s\n",
X rcline[newng],(long)toread[newng],
X toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("%s: %ld article%s\n",
X rcline[newng],(long)toread[newng],
X toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
X#endif
X if (int_count) {
X countdown = 1;
X int_count = 0;
X }
X if (countdown) {
X if (! --countdown) {
X fputs("etc.\n",stdout) FLUSH;
X if (checkflag)
X finalize(1);
X suppress_cn = TRUE;
X }
X }
X }
X }
X }
X fclose(rcfp); /* close .newsrc */
X if (tmpfp != Nullfp)
X fclose(tmpfp); /* close .rnsoft */
X if (checkflag) { /* were we just checking? */
X finalize(foundany); /* tell them what we found */
X }
X if (paranoid)
X cleanup_rc();
X
X#ifdef DEBUGGING
X if (debug & DEB_HASH) {
X page_init();
X for (i=0; i<HASHSIZ; i++) {
X sprintf(buf,"%d %d",i,hashtbl[i]);
X print_lines(buf,NOMARKING);
X }
X }
X#endif
X
X return foundany;
X}
X
X/* try to find or add an explicitly specified newsgroup */
X/* returns TRUE if found or added, FALSE if not. */
X/* assumes that we are chdir'ed to SPOOL */
X
X#ifdef SERVER
Xstatic int addnewbydefault = 0;
X#endif /* SERVER */
X
Xbool
Xget_ng(what,do_reloc)
Xchar *what;
Xbool do_reloc;
X{
X char *ntoforget;
X char promptbuf[128];
X#ifdef SERVER
X char ser_line[256];
X#endif /* SERVER */
X
X#ifdef VERBOSE
X IF(verbose)
X ntoforget = "Type n to forget about this newsgroup.\n";
X ELSE
X#endif
X#ifdef TERSE
X ntoforget = "n to forget it.\n";
X#endif
X if (index(what,'/')) {
X dingaling();
X printf("\nBad newsgroup name.\n") FLUSH;
X return FALSE;
X }
X set_ngname(what);
X ng = find_ng(ngname);
X if (ng == nextrcline) { /* not in .newsrc? */
X
X#ifdef SERVER
X sprintf(ser_line, "GROUP %s", ngname);
X put_server(ser_line);
X if (get_server(ser_line, sizeof(ser_line)) < 0) {
X fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X finalize(1);
X }
X if (*ser_line != CHAR_OK) {
X if (atoi(ser_line) != ERR_NOGROUP) {
X fprintf(stderr, "Server response to GROUP %s:\n%s\n",
X ngname, ser_line);
X }
X#else /* not SERVER */
X
X if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X
X#endif /* SERVER */
X
X dingaling();
X#ifdef VERBOSE
X IF(verbose)
X printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X printf("\nNo %s!\n",ngname) FLUSH;
X#endif
X sleep(2);
X return FALSE;
X }
X#ifdef SERVER
X if (addnewbydefault) {
X printf("(Adding %s to end of your .newsrc)\n", ngname);
X ng = add_newsgroup(ngname, ':');
X do_reloc = FALSE;
X } else {
X#endif /* SERVER */
X#ifdef VERBOSE
X IF(verbose)
X sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
X ELSE
X#endif
X#ifdef TERSE
X sprintf(promptbuf,"\nAdd %s? [yn] ",ngname);
X#endif
Xreask_add:
X in_char(promptbuf,'A');
X putchar('\n') FLUSH;
X setdef(buf,"y");
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X#ifdef VERBOSE
X IF(verbose)
X printf("Type y or SP to add %s to your .newsrc.\n", ngname)
X FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("y or SP to add\n",stdout) FLUSH;
X#endif
X fputs(ntoforget,stdout) FLUSH;
X goto reask_add;
X }
X else if (*buf == 'n' || *buf == 'q') {
X ng = add_newsgroup(ngname, '!');
X return FALSE;
X }
X else if (*buf == 'y') {
X ng = add_newsgroup(ngname, ':');
X do_reloc = FALSE;
X }
X#ifdef SERVER
X else if (*buf == 'Y') {
X fputs(
X "(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
X addnewbydefault = 1;
X printf("(Adding %s to end of your .newsrc)\n", ngname);
X ng = add_newsgroup(ngname, ':');
X do_reloc = FALSE;
X }
X#endif /* SERVER */
X else {
X fputs(hforhelp,stdout) FLUSH;
X settle_down();
X goto reask_add;
X }
X#ifdef SERVER
X }
X#endif /* SERVER */
X }
X else if (rcchar[ng] == NEGCHAR) { /* unsubscribed? */
X#ifdef VERBOSE
X IF(verbose)
X sprintf(promptbuf,
X"\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname)
X FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname)
X FLUSH;
X#endif
Xreask_unsub:
X in_char(promptbuf,'R');
X putchar('\n') FLUSH;
X setdef(buf,"y");
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X#ifdef VERBOSE
X IF(verbose)
X printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("y or SP to resubscribe.\n",stdout) FLUSH;
X#endif
X fputs(ntoforget,stdout) FLUSH;
X goto reask_unsub;
X }
X else if (*buf == 'n' || *buf == 'q') {
X return FALSE;
X }
X else if (*buf == 'y') {
X rcchar[ng] = ':';
X }
X else {
X fputs(hforhelp,stdout) FLUSH;
X settle_down();
X goto reask_unsub;
X }
X }
X
X /* now calculate how many unread articles in newsgroup */
X
X set_toread(ng);
X#ifdef RELOCATE
X if (do_reloc)
X ng = relocate_newsgroup(ng,-1);
X#endif
X return toread[ng] >= TR_NONE;
X}
X
X/* add a newsgroup to the .newsrc file (eventually) */
X
XNG_NUM
Xadd_newsgroup(ngn, c)
Xchar *ngn, c;
X{
X register NG_NUM newng = nextrcline++;
X /* increment max rcline index */
X
X rcnums[newng] = strlen(ngn) + 1;
X rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1));
X strcpy(rcline[newng],ngn); /* and copy over the name */
X *(rcline[newng] + rcnums[newng]) = '\0';
X rcchar[newng] = c; /* subscribe or unsubscribe */
X toread[newng] = TR_NONE; /* just for prettiness */
X#ifdef HASHNG
X sethash(newng); /* so we can find it again */
X#endif
X#ifdef RELOCATE
X return c=='!' ? newng : relocate_newsgroup(newng,-1);
X#else
X return newng;
X#endif
X}
X
X#ifdef RELOCATE
XNG_NUM
Xrelocate_newsgroup(ngx,newng)
XNG_NUM ngx;
XNG_NUM newng;
X{
X char *dflt = (ngx!=current_ng ? "$^.L" : "$^L");
X char *tmprcline;
X ART_UNREAD tmptoread;
X char tmprcchar;
X char tmprcnums;
X ACT_POS tmpsoftptr;
X register NG_NUM i;
X#if defined(DEBUGGING) && !defined(USETHREADS)
X ART_NUM tmpngmax;
X#endif
X#ifdef CACHEFIRST
X ART_NUM tmpabs1st;
X#endif
X
X starthere = 0; /* Disable this optimization */
X writesoft = TRUE; /* Update soft pointer file */
X if (ngx < nextrcline-1) {
X#ifdef HASHNG
X for (i=0; i<HASHSIZ; i++) {
X if (hashtbl[i] > ngx)
X --hashtbl[i];
X else if (hashtbl[i] == ngx)
X hashtbl[i] = nextrcline-1;
X }
X#endif
X tmprcline = rcline[ngx];
X tmptoread = toread[ngx];
X tmprcchar = rcchar[ngx];
X tmprcnums = rcnums[ngx];
X tmpsoftptr = softptr[ngx];
X#if defined(DEBUGGING) && !defined(USETHREADS)
X tmpngmax = ngmax[ngx];
X#endif
X#ifdef CACHEFIRST
X tmpabs1st = abs1st[ngx];
X#endif
X for (i=ngx+1; i<nextrcline; i++) {
X rcline[i-1] = rcline[i];
X toread[i-1] = toread[i];
X rcchar[i-1] = rcchar[i];
X rcnums[i-1] = rcnums[i];
X softptr[i-1] = softptr[i];
X#if defined(DEBUGGING) && !defined(USETHREADS)
X ngmax[i-1] = ngmax[i];
X#endif
X#ifdef CACHEFIRST
X abs1st[i-1] = abs1st[i];
X#endif
X }
X rcline[nextrcline-1] = tmprcline;
X toread[nextrcline-1] = tmptoread;
X rcchar[nextrcline-1] = tmprcchar;
X rcnums[nextrcline-1] = tmprcnums;
X softptr[nextrcline-1] = tmpsoftptr;
X#if defined(DEBUGGING) && !defined(USETHREADS)
X ngmax[nextrcline-1] = tmpngmax;
X#endif
X#ifdef CACHEFIRST
X abs1st[nextrcline-1] = tmpabs1st;
X#endif
X }
X if (current_ng > ngx)
X current_ng--;
X if (newng < 0) {
X reask_reloc:
X unflush_output(); /* disable any ^O in effect */
X#ifdef SERVER
X if (addnewbydefault) {
X buf[0] = '$';
X buf[1] = '\0';
X } else {
X#endif /* SERVER */
X#ifdef VERBOSE
X IF(verbose)
X printf("\nPut newsgroup where? [%s] ", dflt);
X ELSE
X#endif
X#ifdef TERSE
X printf("\nPut where? [%s] ", dflt);
X#endif
X fflush(stdout);
X reinp_reloc:
X eat_typeahead();
X getcmd(buf);
X#ifdef SERVER
X }
X#endif /* SERVER */
X if (errno || *buf == '\f') {
X /* if return from stop signal */
X goto reask_reloc; /* give them a prompt again */
X }
X setdef(buf,dflt);
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X#ifdef VERBOSE
X IF(verbose) {
X printf("\n\n\
XType ^ to put the newsgroup first (position 0).\n\
XType $ to put the newsgroup last (position %d).\n", nextrcline-1);
X printf("\
XType . to put it before the current newsgroup (position %d).\n", current_ng);
X printf("\
XType -newsgroup name to put it before that newsgroup.\n\
XType +newsgroup name to put it after that newsgroup.\n\
XType a number between 0 and %d to put it at that position.\n", nextrcline-1);
X printf("\
XType L for a listing of newsgroups and their positions.\n") FLUSH;
X }
X ELSE
X#endif
X#ifdef TERSE
X {
X printf("\n\n\
X^ to put newsgroup first (pos 0).\n\
X$ to put last (pos %d).\n", nextrcline-1);
X printf("\
X. to put before current newsgroup (pos %d).\n", current_ng);
X printf("\
X-newsgroup to put before newsgroup.\n\
X+newsgroup to put after.\n\
Xnumber in 0-%d to put at that pos.\n", nextrcline-1);
X printf("\
XL for list of .newsrc.\n") FLUSH;
X }
X#endif
X goto reask_reloc;
X }
X else if (*buf == 'L') {
X putchar('\n') FLUSH;
X list_newsgroups();
X goto reask_reloc;
X }
X else if (isdigit(*buf)) {
X if (!finish_command(TRUE)) /* get rest of command */
X goto reinp_reloc;
X newng = atol(buf);
X if (newng < 0)
X newng = 0;
X if (newng >= nextrcline)
X return nextrcline-1;
X }
X else if (*buf == '^') {
X putchar('\n') FLUSH;
X newng = 0;
X }
X else if (*buf == '$') {
X putchar('\n') FLUSH;
X return nextrcline-1;
X }
X else if (*buf == '.') {
X putchar('\n') FLUSH;
X newng = current_ng;
X }
X else if (*buf == '-' || *buf == '+') {
X if (!finish_command(TRUE)) /* get rest of command */
X goto reinp_reloc;
X newng = find_ng(buf+1);
X if (newng == nextrcline) {
X fputs("Not found.",stdout) FLUSH;
X goto reask_reloc;
X }
X if (*buf == '+')
X newng++;
X }
X else {
X printf("\n%s",hforhelp) FLUSH;
X settle_down();
X goto reask_reloc;
X }
X }
X if (newng < nextrcline-1) {
X#ifdef HASHNG
X for (i=0; i<HASHSIZ; i++) {
X if (hashtbl[i] == nextrcline-1)
X hashtbl[i] = newng;
X else if (hashtbl[i] >= newng)
X ++hashtbl[i];
X }
X#endif
X tmprcline = rcline[nextrcline-1];
X tmptoread = toread[nextrcline-1];
X tmprcchar = rcchar[nextrcline-1];
X tmprcnums = rcnums[nextrcline-1];
X tmpsoftptr = softptr[nextrcline-1];
X#if defined(DEBUGGING) && !defined(USETHREADS)
X tmpngmax = ngmax[nextrcline-1];
X#endif
X#ifdef CACHEFIRST
X tmpabs1st = abs1st[nextrcline-1];
X#endif
X for (i=nextrcline-2; i>=newng; i--) {
X rcline[i+1] = rcline[i];
X toread[i+1] = toread[i];
X rcchar[i+1] = rcchar[i];
X rcnums[i+1] = rcnums[i];
X softptr[i+1] = softptr[i];
X#if defined(DEBUGGING) && !defined(USETHREADS)
X ngmax[i+1] = ngmax[i];
X#endif
X#ifdef CACHEFIRST
X abs1st[i+1] = abs1st[i];
X#endif
X }
X rcline[newng] = tmprcline;
X toread[newng] = tmptoread;
X rcchar[newng] = tmprcchar;
X rcnums[newng] = tmprcnums;
X softptr[newng] = tmpsoftptr;
X#if defined(DEBUGGING) && !defined(USETHREADS)
X ngmax[newng] = tmpngmax;
X#endif
X#ifdef CACHEFIRST
X abs1st[newng] = tmpabs1st;
X#endif
X }
X if (current_ng >= newng)
X current_ng++;
X return newng;
X}
X#endif
X
X/* List out the newsrc with annotations */
X
Xvoid
Xlist_newsgroups()
X{
X register NG_NUM i;
X char tmpbuf[2048];
X static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"};
X int cmd;
X
X page_init();
X print_lines("\
X # Status Newsgroup\n\
X",STANDOUT);
X for (i=0; i<nextrcline && !int_count; i++) {
X if (toread[i] >= 0)
X set_toread(i);
X *(rcline[i] + rcnums[i] - 1) = rcchar[i];
X if (toread[i] > 0)
X sprintf(tmpbuf,"%3d %6ld ",i,(long)toread[i]);
X else
X sprintf(tmpbuf,"%3d %7s ",i,status[-toread[i]]);
X safecpy(tmpbuf+13,rcline[i],2034);
X *(rcline[i] + rcnums[i] - 1) = '\0';
X if (cmd = print_lines(tmpbuf,NOMARKING)) {
X if (cmd > 0)
X pushchar(cmd);
X break;
X }
X }
X int_count = 0;
X}
X
X/* find a newsgroup in .newsrc */
X
XNG_NUM
Xfind_ng(ngnam)
Xchar *ngnam;
X{
X register NG_NUM ngnum;
X#ifdef HASHNG
X register int hashix = hash(ngnam);
X register int incr = 1;
X
X while ((ngnum = hashtbl[hashix]) >= 0) {
X if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
X return ngnum;
X hashix = (hashix + incr) % HASHSIZ;
X incr += 2; /* offsets from original are in n*2 */
X }
X return nextrcline; /* = notfound */
X
X#else /* just do linear search */
X
X for (ngnum = 0; ngnum < nextrcline; ngnum++) {
X if (strEQ(rcline[ngnum],ngnam))
X break;
X }
X return ngnum;
X#endif
X}
X
Xvoid
Xcleanup_rc()
X{
X register NG_NUM ngx;
X register NG_NUM bogosity = 0;
X
X#ifdef VERBOSE
X IF(verbose)
X fputs("Checking out your .newsrc--hang on a second...\n",stdout)
X FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("Checking .newsrc--hang on...\n",stdout) FLUSH;
X#endif
X for (ngx = 0; ngx < nextrcline; ngx++) {
X if (toread[ngx] >= TR_UNSUB) {
X set_toread(ngx); /* this may reset newsgroup */
X /* or declare it bogus */
X }
X if (toread[ngx] == TR_BOGUS)
X bogosity++;
X }
X for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
X bogosity--; /* discount already moved ones */
X if (nextrcline > 5 && bogosity > nextrcline / 2) {
X fputs(
X"It looks like the active file is messed up. Contact your news administrator,\n\
X",stdout);
X fputs(
X"leave the \"bogus\" groups alone, and they may come back to normal. Maybe.\n\
X",stdout) FLUSH;
X }
X#ifdef RELOCATE
X else if (bogosity) {
X#ifdef VERBOSE
X IF(verbose)
X fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
X stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("Moving boguses to the end.\n",stdout) FLUSH;
X#endif
X for (; ngx >= 0; ngx--) {
X if (toread[ngx] == TR_BOGUS)
X relocate_newsgroup(ngx,nextrcline-1);
X }
X#ifdef DELBOGUS
Xreask_bogus:
X in_char("Delete bogus newsgroups? [ny] ", 'D');
X putchar('\n') FLUSH;
X setdef(buf,"n");
X#ifdef VERIFY
X printcmd();
X#endif
X if (*buf == 'h') {
X#ifdef VERBOSE
X IF(verbose)
X fputs("\
XType y to delete bogus newsgroups.\n\
XType n or SP to leave them at the end in case they return.\n\
X",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("y to delete, n to keep\n",stdout) FLUSH;
X#endif
X goto reask_bogus;
X }
X else if (*buf == 'n' || *buf == 'q')
X ;
X else if (*buf == 'y') {
X while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0)
X --nextrcline; /* real tough, huh? */
X }
X else {
X fputs(hforhelp,stdout) FLUSH;
X settle_down();
X goto reask_bogus;
X }
X#endif
X }
X#else
X#ifdef VERBOSE
X IF(verbose)
X fputs("You should edit bogus newsgroups out of your .newsrc.\n",
X stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("Edit boguses from .newsrc.\n",stdout) FLUSH;
X#endif
X#endif
X paranoid = FALSE;
X}
X
X#ifdef HASHNG
X/* make an entry in the hash table for the current newsgroup */
X
Xvoid
Xsethash(thisng)
XNG_NUM thisng;
X{
X register int hashix = hash(rcline[thisng]);
X register int incr = 1;
X#ifdef DEBUGGING
X static int hashhits = 0, hashtries = 0;
X#endif
X
X#ifdef DEBUGGING
X hashtries++;
X#endif
X while (hashtbl[hashix] >= 0) {
X#ifdef DEBUGGING
X hashhits++;
X if (debug & DEB_HASH) {
X printf(" Hash hits: %d / %d\n",hashhits, hashtries) FLUSH;
X }
X hashtries++;
X#endif
X hashix = (hashix + incr) % HASHSIZ;
X incr += 2; /* offsets from original are in n*2 */
X }
X hashtbl[hashix] = thisng;
X}
X
Xshort prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59,
X -61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1};
X
Xint
Xhash(ngnam)
Xregister char *ngnam;
X{
X register int i = 0;
X register int ch;
X register int sum = 0;
X#ifdef DEBUGGING
X char *ngn = ngnam;
X#endif
X
X while (ch = *ngnam++) {
X sum += (ch + i) * prime[i]; /* gives ~ 10% hits at 25% full */
X i++;
X }
X#ifdef DEBUGGING
X if (debug & DEB_HASH)
X printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ)
X FLUSH;
X#endif
X if (sum < 0)
X sum = -sum;
X return sum % HASHSIZ;
X}
X
X#endif
X
Xvoid
Xnewsrc_check()
X{
X rcfp = fopen(rcname,"r"); /* open it */
X if (rcfp == Nullfp) { /* not there? */
X#ifdef VERBOSE
X IF(verbose)
X fputs("\
XTrying to set up a .newsrc file--running newsetup...\n\n\
X",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("Setting up .newsrc...\n",stdout) FLUSH;
X#endif
X if (doshell(sh,filexp(NEWSETUP)) ||
X (rcfp = fopen(rcname,"r")) == Nullfp) {
X#ifdef VERBOSE
X IF(verbose)
X fputs("\
XCan't create a .newsrc--you must do it yourself.\n\
X",stdout) FLUSH;
X ELSE
X#endif
X#ifdef TERSE
X fputs("(Fatal)\n",stdout) FLUSH;
X#endif
X finalize(1);
X }
X }
X else {
X UNLINK(rcbname); /* unlink backup file name */
X link(rcname,rcbname); /* and backup current name */
X }
X}
X
X/* write out the (presumably) revised .newsrc */
X
Xvoid
Xwrite_rc()
X{
X register NG_NUM tmpng;
X register char *delim;
X
X rcfp = fopen(rctname, "w"); /* open .newsrc */
X if (rcfp == Nullfp) {
X printf("Can't recreate .newsrc\n") FLUSH;
X finalize(1);
X }
X
X /* write out each line*/
X
X for (tmpng = 0; tmpng < nextrcline; tmpng++) {
X if (rcnums[tmpng]) {
X delim = rcline[tmpng] + rcnums[tmpng] - 1;
X *delim = rcchar[tmpng];
X }
X else
X delim = Nullch;
X#ifdef DEBUGGING
X if (debug & DEB_NEWSRC_LINE)
X printf("%s\n",rcline[tmpng]) FLUSH;
X#endif
X fprintf(rcfp,"%s\n",rcline[tmpng]);
X if (delim)
X *delim = '\0'; /* might still need this line */
X }
X
X fclose(rcfp); /* close .newsrc */
X UNLINK(rcname);
X link(rctname,rcname);
X UNLINK(rctname);
X
X if (writesoft) {
X tmpfp = fopen(filexp(softname), "w"); /* open .rnsoft */
X if (tmpfp == Nullfp) {
X printf(cantcreate,filexp(softname)) FLUSH;
X return;
X }
X for (tmpng = 0; tmpng < nextrcline; tmpng++) {
X fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
X }
X fclose(tmpfp);
X }
X}
X
Xvoid
Xget_old_rc()
X{
X UNLINK(rctname);
X link(rcname,rctname);
X UNLINK(rcname);
X link(rcbname,rcname);
X UNLINK(rcbname);
X}
END_OF_FILE
if test 23291 -ne `wc -c <'rcstuff.c'`; then
echo shar: \"'rcstuff.c'\" unpacked with wrong size!
fi
# end of 'rcstuff.c'
fi
echo shar: End of archive 3 \(of 14\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 14 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list