This is a new archive version of TRN at patchlevel 3. The original posting took up Volume23, issues 60 to 73, with various problems. These files replace those issues. #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: bits.h init.c mthreads.1 ngdata.c ngstuff.c term.h util.c # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:39:01 1991 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 11 (of 14)."' if test -f 'bits.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'bits.h'\" else echo shar: Extracting \"'bits.h'\" \(2440 characters\) sed "s/^X//" >'bits.h' <<'END_OF_FILE' X/* $Header: bits.h,v 4.3.3.2 91/01/16 02:29:50 davison Trn $ X * X * $Log: bits.h,v $ X * Revision 4.3.3.2 91/01/16 02:29:50 davison X * Added optional prototyping. X * X * Revision 4.3.3.1 90/06/20 22:36:35 davison X * Initial Trn Release X * X * Revision 4.3.2.1 90/11/22 15:46:42 sob X * Made changes to make pickly preprocessors happier. X * X * Revision 4.3.1.2 86/11/03 09:49:58 lwall X * Added firstbit variable. X * X * Revision 4.3.1.1 85/05/10 11:31:52 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:36:39 lwall X * Baseline for release with 4.3bsd. X * X */ X XEXT char *ctlarea INIT(Nullch); /* one bit for each article in current newsgroup */ X /* with the following interpretation: */ X /* 0 => unread */ X /* 1 => read */ X X/* if subscripting is faster than shifting on your machine, define this */ X#undef USESUBSCRIPT X#ifdef USESUBSCRIPT XEXT char powerof2[] INIT({1,2,4,8,16,32,64,128}); X#define pow2(x) powerof2[x] X#else X#define pow2(x) (1 << (x)) X#endif X X#ifdef lint XEXT bool nonesuch INIT(FALSE); X#define ctl_set(a) X#define ctl_clear(a) X#define ctl_read(a) nonesuch X#define was_read(a) nonesuch X#else X#define ctl_set(a) (ctlarea[(OFFSET(a)) / BITSPERBYTE] |= pow2((OFFSET(a)) % BITSPERBYTE)) X#define ctl_clear(a) (ctlarea[(OFFSET(a)) / BITSPERBYTE] &= ~pow2((OFFSET(a)) % BITSPERBYTE)) X#define ctl_read(a) ((ctlarea[(OFFSET(a)) / BITSPERBYTE] & pow2((OFFSET(a)) % BITSPERBYTE)) != 0) X X#define was_read(a) ((a)'init.c' <<'END_OF_FILE' X/* $Header: init.c,v 4.3.3.2 91/01/16 02:43:39 davison Trn $ X * X * $Log: init.c,v $ X * Revision 4.3.3.2 91/01/16 02:43:39 davison X * Integrated rn patches 48-54. Twiddled 'rn' to 'trn'. X * X * Revision 4.3.3.1 90/06/20 22:37:39 davison X * Initial Trn Release X * X * Revision 4.3.2.8 90/11/22 13:51:39 sob X * Removed some cruft trailing the #endif directive to make more compilers X * happy. X * X * Revision 4.3.2.7 90/10/30 22:42:23 sob X * Used fileno() instead of _file to increase portability. X * X * Revision 4.3.2.6 90/05/08 22:05:55 sob X * Added quick startup (-q) flag. X * X * Revision 4.3.2.5 90/05/04 23:10:01 sob X * Fix for exiting "second" rn such that tty will be left in correct state. X * Provided by glenn@mathcs.emory.edu X * X * Revision 4.3.2.4 90/03/22 23:04:32 sob X * Fixes provided by Wayne Davison X * X * Revision 4.3.2.3 90/03/17 21:34:04 sob X * Cleaned up a bit. X * X * Revision 4.3.2.2 89/11/08 01:17:48 sob X * Added changes to insure that this will compile for RN or RRN with no X * changes to the source code. X * X * Revision 4.3.2.1 89/11/06 00:39:14 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3.1.4 86/09/05 14:24:02 lwall X * Removed net.announce dependency. X * X * Revision 4.3.1.3 85/07/23 18:08:36 lwall X * Fixed up NOLINEBUF option to work. X * X * Revision 4.3.1.2 85/05/21 14:22:46 lwall X * Sped up "rn -c" by avoiding unnecessary initialization. X * X * Revision 4.3.1.1 85/05/10 11:33:39 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 16:16:13 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 "final.h" X#include "term.h" X#include "last.h" X#include "rn.h" X#include "rcstuff.h" X#include "ngdata.h" X#include "only.h" X#include "intrp.h" X#include "addng.h" X#include "sw.h" X#include "art.h" X#include "artsrch.h" X#include "artio.h" X#include "backpage.h" X#include "bits.h" X#include "cheat.h" X#include "head.h" X#include "help.h" X#include "kfile.h" X#include "ngsrch.h" X#include "ngstuff.h" X#include "rcln.h" X#include "respond.h" X#ifdef SERVER X#include "server.h" X#endif X#ifdef USETHREADS X#include "rthreads.h" X#endif X#include "ng.h" X#include "INTERN.h" X#include "init.h" X Xbool Xinitialize(argc,argv) Xint argc; Xchar *argv[]; X{ X char *tcbuf; X register bool foundany = FALSE; X long time(); X#ifdef SERVER X char *server; X int response; X#endif X#ifdef NOLINEBUF X static char std_out_buf[BUFSIZ]; /* must be static or malloced */ X X setbuf(stdout, std_out_buf); X#endif X X tcbuf = safemalloc(1024); /* make temp buffer for termcap and */ X /* other initialization stuff */ X X /* init terminal */ X X term_init(); /* must precede sw_init() so that */ X /* ospeed is set for baud-rate */ X /* switches. Actually terminal */ X /* mode setting is in term_set() */ X X /* we have to know rnlib to look up global switches in %X/INIT */ X X lib = savestr(filexp(LIB)); X rnlib = savestr(filexp(RNLIB)); X X /* decode switches */ X X sw_init(argc,argv,&tcbuf); /* must not do % interps! */ X /* (but may mung environment) */ X X /* init signals, status flags */ X X final_init(); X X /* start up file expansion and the % interpreter */ X X intrp_init(tcbuf); X X /* now make sure we have a current working directory */ X X if (!checkflag) X cwd_check(); X X /* now that we know where to save things, cd to news directory */ X X if (chdir(spool)) { X printf(nocd,spool) FLUSH; X finalize(1); X } X X /* if we aren't just checking, turn off echo */ X X if (!checkflag) X term_set(tcbuf); X X /* get info on last rn run, if any */ X X if (!checkflag) X last_init(tcbuf); X X free(tcbuf); /* recover 1024 bytes */ X X /* make sure we are the sole possessors of .newsrc */ X X if (!checkflag) X lock_check(); X X /* check for news news */ X X if (!checkflag) X newsnews_check(); X X#ifdef SERVER X X /* open connection to server if appropriate */ X X server = getserverbyfile(SERVER_FILE); X if (server == NULL) { X fprintf(stderr, "Can't get the name of the news server from %s\n", X SERVER_FILE); X fprintf(stderr, X "Either fix this file, or put NNTPSERVER in your environment.\n"); X finalize(1); X } X X response = server_init(server); X if (response < 0) { X fprintf(stderr, X "Couldn't connect to %s news server, try again later.\n", X server); X finalize(1); X } X X if (handle_server_response(response, server) < 0) X finalize(1); X X#endif X X /* open active file, etc. */ X X ngdata_init(); X X /* now read in the .newsrc file */ X X foundany = rcstuff_init(); X X /* it looks like we will actually read something, so init everything */ X X addng_init(); X art_init(); X artio_init(); X artsrch_init(); X backpage_init(); X bits_init(); X cheat_init(); X head_init(); X help_init(); X kfile_init(); X ng_init(); X ngsrch_init(); X ngstuff_init(); X only_init(); X rcln_init(); X respond_init(); X rn_init(); X search_init(); X#ifdef USETHREADS X thread_init(); X#endif X util_init(); X X#ifdef FINDNEWNG X/* fstat(actfp->_file,&filestat); ... does not work on Apollos */ X fstat(fileno(actfp),&filestat); /* did active file grow? */ X /* X * Skip this check if the -q flag was given. X */ X X if (!quickstart && filestat.st_size != lastactsiz) { X long actsiz = filestat.st_size; /* remember new size */ X NG_NUM oldnext = nextrcline; /* remember # lines in newsrc */ X#ifdef FASTNEW X bool munged = writesoft || !lastactsiz; X /* bad soft ptrs -> edited active */ X#else X bool munged = TRUE; /* just assume .newsrc munged */ X#endif X X#ifdef VERBOSE X IF(verbose) X fputs("\nChecking active list for new newsgroups...\n",stdout) X FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nNew newsgroups:\n",stdout) FLUSH; X#endif X#ifdef FASTNEW X if (!munged) { /* maybe just do tail of file? */ X fseek(actfp,lastactsiz-NL_SIZE,0); X fgets(buf,LBUFLEN,actfp); X munged = (*buf != '\n'); X if (!munged) X munged = newlist(munged,FALSE); X } X#endif X if (munged) { /* must we scan entire file? */ X fseek(actfp,0L,0); /* rewind active file */ X newlist(munged,FALSE); /* sure hope they use hashing... */ X } X lastactsiz = actsiz; /* remember for .rnlast */ X if (nextrcline != oldnext) { /* did we add any new groups? */ X foundany = TRUE; /* let main() know */ X starthere = 0; /* and start ng scan from the top */ X } X } X#endif X time(&lasttime); /* remember when we inited-- */ X /* ends up back in .rnlast */ X writelast(); /* in fact, put it there now */ X X#ifdef FINDNEWNG X# ifdef ONLY X if (maxngtodo) /* patterns on command line? */ X foundany |= scanactive(); X# endif X#endif X X return foundany; X} X X/* make sure there is no rn out there already */ X Xvoid Xlock_check() X{ X lockname = savestr(filexp(LOCKNAME)); X if (!checkflag) { X tmpfp = fopen(lockname,"r"); X if (tmpfp != Nullfp) { X int processnum; X X fgets(buf,LBUFLEN,tmpfp); X fclose(tmpfp); X processnum = atoi(buf); X#ifdef VERBOSE X IF(verbose) X printf("You seem to have left a trn running, process %d.\n", X processnum) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("Trn left running, #%d.\n", processnum) FLUSH; X#endif X if (kill(processnum, SIGEMT)) { X /* does process not exist? */ X /* (rn ignores SIGEMT) */ X sleep(2); X#ifdef VERBOSE X IF(verbose) X fputs("\n\ XThat process does not seem to exist anymore. The count of read articles\n\ Xmay be incorrect in the last newsgroup accessed by that other (defunct)\n\ Xprocess.\n\n",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nProcess crashed.\n",stdout) FLUSH; X#endif X if (*lastngname) { X#ifdef VERBOSE X IF(verbose) X printf("(The last newsgroup accessed was %s.)\n\n", X lastngname) FLUSH; X ELSE X#endif X#ifdef TERSE X printf("(In %s.)\n\n",lastngname) FLUSH; X#endif X } X get_anything(); X putchar('\n') FLUSH; X } X else { X#ifdef VERBOSE X IF(verbose) X fputs("\n\ XYou may not have two copies of [t]rn running simultaneously. Goodbye.\n\ X",stdout) FLUSH; X ELSE X#endif X#ifdef TERSE X fputs("\nCan't start another.\n",stdout) FLUSH; X#endif X if (bizarre) X resetty(); X exit(0); X } X } X tmpfp = fopen(lockname,"w"); X if (tmpfp == Nullfp) { X printf(cantcreate,lockname) FLUSH; X sig_catcher(0); X } X fprintf(tmpfp,"%d\n",getpid()); X fclose(tmpfp); X } X} X Xvoid Xnewsnews_check() X{ X char *newsnewsname = filexp(NEWSNEWSNAME); X X if ((tmpfp = fopen(newsnewsname,"r")) != Nullfp) { X/* fstat(tmpfp->_file,&filestat); .... does not work on Apollos */ X fstat(fileno(tmpfp),&filestat); X if (filestat.st_mtime > lasttime) { X while (fgets(buf,sizeof(buf),tmpfp) != Nullch) X fputs(buf,stdout) FLUSH; X get_anything(); X putchar('\n') FLUSH; X } X fclose(tmpfp); X } X} END_OF_FILE if test 8905 -ne `wc -c <'init.c'`; then echo shar: \"'init.c'\" unpacked with wrong size! fi # end of 'init.c' fi if test -f 'mthreads.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mthreads.1'\" else echo shar: Extracting \"'mthreads.1'\" \(9578 characters\) sed "s/^X//" >'mthreads.1' <<'END_OF_FILE' X''' $Header: mthreads.1,v 4.3.3.3 91/01/18 19:27:39 davison Trn $ X''' X''' $Log: mthreads.1,v $ X''' Revision 4.3.3.3 91/01/18 19:27:39 davison X''' Added commands -s and -z. X''' X''' Revision 4.3.3.2 90/08/20 16:42:32 davison X''' Document new command-line interface. X''' X''' Revision 4.3.3.1 90/07/21 20:03:37 davison X''' Initial Trn Release X''' X''' X.de Sh X.br X.ne 5 X.PP X\fB\\$1\fR X.PP X.. X.de Sp X.if t .sp .5v X.if n .sp X.. X.de Ip X.br X.ie \\n.$>=3 .ne \\$3 X.el .ne 3 X.IP "\\$1" \\$2 X.. X''' X''' Set up \*(-- to give an unbreakable dash; X''' string Tr holds user defined translation string. X''' Bell System Logo is used as a dummy character. X''' X.tr \(bs-|\(bv\*(Tr X.ie n \{\ X.ds -- \(bs- X.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch X.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch X.ds L" "" X.ds R" "" X.ds L' ' X.ds R' ' X'br\} X.el\{\ X.ds -- \(em\| X.tr \*(Tr X.ds L" `` X.ds R" '' X.ds L' ` X.ds R' ' X'br\} X.TH MTHREADS 1 LOCAL X.UC 6 X.SH NAME Xmthreads - threaded database manager for trn X.SH SYNOPSIS X.B mthreads [-d[MM]] [-e[HHMM]] [-aDfknv] [hierarchy_list] X.SH DESCRIPTION X.I Mthreads Xmanages the thread files that are used by the X.IR trn (1) Xnewsreader. X\*(L"Thread files\*(R" are used to store information about the news Xarticles and how they are all related to one another. X.PP X.I Mthreads Xneeds to be run Xperiodically \*(-- either in single-pass mode out of cron, Xor in daemon mode out of the boot script \*(-- to update the thread Xinformation whenever new news is received. XA site that gets its news feed during the night and doesn't need local Xpostings processed throughout the day can run X.I mthreads Xin single-pass mode once a day. XIf more processing is needed, either run X.I mthreads Xmore often or run it in daemon mode. XIn daemon mode, a background process is forked off that wakes up every 10 Xminutes (by default) to check if the active file has been updated. X.SH INSTALLATION X.I Mthreads Xin installed in the RNLIB directory chosen during configuration. XWhen it is run for the first time, it will automatically create a file called X.I active2 Xin the same directory. XThis file is essentially a copy of the active file that keeps the newsgroup Xtotals from the last run in one place. XIt is also used to choose which groups are to be processed into thread files. XAll groups start out as \*(L"unthreaded\*(R" unless they are turned on with Xa command like: X.IP Xmthreads all X.PP Xwhich would create thread file for all the groups. XFor testing purposes it is a good idea to start out small with a command Xlike: X.IP Xmthreads news X.PP Xwhich would thread only the news hierarchy. XThread processing can be turned on or off for individual groups or entire Xhierarchies by specifying the groups in a syntax very similar to that used Xin the sys file. XFor example, to turn on all of soc and talk except for talk.politics, and Xto turn off news.lists, use the following command once: X.IP Xmthreads soc,talk,!talk.politics,!news.lists X.PP XIf mthreads complains that another mthreads process is already running, Xit can be killed with the command: X.IP Xmthreads -k X.PP Xand then repeat the prior command after giving it a little time to die. X.PP XOnce all the desired groups are turned on, it is not necessary to Xspecify a hierarchy list for the normal functioning of mthreads. XIt can be used, however, to customize which new groups get turned on Xas they are created. X.SH LOGGING XAs mthreads executes, some status information (including error messages) Xis placed in Xthe file mt.log in the RNLIB directory. XThis file will grow without bounds, and should be scanned periodically for Xerrors, and trimmed in size when it grows too large. XSee the shell script X.I mt.check Xfor an mt.log maintainer that will send mail if it finds database errors. X.SH OPTIONS X.TP 5 X.B \-a Xis used to automatically turn on thread processing for new news groups as Xthey are created. XThe default is to leave new groups unthreaded. X.TP 5 X.B \-D Xspecifies a debugging mode where only the groups mentioned on the Xcommand-line are processed \*(-- all other groups are left unchanged. XIt also outputs each group's name into the log file before it is processed. X.TP 5 X.B \-d Xis used to specify the daemon mode, where X.I mthreads Xforks a background task that periodically wakes up and checks for an updated Xactive file. XThe number of minutes to wait after the completion of the last pass can Xbe specified after the '-d' option (e.g. -d20), otherwise it will default to X10 minutes. X.TP 5 X.B \-e Xtells X.I mthreads Xto run an enhanced expiration check on the database. XWithout this option, only articles below the minimum field in the active Xfile are expired. XWith this option, all unexpired articles in the database are stat()'ed to Xsee if they actually exist. XIn single-pass mode the X.B -e Xoption always affects the current pass \*(-- use it Xonce a day after expire has run. XIn daemon mode, the X.B -e Xoption will cause one pass a day to be the enhanced expire pass. XBy default, this is the first time mthreads wakes up after 12:30 am. XIf a different time is desired, it can be specified in the form HHMM X(e.g. -e2359). X.TP 5 X.B -f Xis used to force X.I mthreads Xto open each and every thread file to see which ones really need to be Xupdated, not just the ones that differ in the active/active2 comparison. XIt will also remove any extraneous thread files from unthreaded groups X(which should only occur if you manually change the active2 file). XThis option should only be used when manipulating the thread files in Xunorthodox ways. X.TP 5 X.B -k Xcan be used to terminate the currently running mthreads, just as if it Xhad received a terminate signal. XWhen this option is specified, no other activity is performed. X.TP 5 X.B -n Xtells X.I mthreads Xthat no actual processing of thread files is to be performed. XThis can be used to just adjust which groups are to be processed, without Xactually doing any of the processing right away. X.TP 5 X.B -s Xtells mthreads to sleep one second before processing each article. XThis is useful if your NNTP server cannot handle mthreads running at Xfull speed. XFor each additional X.B -s Xspecified, mthreads sleeps an additional second. X.TP 5 X.B -v Xselects additional levels of verbosity in the log file. XThe default (without -v) is to log mthread's startup, the totals for each Xpass, the inclusion of the enhanced expire option, and major database errors. XAdd one X.B -v Xto get extra reference line problems logged into the file. XAdd a second and a third for even more (useless?) information. XA fourth will cause mthreads to output each group's name into the log file Xbefore it is processed. X.TP 5 X.B -z Xtells mthreads to 'zap' any thread file it believes to be corrupt. XThis will allow the file to be regenerated from scratch on the next pass. X.TP 5 X.B hierarchy_list XThe hierarchy list is used to turn thread processing on or off for the listed Xgroups. XThe groups are specified in a manner very similar to the news software's Xsys file: \*(L"news\*(R" matches all groups in news; \*(L"!news\*(R" excludes Xall groups in news; \*(L"comp.all.ibm.pc,!comp.all.ibm.pc.all\*(L" matches both Xcomp.sys.ibm.pc and comp.binaries.ibm.pc, but not comp.binaries.ibm.pc.d. X.Sp XThe hierarchy_list is also used in conjunction with the debug flag to only Xprocess one or more groups for testing purposes. X.SH OUTPUT XWhen X.I mthreads Xis run in single-pass mode it generates a stream a status characters on Xstdout that present a visual display of what is happening. If Xsingle-pass mode is used for regular processing, this output can be Xredirected to /dev/null. X.Sp XThe output definitions: X.br X \&'.' = group's entry is up-to-date X.br X \&':' = group processed -- no change X.br X \&'#' = group processed X.br X \&'-' = group processed -- is now empty X.br X \&'x' = group excluded in active X.br X \&'X' = group excluded in active2 X.br X \&'*' = chdir failed (might be ok) X.br X \&'!' = write failed (is NOT ok) X.br X \&'e' = informational error X.br X \&'E' = database-affecting error -- please report! X.SH CONFIGURATION XDuring the configuration of X.I trn Xa choice was made about where to place the thread data files. XThey either exist as a .thread file in each group's spool directory, or Xthey are a group.th file in a one-off directory structure on another drive. XSee the THREAD_DIR definition in config.h to review or change this definition. X.SH REBUILDING XIf the thread files are ever removed, also remove the file db.init in Xthe RNLIB directory. XThis file contains the byte-order of the machine that generated the database, Xand needs to be removed to truly start from scratch. XAn easy way to get X.I mthreads Xto remove all the files except for db.init is to specify the command: X.IP Xmthreads !all X.PP XThis also turns off thread processing for all groups. X.SH "ERROR HANDLING" XIf the active2 file is removed or corrupted, it will Xbe automatically rebuilt in the normal course of operation. XThe record of which groups should be threaded will be lost, however. XMissing/corrupted thread files are automatically re-built. X.SH EXAMPLES XRecommended commands to run on a regular basis are: X.IP Xmthreads -adve0630 X.PP Xto start up an mthreads daemon in verbose logging mode that automatically Xthreads new groups and performs an extended expire at 6:30 am, or: X.IP Xmthreads -e >/dev/null X.PP Xto run an mthreads single-pass with extended expire that leaves new groups Xunthreaded. X.SH FILES X/usr/lib/news/active X.br X$RNLIB/active2 X.br X$RNLIB/mt.log X.br X$RNLIB/db.init X.br X$RNLIB/LOCKmthreads X.br XLots of thread data files. X.SH AUTHOR XWayne Davison END_OF_FILE if test 9578 -ne `wc -c <'mthreads.1'`; then echo shar: \"'mthreads.1'\" unpacked with wrong size! fi # end of 'mthreads.1' fi if test -f 'ngdata.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ngdata.c'\" else echo shar: Extracting \"'ngdata.c'\" \(8913 characters\) sed "s/^X//" >'ngdata.c' <<'END_OF_FILE' X/* $Header: ngdata.c,v 4.3.3.2 91/01/16 03:18:21 davison Trn $ X * X * $Log: ngdata.c,v $ X * Revision 4.3.3.2 91/01/16 03:18:21 davison X * Integrated rn patches 48-54. Fixed bug in ZEROGLOB code. X * X * Revision 4.3.3.1 90/07/21 20:28:27 davison X * Initial Trn Release X * X * Revision 4.3.2.11 90/11/22 16:14:34 sob X * Added changes to accomodate picky C preprocessors X * X * Revision 4.3.2.10 90/04/14 22:05:15 sob X * Removed redundant declaration of active_name X * X * Revision 4.3.2.9 90/03/22 23:04:55 sob X * Fixes provided by Wayne Davison X * X * Revision 4.3.2.8 90/03/17 20:50:51 sob X * Fixes provided by stewart@netxcom.iad-nxe.global-mis.dhl.com to handle X * flaky transfers of the active file from the server. X * X * Revision 4.3.2.7 90/03/17 17:11:08 sob X * Added support for CNEWS active file flags. X * X * Revision 4.3.2.6 89/12/08 22:42:04 sob X * Corrected typo in an #ifdef statement pointed out by X * jik@pit-manager.mit.edu X * X * Revision 4.3.2.5 89/11/28 01:51:14 sob X * Removed redundant #include directive. X * X * Revision 4.3.2.4 89/11/27 01:31:07 sob X * Altered NNTP code per ideas suggested by Bela Lubkin X * X * X * Revision 4.3.2.3 89/11/08 02:41:40 sob X * Removed unneeded subroutine. X * X * Revision 4.3.2.2 89/11/08 02:24:31 sob X * Integrated modifications from other RRN patches colleceted from USENET X * X * Revision 4.3.2.1 89/11/06 00:42:43 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3 85/05/01 11:44:38 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "ndir.h" X#include "rcstuff.h" X#include "rn.h" X#include "intrp.h" X#include "final.h" X#include "rcln.h" X#include "util.h" X#ifdef SERVER X#include "server.h" X#endif X#include "INTERN.h" X#include "ngdata.h" X Xvoid Xngdata_init() X{ X#ifdef SERVER X char ser_line[256]; X int entries; X#endif X char *cp; X X/* The following is only for systems that do not zero globals properly */ X#ifdef ZEROGLOB X# ifdef CACHEFIRST X { X int i; X for (i=0; i= 0) { X if (softptr[num] != oldsoft) { X softmisses++; X writesoft = TRUE; X } X } X else { X softptr[num] = 0; X if (rcchar[num] == ':') /* unsubscribe quietly */ X rcchar[num] = NEGCHAR; X return TR_BOGUS; /* well, not so quietly, actually */ X } X X#ifdef DEBUGGING X if (debug & DEB_SOFT_POINTERS) { X printf("Should be %ld\n",(long)softptr[num]) FLUSH; X } X#endif X#ifdef MININACT X { X register char *s, ch; X ART_NUM tmp; X X for (s=tmpbuf+len+1; isdigit(*s); s++) ; X if (tmp = atol(s)) X#ifdef CACHEFIRST X abs1st[num] = tmp; X#else X abs1st = tmp; X#endif X if (!in_ng) { X for (s++; isdigit(*s); s++) ; X while (isspace(*s)) s++; X ch = *s; X#ifdef USETHREADS X if (isupper(ch)) { X ch = tolower(ch); X ThreadedGroup = FALSE; X } else X ThreadedGroup = use_threads; X#endif X switch (ch) { X case 'n': moderated = getval("NOPOSTRING"," (no posting)"); break; X case 'm': moderated = getval("MODSTRING", " (moderated)"); break; X /* This shouldn't even occur. What are we doing in a non-existent X group? Disallow it. */ X case 'x': return TR_BOGUS; X /* what should be done about refiled groups? rn shouldn't even X be in them (ie, if sci.aquaria is refiled to rec.aquaria, then X get the news there) */ X case '=': return TR_BOGUS; X default: moderated = nullstr; X } X } X } X#endif X return atol(tmpbuf+len+1); X} X XACT_POS Xfindact(outbuf,nam,len,suggestion) Xchar *outbuf; Xchar *nam; Xint len; Xlong suggestion; X{ X ACT_POS retval; X X fseek(actfp,100000L,1); /* hopefully this forces a reread */ X if (suggestion == 0L || fseek(actfp,suggestion,0) < 0 || X fgets(outbuf,80,actfp) == Nullch || X outbuf[len] != ' ' || X strnNE(outbuf,nam,len)) { X#ifdef DEBUGGING X if (debug & DEB_SOFT_POINTERS) X printf("Missed, looking for %s in %sLen = %d\n",nam,outbuf,len) X FLUSH; X#endif X fseek(actfp,0L,0); X#ifndef lint X retval = (ACT_POS)ftell(actfp); X#else X retval = Null(ACT_POS); X#endif /* lint */ X while (fgets(outbuf,80,actfp) != Nullch) { X if (outbuf[len] == ' ' && strnEQ(outbuf,nam,len)) X return retval; X#ifndef lint X retval = (ACT_POS) ftell(actfp); X#endif /* lint */ X } X return (ACT_POS) -1; /* well, not so quietly, actually */ X } X else X#ifndef lint X return (ACT_POS) suggestion; X#else X return retval; X#endif /* lint */ X /*NOTREACHED*/ X} X X/* determine the absolutely first existing article number */ X#ifdef SERVER XART_NUM Xgetabsfirst(ngnum,ngsize) Xregister NG_NUM ngnum; XART_NUM ngsize; X{ X register ART_NUM a1st; X#ifndef MININACT X char ser_line[256]; X ART_NUM x,y; X#endif X X#ifdef CACHEFIRST X if (a1st = abs1st[ngnum]) X return a1st; X#endif X#ifdef MININACT X getngsize(ngnum); X# ifdef CACHEFIRST X return abs1st[ngnum]; X# else X return abs1st; X# endif X#else X sprintf(cp,"GROUP %s",rcline[ngnum]); X put_server(cp); 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) { /* and then see if that's ok */ X a1st = ngsize+1; /* nothing there */ X } X (void) sscanf(ser_line,"%d%d%d",&x,&y,&a1st); X# ifdef CACHEFIRST X abs1st[ngnum] = a1st; X# endif X return a1st; X#endif X} X/* we already know the lowest article number with NNTP */ XART_NUM Xgetngmin(dirname,floor) Xchar *dirname; XART_NUM floor; X{ X return(floor); X} X#else XART_NUM Xgetabsfirst(ngnum,ngsize) Xregister NG_NUM ngnum; XART_NUM ngsize; X{ X register ART_NUM a1st; X#ifndef MININACT X char dirname[MAXFILENAME]; X#endif X X#ifdef CACHEFIRST X if (a1st = abs1st[ngnum]) X return a1st; X#endif X#ifdef MININACT X getngsize(ngnum); X# ifdef CACHEFIRST X return abs1st[ngnum]; X# else X return abs1st; X# endif X#else /* not MININACT */ X sprintf(dirname,"%s/%s",spool,getngdir(rcline[ngnum])); X a1st = getngmin(dirname,0L); X if (!a1st) /* nothing there at all? */ X a1st = ngsize+1; /* aim them at end of newsgroup */ X# ifdef CACHEFIRST X abs1st[ngnum] = a1st; X# endif X return a1st; X#endif /* MININACT */ X} X X/* scan a directory for minimum article number greater than floor */ X XART_NUM Xgetngmin(dirname,floor) Xchar *dirname; XART_NUM floor; X{ X register DIR *dirp; X register struct DIRTYPE *dp; X register ART_NUM min = 1000000; X register ART_NUM maybe; X register char *p; X char tmpbuf[128]; X X dirp = opendir(dirname); X if (!dirp) X return 0; X while ((dp = readdir(dirp)) != Null(struct DIRTYPE *)) { X if ((maybe = atol(dp->d_name)) < min && maybe > floor) { X for (p = dp->d_name; *p; p++) X if (!isdigit(*p)) X goto nope; X if (*dirname == '.' && !dirname[1]) X stat(dp->d_name, &filestat); X else { X sprintf(tmpbuf,"%s/%s",dirname,dp->d_name); X stat(tmpbuf, &filestat); X } X if (! (filestat.st_mode & S_IFDIR)) X min = maybe; X } X nope: X ; X } X closedir(dirp); X return min==1000000 ? 0 : min; X} X#endif END_OF_FILE if test 8913 -ne `wc -c <'ngdata.c'`; then echo shar: \"'ngdata.c'\" unpacked with wrong size! fi # end of 'ngdata.c' fi if test -f 'ngstuff.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ngstuff.c'\" else echo shar: Extracting \"'ngstuff.c'\" \(10924 characters\) sed "s/^X//" >'ngstuff.c' <<'END_OF_FILE' X/* $Header: ngstuff.c,v 4.3.3.3 91/01/16 03:18:25 davison Trn $ X * X * $Log: ngstuff.c,v $ X * Revision 4.3.3.3 91/01/16 03:18:25 davison X * Changed some expressions to registers to bypass a compiler problem. X * X * Revision 4.3.3.2 90/08/20 18:29:08 davison X * Expanded path arrays for consistancy. X * X * Revision 4.3.3.1 90/07/21 20:29:12 davison X * Initial Trn Release X * X * Revision 4.3.2.2 90/04/14 19:40:02 sob X * Fixed small syntax problem that generates errors with particular C X * preprocessors. X * X * Revision 4.3.1.2 85/05/10 14:31:52 lwall X * Prevented "Junked" or "Marked unread" when no state change. X * X * Revision 4.3.1.1 85/05/10 11:36:45 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:45:03 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "term.h" X#include "util.h" X#include "ng.h" X#include "bits.h" X#include "intrp.h" X#include "cheat.h" X#include "head.h" X#include "final.h" X#include "sw.h" X#ifdef USETHREADS X#include "rthreads.h" X#include "rn.h" X#include "rcstuff.h" X#endif X#include "uudecode.h" X#include "INTERN.h" X#include "ngstuff.h" X Xvoid Xngstuff_init() X{ X ; X} X X/* do a shell escape */ X Xint Xescapade() X{ X register char *s; X bool interactive = (buf[1] == FINISHCMD); X bool docd; X char whereiam[512]; X X if (!finish_command(interactive)) /* get remainder of command */ X return -1; X s = buf+1; X docd = *s != '!'; X if (!docd) { X s++; X } X else { X getwd(whereiam); X if (chdir(cwd)) { X printf(nocd,cwd) FLUSH; X sig_catcher(0); X } X } X while (*s == ' ') s++; X /* skip leading spaces */ X interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */ X resetty(); /* make sure tty is friendly */ X doshell(Nullch,cmd_buf); /* invoke the shell */ X noecho(); /* and make terminal */ X crmode(); /* unfriendly again */ X if (docd) { X if (chdir(whereiam)) { X printf(nocd,whereiam) FLUSH; X sig_catcher(0); X } X } X#ifdef MAILCALL X mailcount = 0; /* force recheck */ X#endif X return 0; X} X X/* process & command */ X Xint Xswitcheroo() X{ X if (!finish_command(TRUE)) /* get rest of command */ X return -1; /* if rubbed out, try something else */ X if (!buf[1]) X pr_switches(); X#ifdef PUSHBACK X else if (buf[1] == '&') { X if (!buf[2]) { X page_init(); X show_macros(); X } X else { X char tmpbuf[LBUFLEN]; X register char *s; X X for (s=buf+2; isspace(*s); s++); X mac_line(s,tmpbuf,(sizeof tmpbuf)); X } X } X#endif X else { X bool docd = (instr(buf,"-d") != Nullch); X char whereami[512]; X X if (docd) X getwd(whereami); X sw_list(buf+1); X if (docd) { X cwd_check(); X if (chdir(whereami)) { /* -d does chdirs */ X printf(nocd,whereami) FLUSH; X sig_catcher(0); X } X } X } X return 0; X} X X/* process range commands */ X Xint Xnumnum() X{ X ART_NUM min, max; X char *cmdlst = Nullch; X register char *s, *c; X ART_NUM oldart = art; X char tmpbuf[LBUFLEN]; X bool justone = TRUE; /* assume only one article */ X X perform_cnt = 0; X if (!finish_command(TRUE)) /* get rest of command */ X return NN_INP; X if (lastart < 1) { X fputs("\nNo articles\n",stdout) FLUSH; X return NN_ASK; X } X#ifdef ARTSRCH X if (srchahead) X srchahead = -1; X#endif X for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++) X if (!isdigit(*s)) X justone = FALSE; X if (*s) { X cmdlst = savestr(s); X justone = FALSE; X } X else if (!justone) X cmdlst = savestr("m"); X *s++ = ','; X *s = '\0'; X safecpy(tmpbuf,buf,LBUFLEN); X for (s = tmpbuf; c = index(s,','); s = ++c) { X *c = '\0'; X if (*s == '.') X min = oldart; X else X min = atol(s); X#ifdef USETHREADS X if (minnum; X if (p_art->subject == -1) { X follow_thread('N'); X } X return NN_REREAD; X } X } X } X#endif X if (minlastart) { X max = lastart; X if (min > max) X min = max; X printf("(Last article is %ld)\n",(long)lastart) FLUSH; X pad(just_a_sec/3); X } X if (max < min) { X fputs("\nBad range\n",stdout) FLUSH; X if (cmdlst) X free(cmdlst); X return NN_ASK; X } X if (justone) { X art = min; X return NN_REREAD; X } X check_first(min); X for (art=min; art<=max; art++) { X if (perform(cmdlst,TRUE)) { X#ifdef VERBOSE X IF(verbose) X printf("\n(Interrupted at article %ld)\n",(long)art) X FLUSH; X ELSE X#endif X#ifdef TERSE X printf("\n(Intr at %ld)\n",(long)art) FLUSH; X#endif X if (cmdlst) X free(cmdlst); X return NN_ASK; X } X } X } X art = oldart; X if (cmdlst) X free(cmdlst); X return NN_NORM; X} X X#ifdef USETHREADS Xint Xuse_selected() X{ X PACKED_ARTICLE *root_limit; X register char *s, ch; X register int r; X char *cmdstr; X int ret = 1, orig_root_cnt = selected_root_cnt; X X if (!finish_command(TRUE)) /* get rest of command */ X return 0; X if (!(ch = buf[1])) X return -1; X cmdstr = savestr(buf+1); X X perform_cnt = 0; X page_line = 1; X X /* Multiple commands and commands that operate on individual articles X ** use the article loop. X */ X if (strlen(cmdstr) > 1 || index("ejmMsSwW|=", ch)) { X bool want_unread = (unread_selector || ch == 'm'); X X for (r = 0; r < total.root; r++) { X if (scan_all_roots X || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4)) X || (selected_roots[r] & (unread_selector+1))) { X p_art = p_articles + p_roots[r].articles; X root_limit = upper_limit( p_art, 0 ); X for (; p_art < root_limit; p_art++) { X art = p_art->num; X if (p_art->subject != -1 X && (!was_read(art) ^ want_unread)) { X if (perform(cmdstr, TRUE)) { X fputs("\nInterrupted\n", stdout) FLUSH; X goto break_out; X } X } X if (p_art == Nullart) X break; X }/* for all articles */ X }/* if selected */ X }/* for all threads */ X } /* other commands get the root loop */ X else if (ch == '+' || ch == '-' || ch == 'J' || ch == 'T' || ch == 't') { X for (r = 0; r < total.root; r++) { X if (scan_all_roots X || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4)) X || (selected_roots[r] & (unread_selector+1))) { X if (mode != 't' && ch != 't') { X printf("T%-5ld ", (long)p_roots[r].root_num); X } X p_art = p_articles + p_roots[r].articles; X art = p_art->num; X if (perform(cmdstr, FALSE)) { X fputs("\nInterrupted\n", stdout) FLUSH; X goto break_out; X } X#ifdef VERBOSE X IF(verbose) X if (mode != 't' && ch != 't' && ch != 'T') X putchar('\n') FLUSH; X#endif X } X } X } X else if (ch == 'E') { /* one command needs no looping at all */ X if (uu_out != Nullfp) { X uud_end(); X } else { X ret = 2; X } X } X else { X printf("???%s\n",cmdstr); X ret = -1; X } X break_out: X free(cmdstr); X return ret; X} X#endif X Xint Xperform(cmdlst,toplevel) Xregister char *cmdlst; Xint toplevel; X{ X register int ch; X X if (toplevel) { X printf("%-6ld ",art); X fflush(stdout); X } X perform_cnt++; X for (; ch = *cmdlst; cmdlst++) { X if (isspace(ch) || ch == ':') X continue; X if (ch == 'j') { X if (!was_read(art)) { X mark_as_read(); X#ifdef VERBOSE X IF(verbose) X fputs("\tJunked",stdout); X#endif X } X } X#ifdef USETHREADS X else if (ch == '+') { X register char mask = unread_selector+1; X find_article(art); X if (p_art && !(selected_roots[p_art->root] & mask)) { X register int r = p_art->root; X selected_roots[r] |= mask; X selected_root_cnt++; X if (mode == 't') { X selected_count += root_article_cnts[r]; X } else { X selected_count += count_one_root(r); X#ifdef VERBOSE X IF(verbose) X fputs("\tSelected",stdout); X#endif X } X } X } X else if (ch == '-') { X register char mask = unread_selector+1; X find_article(art); X if (p_art && selected_root_cnt X && (selected_roots[p_art->root] & mask)) { X register int r = p_art->root; X selected_roots[r] &= ~mask; X selected_root_cnt--; X if (mode == 't') { X selected_count -= root_article_cnts[r]; X } else { X selected_count -= count_one_root(r); X#ifdef VERBOSE X IF(verbose) X fputs("\tDeselected",stdout); X#endif X } X } X } X else if (ch == 't') { X find_article(art); X entire_tree(); X } X else if (ch == 'J' || ch == 'T') { X char tmpbuf[128]; X ART_NUM oldart = art; X X find_article(art); X if (p_art) { X if (ch == 'T') { X sprintf(tmpbuf,"T%ld\t# %s", X (long)p_roots[p_art->root].root_num, X subject_ptrs[p_art->subject]); X fputs(tmpbuf,stdout); X kf_append(tmpbuf); X } X follow_thread('J'); X art = oldart; X } X } X#endif X else if (ch == 'm') { X if (was_read(art)) { X unmark_as_read(); X#ifdef VERBOSE X IF(verbose) X fputs("\tMarked unread",stdout); X#endif X } X } X else if (ch == 'M') { X#ifdef DELAYMARK X delay_unmark(art); X#ifdef VERBOSE X IF(verbose) X fputs("\tWill return",stdout); X#endif X#else X notincl("M"); X return -1; X#endif X } X else if (ch == '=') { X printf("\t%s",fetchsubj(art,FALSE,FALSE)); X#ifdef VERBOSE X IF(verbose) X ; X ELSE X#endif X putchar('\n') FLUSH; /* ghad! */ X } X else if (ch == 'C') { X#ifdef ASYNC_PARSE X printf("\t%sancelled",(cancel_article() ? "Not c" : "C")); X#else X notincl("C"); X return -1; X#endif X } X else if (ch == '%') { X#ifdef ASYNC_PARSE X char tmpbuf[512]; X X if (one_command) X interp(tmpbuf, (sizeof tmpbuf), cmdlst); X else X cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst, ":") - 1; X perform_cnt--; X if (perform(tmpbuf,FALSE)) X return -1; X#else X notincl("%"); X return -1; X#endif X } X else if (index("!&sSwWe|",ch)) { X if (one_command) X strcpy(buf,cmdlst); X else X cmdlst = cpytill(buf,cmdlst,':') - 1; X /* we now have the command in buf */ X if (ch == '!') { X escapade(); X#ifdef VERBOSE X IF(verbose) X fputs("\tShell escaped",stdout); X#endif X } X else if (ch == '&') { X switcheroo(); X#ifdef VERBOSE X IF(verbose) X if (buf[1] && buf[1] != '&') X fputs("\tSwitched",stdout); X#endif X } X else { X putchar('\t'); X save_article(); X#ifdef VERBOSE X IF(verbose) X ; X ELSE X#endif X putchar('\n') FLUSH; X } X } X else { X printf("\t???%s\n",cmdlst); X return -1; X } X#ifdef VERBOSE X fflush(stdout); X#endif X if (one_command) X break; X } X if (toplevel) { X#ifdef VERBOSE X IF(verbose) X putchar('\n') FLUSH; X#endif X } X if( int_count ) { X int_count = 0; X return -1; X } X return 0; X} END_OF_FILE if test 10924 -ne `wc -c <'ngstuff.c'`; then echo shar: \"'ngstuff.c'\" unpacked with wrong size! fi # end of 'ngstuff.c' fi if test -f 'term.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term.h'\" else echo shar: Extracting \"'term.h'\" \(8474 characters\) sed "s/^X//" >'term.h' <<'END_OF_FILE' X/* $Header: term.h,v 4.3.3.2 91/01/16 03:38:39 davison Trn $ X * X * $Log: term.h,v $ X * Revision 4.3.3.2 91/01/16 03:38:39 davison X * Integrated rn patches 48-54. Added optional prototyping. X * X * Revision 4.3.3.1 90/06/20 22:40:34 davison X * Initial Trn Release X * X * Revision 4.3.2.6 90/12/10 01:32:08 sob X * Hopefully, the rn -e -L problem is now fixed. X * X * Revision 4.3.2.5 90/11/22 13:48:09 sob X * Backed out change in Patch 48. X * X * Revision 4.3.2.4 90/11/05 23:54:49 sob X * changed maybe_eol to test when erase_screen is FALSE intstead of TRUE. X * X * Revision 4.3.2.3 90/10/01 01:49:39 sob X * Changed ospeed from short to long. X * X * Revision 4.3.2.2 90/04/06 20:35:34 sob X * Added fixes for SCO Xenix sent by ronald@robobar.co.uk. X * X * Revision 4.3.2.1 89/11/28 01:54:03 sob X * Added better support for SIGWINCH. X * X * Revision 4.3.1.2 85/05/13 15:52:05 lwall X * Declared devtty on TERMIO system. X * X * Revision 4.3.1.1 85/05/10 11:41:24 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:51:36 lwall X * Baseline for release with 4.3bsd. X * X */ X X#ifdef PUSHBACK XEXT char circlebuf[PUSHSIZE]; XEXT int nextin INIT(0); XEXT int nextout INIT(0); X#ifdef PENDING X#ifdef FIONREAD XEXT long iocount INIT(0); X#ifndef lint X#define input_pending() (nextin!=nextout || (ioctl(0, FIONREAD, &iocount),(int)iocount)) X#else X#define input_pending() bizarre X#endif /* lint */ X#else /* FIONREAD */ X#ifdef RDCHK X#define input_pending() (rdchk(0) > 0) /* boolean only */ X#else /* RDCHK */ Xint circfill(); XEXT int devtty INIT(0); X#ifndef lint X#define input_pending() (nextin!=nextout || circfill()) X#else X#define input_pending() bizarre X#endif /* lint */ X#endif /* RDCHK */ X#endif /* FIONREAD */ X#else /* PENDING */ X#ifndef lint X#define input_pending() (nextin!=nextout) X#else X#define input_pending() bizarre X#endif /* lint */ X#endif /* PENDING */ X#else /* PUSHBACK */ X#ifdef PENDING X#ifdef FIONREAD /* must have FIONREAD or O_NDELAY for input_pending() */ X#define read_tty(addr,size) read(0,addr,size) X#ifndef lint X#define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount) X#else X#define input_pending() bizarre X#endif /* lint */ XEXT long iocount INIT(0); X X#else /* FIONREAD */ X X#ifdef RDCHK X#define input_pending() (rdchk(0) > 0) /* boolean only */ X#else /* RDCHK */ X XEXT int devtty INIT(0); XEXT bool is_input INIT(FALSE); XEXT char pending_ch INIT(0); X#ifndef lint X#define input_pending() (is_input || (is_input=read(devtty,&pending_ch,1))) X#else X#define input_pending() bizarre X#endif /* lint */ X#endif /* RDCHK */ X#endif /* FIONREAD */ X#else /* PENDING */ X#define read_tty(addr,size) read(0,addr,size) X#define input_pending() (FALSE) X#endif /* PENDING */ X#endif /* PUSHBACK */ X X/* stuff wanted by terminal mode diddling routines */ X X#ifdef TERMIO XEXT struct termio _tty, _oldtty; X#else XEXT struct sgttyb _tty; XEXT int _res_flg INIT(0); X#endif X XEXT int _tty_ch INIT(2); XEXT bool bizarre INIT(FALSE); /* do we need to restore terminal? */ X X/* terminal mode diddling routines */ X X#ifdef TERMIO X X#define crmode() ((bizarre=1),_tty.c_lflag &=~ICANON,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty)) X#define nocrmode() ((bizarre=1),_tty.c_lflag |= ICANON,_tty.c_cc[VEOF] = CEOF,stty(_tty_ch,&_tty)) X#define echo() ((bizarre=1),_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETA, &_tty)) X#define noecho() ((bizarre=1),_tty.c_lflag &=~ECHO, ioctl(_tty_ch, TCSETA, &_tty)) X#define nl() ((bizarre=1),_tty.c_iflag |= ICRNL,_tty.c_oflag |= ONLCR,ioctl(_tty_ch, TCSETAW, &_tty)) X#define nonl() ((bizarre=1),_tty.c_iflag &=~ICRNL,_tty.c_oflag &=~ONLCR,ioctl(_tty_ch, TCSETAW, &_tty)) X#define savetty() (ioctl(_tty_ch, TCGETA, &_oldtty),ioctl(_tty_ch, TCGETA, &_tty)) X#define resetty() ((bizarre=0),ioctl(_tty_ch, TCSETAF, &_oldtty)) X#define unflush_output() X X#else X X#define raw() ((bizarre=1),_tty.sg_flags|=RAW, stty(_tty_ch,&_tty)) X#define noraw() ((bizarre=1),_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty)) X#define crmode() ((bizarre=1),_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty)) X#define nocrmode() ((bizarre=1),_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty)) X#define echo() ((bizarre=1),_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty)) X#define noecho() ((bizarre=1),_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty)) X#define nl() ((bizarre=1),_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty)) X#define nonl() ((bizarre=1),_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty)) X#define savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags) X#define resetty() ((bizarre=0),_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty)) X#ifdef LFLUSHO X#ifndef lint XEXT int lflusho INIT(LFLUSHO); X#else XEXT long lflusho INIT(LFLUSHO); X#endif /* lint */ X#define unflush_output() (ioctl(_tty_ch,TIOCLBIC,&lflusho)) X#else X#define unflush_output() X#endif /* LFLUSHO */ X#endif /* TERMIO */ X X#ifdef TIOCSTI X#ifdef lint X#define forceme(c) ioctl(_tty_ch,TIOCSTI,Null(long*)) /* ghad! */ X#else X#define forceme(c) ioctl(_tty_ch,TIOCSTI,c) /* pass character in " " */ X#endif /* lint */ X#else X#define forceme(c) X#endif X X/* termcap stuff */ X X/* X * NOTE: if you don't have termlib you'll either have to define these strings X * and the tputs routine, or you'll have to redefine the macros below X */ X X#ifdef HAVETERMLIB XEXT char *BC INIT(Nullch); /* backspace character */ XEXT char *UP INIT(Nullch); /* move cursor up one line */ XEXT char *CR INIT(Nullch); /* get to left margin, somehow */ XEXT char *VB INIT(Nullch); /* visible bell */ XEXT char *CL INIT(Nullch); /* home and clear screen */ XEXT char *CE INIT(Nullch); /* clear to end of line */ X#if defined(CLEAREOL) || defined(USETHREADS) XEXT char *CM INIT(Nullch); /* cursor motion */ XEXT char *HO INIT(Nullch); /* home cursor */ X#endif X#ifdef CLEAREOL XEXT char *CD INIT(Nullch); /* clear to end of display */ X#endif /* CLEAREOL */ XEXT char *SO INIT(Nullch); /* begin standout mode */ XEXT char *SE INIT(Nullch); /* end standout mode */ XEXT int SG INIT(0); /* blanks left by SO and SE */ XEXT char *US INIT(Nullch); /* start underline mode */ XEXT char *UE INIT(Nullch); /* end underline mode */ XEXT char *UC INIT(Nullch); /* underline a character, if that's how it's done */ XEXT int UG INIT(0); /* blanks left by US and UE */ XEXT bool AM INIT(FALSE); /* does terminal have automatic margins? */ XEXT bool XN INIT(FALSE); /* does it eat 1st newline after automatic wrap? */ XEXT char PC INIT(0); /* pad character for use by tputs() */ XEXT long ospeed INIT(0); /* terminal output speed, for use by tputs() */ XEXT int LINES INIT(0), COLS INIT(0); /* size of screen */ XEXT int just_a_sec INIT(960); /* 1 sec at current baud rate */ X /* (number of nulls) */ X X/* define a few handy macros */ X X#define backspace() tputs(BC,0,putchr) FLUSH X#define clear() tputs(CL,LINES,putchr) FLUSH X#define erase_eol() tputs(CE,1,putchr) FLUSH X#ifdef CLEAREOL X#define clear_rest() tputs(CD,LINES,putchr) FLUSH X#define maybe_eol() if(erase_screen&&can_home_clear)tputs(CE,1,putchr) FLUSH X#endif /* CLEAREOL */ X#define underline() tputs(US,1,putchr) FLUSH X#define un_underline() tputs(UE,1,putchr) FLUSH X#define underchar() tputs(UC,0,putchr) FLUSH X#define standout() tputs(SO,1,putchr) FLUSH X#define un_standout() tputs(SE,1,putchr) FLUSH X#define up_line() tputs(UP,1,putchr) FLUSH X#define carriage_return() tputs(CR,1,putchr) FLUSH X#define dingaling() tputs(VB,1,putchr) FLUSH X#else X ???????? /* up to you */ X#endif X XEXT int page_line INIT(1); /* line number for paging in print_line (origin 1) */ X Xvoid term_init ANSI((void)); Xvoid term_set ANSI((char *)); X#ifdef PUSHBACK Xvoid pushchar ANSI((char)); Xvoid mac_init ANSI((char *)); Xvoid mac_line ANSI((char *,char *,int)); Xvoid show_macros ANSI((void)); X#endif Xchar putchr ANSI((char)); /* routine for tputs to call */ Xbool finish_command ANSI((int)); Xvoid eat_typeahead ANSI((void)); Xvoid settle_down ANSI((void)); X#ifndef read_tty X int read_tty ANSI((char *,int)); X#endif Xvoid underprint ANSI((char *)); X#ifdef NOFIREWORKS X void no_sofire ANSI((void)); X void no_ulfire ANSI((void)); X#endif Xvoid getcmd ANSI((char *)); Xint get_anything ANSI((void)); Xvoid in_char ANSI((char *,char)); Xint print_lines ANSI((char *,int)); Xvoid page_init ANSI((void)); Xvoid pad ANSI((int)); Xvoid printcmd ANSI((void)); Xvoid rubout ANSI((void)); Xvoid reprint ANSI((void)); X#if defined(CLEAREOL) || defined(USETHREADS) Xvoid home_cursor ANSI((void)); X#endif X#ifdef USETHREADS Xvoid goto_line ANSI((int,int)); X#endif X#ifdef SIGWINCH Xint winch_catcher ANSI((void)); X#endif /* SIGWINCH */ END_OF_FILE if test 8474 -ne `wc -c <'term.h'`; then echo shar: \"'term.h'\" unpacked with wrong size! fi # end of 'term.h' fi if test -f 'util.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util.c'\" else echo shar: Extracting \"'util.c'\" \(10588 characters\) sed "s/^X//" >'util.c' <<'END_OF_FILE' X/* $Header: util.c,v 4.3.3.3 91/01/16 03:41:50 davison Trn $ X * X * $Log: util.c,v $ X * Revision 4.3.3.3 91/01/16 03:41:50 davison X * Integrated rn patches 48-54. X * X * Revision 4.3.3.2 90/08/20 16:51:44 davison X * Fixed getcwd call to not overflow any buffers. X * X * Revision 4.3.3.1 90/07/21 20:34:10 davison X * Initial Trn Release X * X * Revision 4.3.2.8 90/11/22 13:54:06 sob X * Made changes to keep more preprocessors happy. X * X * Revision 4.3.2.7 90/10/01 01:52:18 sob X * Altered the preprocessor defines on GETWD/GETCWD per suggestion by X * rsm@math.arizona.edu. X * X * Revision 4.3.2.6 90/04/23 00:24:42 sob X * A bit of clean up. X * X * Revision 4.3.2.5 90/03/17 21:34:21 sob X * Reworked VOIDSIG into SIGRET. X * X * Revision 4.3.2.4 89/12/14 23:58:54 sob X * Fixed small bug reported by fletcher@cs.utexas.edu in getwd(). X * X * Revision 4.3.2.3 89/11/08 04:47:11 sob X * Added VOIDSIG handling for SunOS 4.X X * X * Revision 4.3.2.2 89/11/07 23:19:35 sob X * Bug fixes for SIGSTP problems X * X * Revision 4.3.2.1 89/11/06 01:03:21 sob X * Added RRN support from NNTP 1.5 X * X * Revision 4.3.1.2 85/05/15 14:44:27 lwall X * Last arg of execl changed from 0 to Nullch [(char*)0]. X * X * Revision 4.3.1.1 85/05/10 11:41:30 lwall X * Branch for patches. X * X * Revision 4.3 85/05/01 11:51:44 lwall X * Baseline for release with 4.3bsd. X * X */ X X#include "EXTERN.h" X#include "common.h" X#include "final.h" X#include "ndir.h" X#include "INTERN.h" X#include "util.h" X Xvoid Xutil_init() X{ X ; X} X X/* fork and exec a shell command */ X Xint Xdoshell(shl,s) Xchar *s, *shl; X{ X int status, pid, w; X char *shell; X X#ifdef SIGTSTP X sigset(SIGTSTP,SIG_DFL); X sigset(SIGTTOU,SIG_DFL); X sigset(SIGTTIN,SIG_DFL); X#endif X if (shl != Nullch) X shell = shl; X else if ((shell = getenv("SHELL")) == Nullch || !*shell) X shell = PREFSHELL; X if ((pid = vfork()) == 0) { X#ifdef SERVER X int i; X X /* This is necessary to keep bourne shell from puking */ X X for (i = 3; i < 10; ++i) X close(i); X#endif /* SERVER */ X X if (*s) X execl(shell, shell, "-c", s, Nullch); X else X execl(shell, shell, Nullch, Nullch, Nullch); X _exit(127); X } X signal(SIGINT, SIG_IGN); X#ifdef SIGQUIT X signal(SIGQUIT, SIG_IGN); X#endif X waiting = TRUE; X while ((w = wait(&status)) != pid && w != -1) X ; X if (w == -1) X status = -1; X waiting = FALSE; X sigset(SIGINT, int_catcher); /* always catch interrupts */ X#ifdef SIGQUIT X signal(SIGQUIT, SIG_DFL); X#endif X#ifdef SIGTSTP X sigset(SIGTSTP,stop_catcher); X sigset(SIGTTOU,stop_catcher); X sigset(SIGTTIN,stop_catcher); X#endif X return status; X} X Xstatic char nomem[] = "rn: out of memory!\n"; X X/* paranoid version of malloc */ X Xchar * Xsafemalloc(size) XMEM_SIZE size; X{ X char *ptr; X char *malloc(); X X ptr = malloc(size ? size : (MEM_SIZE)1); X if (ptr != Nullch) X return ptr; X else { X fputs(nomem,stdout) FLUSH; X sig_catcher(0); X } X /*NOTREACHED*/ X} X X/* paranoid version of realloc */ X Xchar * Xsaferealloc(where,size) Xchar *where; XMEM_SIZE size; X{ X char *ptr; X char *realloc(); X X ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */ X if (ptr != Nullch) X return ptr; X else { X fputs(nomem,stdout) FLUSH; X sig_catcher(0); X } X /*NOTREACHED*/ X} X X/* safe version of string copy */ X Xchar * Xsafecpy(to,from,len) Xchar *to; Xregister char *from; Xregister int len; X{ X register char *dest = to; X X if (from != Nullch) X for (len--; len && (*dest++ = *from++); len--) ; X *dest = '\0'; X return to; X} X X/* safe version of string concatenate, with \n deletion and space padding */ X Xchar * Xsafecat(to,from,len) Xchar *to; Xregister char *from; Xregister int len; X{ X register char *dest = to; X X len--; /* leave room for null */ X if (*dest) { X while (len && *dest++) len--; X if (len) { X len--; X *(dest-1) = ' '; X } X } X if (from != Nullch) X while (len && (*dest++ = *from++)) len--; X if (len) X dest--; X if (*(dest-1) == '\n') X dest--; X *dest = '\0'; X return to; X} X X/* copy a string up to some (non-backslashed) delimiter, if any */ X Xchar * Xcpytill(to,from,delim) Xregister char *to, *from; Xregister int delim; X{ X for (; *from; from++,to++) { X if (*from == '\\' && from[1] == delim) X from++; X else if (*from == delim) X break; X *to = *from; X } X *to = '\0'; X return from; X} X X/* return ptr to little string in big string, NULL if not found */ X Xchar * Xinstr(big, little) Xchar *big, *little; X X{ X register char *t, *s, *x; X X for (t = big; *t; t++) { X for (x=t,s=little; *s; x++,s++) { X if (!*x) X return Nullch; X if (*s != *x) X break; X } X if (!*s) X return t; X } X return Nullch; X} X X/* effective access */ X X#ifdef SETUIDGID Xint Xeaccess(filename, mod) Xchar *filename; Xint mod; X{ X int protection, euid; X X mod &= 7; /* remove extraneous garbage */ X if (stat(filename, &filestat) < 0) X return -1; X euid = geteuid(); X if (euid == ROOTID) X return 0; X protection = 7 & (filestat.st_mode >> X (filestat.st_uid == euid ? 6 : X (filestat.st_gid == getegid() ? 3 : 0) X )); X if ((mod & protection) == mod) X return 0; X errno = EACCES; X return -1; X} X#endif X X/* X * Get working directory X */ X#ifndef GETWD X#ifdef GETCWD Xchar * Xgetwd(np) Xchar *np; X{ X char * name; X extern char * getcwd(); X name = getcwd(np,512); X return(name); X} X#else Xchar * Xgetwd(np) /* shorter but slower */ Xchar *np; X{ X FILE *popen(); X FILE *pipefp = popen("/bin/pwd","r"); X X if (pipefp == Nullfp) { X printf("Can't run /bin/pwd\n") FLUSH; X finalize(1); X } X fgets(np,512,pipefp); X np[strlen(np)-1] = '\0'; /* wipe out newline */ X pclose(pipefp); X return np; X} X#endif X#endif X/* just like fgets but will make bigger buffer as necessary */ X Xchar * Xget_a_line(original_buffer,buffer_length,fp) Xchar *original_buffer; Xregister int buffer_length; XFILE *fp; X{ X register int bufix = 0; X register int nextch; X register char *some_buffer_or_other = original_buffer; X X do { X if (bufix >= buffer_length) { X buffer_length *= 2; X if (some_buffer_or_other == original_buffer) { X /* currently static? */ X some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1); X strncpy(some_buffer_or_other,original_buffer,buffer_length/2); X /* so we must copy it */ X } X else { /* just grow in place, if possible */ X some_buffer_or_other = saferealloc(some_buffer_or_other, X (MEM_SIZE)buffer_length+1); X } X } X if ((nextch = getc(fp)) == EOF) X return Nullch; X some_buffer_or_other[bufix++] = (char) nextch; X } while (nextch && nextch != '\n'); X some_buffer_or_other[bufix] = '\0'; X len_last_line_got = bufix; X return some_buffer_or_other; X} X X/* copy a string to a safe spot */ X Xchar * Xsavestr(str) Xchar *str; X{ X register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1)); X X strcpy(newaddr,str); X return newaddr; X} X Xint Xmakedir(dirname,nametype) Xregister char *dirname; Xint nametype; X{ X#ifdef MAKEDIR X register char *end; X register char *s; X char tmpbuf[1024]; X register char *tbptr = tmpbuf+5; X X for (end = dirname; *end; end++) ; /* find the end */ X if (nametype == MD_FILE) { /* not to create last component? */ X for (--end; end != dirname && *end != '/'; --end) ; X if (*end != '/') X return 0; /* nothing to make */ X *end = '\0'; /* isolate file name */ X } X strcpy(tmpbuf,"mkdir"); X X s = end; X for (;;) { X if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) { X /* does this much exist as a dir? */ X *s = '/'; /* mark this as existing */ X break; X } X s = rindex(dirname,'/'); /* shorten name */ X if (!s) /* relative path! */ X break; /* hope they know what they are doing */ X *s = '\0'; /* mark as not existing */ X } X X for (s=dirname; s <= end; s++) { /* this is grody but efficient */ X if (!*s) { /* something to make? */ X sprintf(tbptr," %s",dirname); X tbptr += strlen(tbptr); /* make it, sort of */ X *s = '/'; /* mark it made */ X } X } X if (nametype == MD_DIR) /* don't need final slash unless */ X *end = '\0'; /* a filename follows the dir name */ X X return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf)); X /* exercise our faith */ X#else X sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype); X return doshell(sh,cmd_buf); X#endif X} X X#ifdef SETENV Xstatic bool firstsetenv = TRUE; Xextern char **environ; X Xvoid Xsetenv(nam,val) Xchar *nam, *val; X{ X register int i=envix(nam); /* where does it go? */ X X if (!environ[i]) { /* does not exist yet */ X if (firstsetenv) { /* need we copy environment? */ X int j; X#ifndef lint X char **tmpenv = (char**) /* point our wand at memory */ X safemalloc((MEM_SIZE) (i+2) * sizeof(char*)); X#else X char **tmpenv = Null(char **); X#endif /* lint */ X X firstsetenv = FALSE; X for (j=0; j *curlen) { /* need more room? */ X if (*curlen) X *strptr = saferealloc(*strptr,(MEM_SIZE)newlen); X else X *strptr = safemalloc((MEM_SIZE)newlen); X *curlen = newlen; X } X} X Xvoid Xsetdef(buffer,dflt) Xchar *buffer,*dflt; X{ X#ifdef STRICTCR X if (*buffer == ' ') X#else X if (*buffer == ' ' || *buffer == '\n') X#endif X { X if (*dflt == '^' && isupper(dflt[1])) X *buffer = Ctl(dflt[1]); X else X *buffer = *dflt; X } X} END_OF_FILE if test 10588 -ne `wc -c <'util.c'`; then echo shar: \"'util.c'\" unpacked with wrong size! fi # end of 'util.c' fi echo shar: End of archive 11 \(of 14\). cp /dev/null ark11isdone 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