home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1460 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  61.7 KB

  1. From: sob@lib.tmc.edu (Stan Barber)
  2. Newsgroups: alt.sources
  3. Subject: rrn/rn combo kit part 3 of 9
  4. Message-ID: <429@lib.tmc.edu>
  5. Date: 14 Jun 90 03:27:08 GMT
  6.  
  7. #! /bin/sh
  8.  
  9. # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9 
  10. # through sh.  When all 9 kits have been run, read README.
  11.  
  12. echo "This is rn kit 3 (of 9).  If kit 3 is complete, the line"
  13. echo '"'"End of kit 3 (of 9)"'" will echo at the end.'
  14. echo ""
  15. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  16. echo Extracting common.h
  17. cat >common.h <<'!STUFFY!FUNK!'
  18. /* $Header: common.h,v 4.3.2.13 90/05/08 22:05:37 sob Exp $
  19.  * 
  20.  * $Log:    common.h,v $
  21.  * Revision 4.3.2.13  90/05/08  22:05:37  sob
  22.  * Added quick startup (-q) flag.
  23.  * 
  24.  * Revision 4.3.2.12  90/04/23  00:32:04  sob
  25.  * More cleanup.
  26.  * 
  27.  * Revision 4.3.2.11  90/04/14  19:37:07  sob
  28.  * Added better support for the NeXT.
  29.  * 
  30.  * Revision 4.3.2.10  90/04/06  20:54:12  sob
  31.  * Corrected forward definition of fseek()
  32.  * 
  33.  * Revision 4.3.2.9  90/03/17  21:19:04  sob
  34.  * Removed the incorrect forward definition of sprintf().
  35.  * 
  36.  * Revision 4.3.2.8  89/12/20  20:40:03  sob
  37.  * Changed ACT_POS from short to long per suggestion from eps@cd.SFSU.EDU.
  38.  * 
  39.  * Revision 4.3.2.7  89/12/08  22:43:12  sob
  40.  * Corrected typo pointed out by weening@gang-of-four.stanford.edu
  41.  * 
  42.  * Revision 4.3.2.6  89/11/28  01:57:31  sob
  43.  * Added initlines_specified variable for use with SIGWINCH support.
  44.  * 
  45.  * Revision 4.3.2.5  89/11/28  00:30:56  sob
  46.  * Reversed the CANCELHEADER definitions.
  47.  * 
  48.  * Revision 4.3.2.4  89/11/27  01:29:23  sob
  49.  * Altered NNTP code per ideas suggested by Bela Lubkin
  50.  * <filbo@gorn.santa-cruz.ca.us>
  51.  * 
  52.  * Revision 4.3.2.3  89/11/26  19:32:06  sob
  53.  * Increased the size of MAXRCLINE from 1000 to 1500
  54.  * Increated HASHSIZ from 1103 to 1693
  55.  * 
  56.  * Revision 4.3.2.2  89/11/07  23:18:49  sob
  57.  * Repaired NEWSHEADER and CANCEL to work correctly with NNTP and INTERNET.
  58.  * 
  59.  * Revision 4.3.2.1  89/11/06  00:12:33  sob
  60.  * Added RRN support from NNTP 1.5
  61.  * 
  62.  * Revision 4.3.1.4  86/10/31  15:46:09  lwall
  63.  * Expanded maximum number of .newsrc lines for net reorganization.
  64.  * 
  65.  * Revision 4.3.1.3  85/05/23  17:19:32  lwall
  66.  * Now allows 'r' and 'f' on null articles.
  67.  * 
  68.  * Revision 4.3.1.2  85/05/13  09:30:39  lwall
  69.  * Added CUSTOMLINES option.
  70.  * 
  71.  * Revision 4.3.1.1  85/05/10  11:32:04  lwall
  72.  * Branch for patches.
  73.  * 
  74.  * Revision 4.3  85/05/01  11:37:11  lwall
  75.  * Baseline for release with 4.3bsd.
  76.  * 
  77.  */
  78.  
  79. #include "config.h"    /* generated by installation script */
  80. #ifdef WHOAMI
  81. #    include <whoami.h>
  82. #endif
  83.  
  84. #include <stdio.h>
  85. #include <sys/types.h>
  86. #include <sys/stat.h>
  87. #include <ctype.h>
  88.  
  89. #ifndef isalnum
  90. #   define isalnum(c) (isalpha(c) || isdigit(c))
  91. #endif
  92.  
  93. #include <errno.h>
  94. #include <signal.h>
  95. #ifdef IOCTL
  96. #include <sys/ioctl.h>
  97. #endif IOCTL
  98.  
  99. #ifdef FCNTL
  100. #   include <fcntl.h>
  101. #endif
  102.  
  103. #ifdef TERMIO
  104. #   include <termio.h>
  105. #else
  106. #   include <sgtty.h>
  107. #endif
  108.  
  109. #ifdef GETPWENT
  110. #   include <pwd.h>
  111. #endif
  112.  
  113. #define BITSPERBYTE 8
  114. #define LBUFLEN 512    /* line buffer length */
  115.             /* (don't worry, .newsrc lines can exceed this) */
  116. #ifdef pdp11
  117. #   define CBUFLEN 256    /* command buffer length */
  118. #   define PUSHSIZE 128
  119. #else
  120. #   define CBUFLEN 512    /* command buffer length */
  121. #   define PUSHSIZE 256
  122. #endif
  123. #ifdef pdp11
  124. #   define MAXFILENAME 128
  125. #else
  126. #   define MAXFILENAME 512
  127. #endif
  128. #define LONGKEY 15    /* longest keyword: currently "posting-version" */
  129. #define FINISHCMD 0177
  130.  
  131. /* some handy defs */
  132.  
  133. #define bool char
  134. #define TRUE (1)
  135. #define FALSE (0)
  136. #define Null(t) ((t)0)
  137. #define Nullch Null(char *)
  138. #define Nullfp Null(FILE *)
  139.  
  140. #define Ctl(ch) (ch & 037)
  141.  
  142. #define strNE(s1,s2) (strcmp(s1,s2))
  143. #define strEQ(s1,s2) (!strcmp(s1,s2))
  144. #define strnNE(s1,s2,l) (strncmp(s1,s2,l))
  145. #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
  146.  
  147. /* Things we can figure out ourselves */
  148.  
  149. #ifdef SIGTSTP
  150. #   define BERKELEY     /* include job control signals? */
  151. #endif
  152.  
  153. #ifdef FIONREAD
  154. #   define PENDING
  155. #else
  156. #   ifdef O_NDELAY
  157. #    define PENDING
  158. #   endif
  159. #endif
  160.  
  161. #ifdef EUNICE
  162. #   define LINKART        /* add 1 level of possible indirection */
  163. #   define UNLINK(victim) while (!unlink(victim))
  164. #else
  165. #   define UNLINK(victim) unlink(victim)
  166. #endif
  167.  
  168. /* Valid substitutions for strings marked with % comment are:
  169.  *    %a    Current article number
  170.  *    %A    Full name of current article (%P/%c/%a)
  171.  *        (if LINKART defined, is the name of the real article)
  172.  *    %b    Destination of a save command, a mailbox or command
  173.  *    %B    The byte offset to the beginning of the article for saves
  174.  *        with or without the header
  175.  *    %c    Current newsgroup, directory form
  176.  *    %C    Current newsgroup, dot form
  177.  *    %d    %P/%c
  178.  *    %D    Old Distribution: line
  179.  *    %f    Old From: line or Reply-To: line
  180.  *    %F    Newsgroups to followup to from Newsgroups: and Followup-To:
  181.  *    %h    Name of header file to pass to mail or news poster
  182.  *    %H    Host name (yours)
  183.  *    %i    Old Message-I.D.: line, with <>
  184.  *    %I    Inclusion indicator
  185.  *    %l    News administrator login name
  186.  *    %L    Login name (yours)
  187.  *    %M    Number of articles markd with M
  188.  *    %n    Newsgroups from source article
  189.  *    %N    Full name (yours)
  190.  *    %o    Organization (yours)
  191.  *    %O    Original working directory (where you ran rn from)
  192.  *    %p    Your private news directory (-d switch)
  193.  *    %P    Public news spool directory (SPOOLDIR)
  194.  *    %r    Last reference (parent article id)
  195.  *    %R    New references list
  196.  *    %s    Subject, with all Re's and (nf)'s stripped off
  197.  *    %S    Subject, with one Re stripped off
  198.  *    %t    New To: line derived from From: and Reply-To (Internet always)
  199.  *    %T    New To: line derived from Path:
  200.  *    %u    Number of unread articles
  201.  *    %U    Number of unread articles disregarding current article
  202.  *    %x    News library directory, usually /usr/lib/news
  203.  *    %X    Rn library directory, usually %x/rn
  204.  *    %z    Size of current article in bytes.
  205.  *    %~    Home directory
  206.  *    %.    Directory containing . files
  207.  *    %$    current process number
  208.  *    %{name} Environment variable "name".  %{name-default} form allowed.
  209.  *    %[name]    Header line beginning with "Name: ", without "Name: " 
  210.  *    %"prompt"
  211.  *        Print prompt and insert what is typed.
  212.  *    %`command`
  213.  *        Insert output of command.
  214.  *    %(test_text=pattern?if_text:else_text)
  215.  *        Substitute if_text if test_text matches pattern, otherwise
  216.  *        substitute else_text.  Use != for negated match.
  217.  *        % substitutions are done on test_text, if_text, and else_text.
  218.  *        (Note: %() only works if CONDSUB defined.)
  219.  *    %digit    Substitute the text matched by the nth bracket in the last
  220.  *        pattern that had brackets.  %0 matches the last bracket
  221.  *        matched, in case you had alternatives.
  222.  *
  223.  *    Put ^ in the middle to capitalize the first letter: %^C = Net.jokes
  224.  *    Put _ in the middle to capitalize last component: %_c = net/Jokes
  225.  *
  226.  *    ~ interpretation in filename expansion happens after % expansion, so
  227.  *    you could put ~%{NEWSLOGNAME-news} and it will expand correctly.
  228.  */
  229.  
  230. /* *** System Dependent Stuff *** */
  231.  
  232. /* NOTE: many of these are defined in the config.h file */
  233.  
  234. /* name of organization */
  235. #ifndef ORGNAME
  236. #   define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota"
  237. #endif
  238.  
  239. #ifndef MBOXCHAR
  240. #   define MBOXCHAR 'F'    /* how to recognize a mailbox by 1st char */
  241. #endif
  242.  
  243. #ifndef ROOTID
  244. #   define ROOTID 0        /* uid of superuser */
  245. #endif
  246.  
  247. #ifdef NORMSIG
  248. #   define sigset signal
  249. #   define sigignore(sig) signal(sig,SIG_IGN)
  250. #endif
  251.  
  252. #ifndef LOGDIRFIELD
  253. #   define LOGDIRFIELD 6        /* Which field (origin 1) is the */
  254.                     /* login directory in /etc/passwd? */
  255.                     /* (If it is not kept in passwd, */
  256.                     /* but getpwnam() returns it, */
  257.                     /* define the symbol GETPWENT) */
  258. #endif
  259. #ifndef GCOSFIELD
  260. #   define GCOSFIELD 5
  261. #endif
  262.  
  263. #ifndef NEGCHAR
  264. #   define NEGCHAR '!'
  265. #endif
  266.  
  267. /* Space conservation section */
  268.  
  269. /* To save D space, cut down size of MAXRCLINE, NGMAX, VARYSIZE. */
  270. #define MAXRCLINE 1500    /* number of lines allowed in .newsrc */
  271.             /* several parallel arrays affected. */
  272.             /* (You can have more lines in the active file, */
  273.             /* just not in the .newsrc) */
  274. #define HASHSIZ 1693    /* should be prime, and at least MAXRCLINE + 10% */
  275. #define NGMAX 100    /* number of newsgroups allowed on command line */
  276.             /* undefine ONLY symbol to disable "only" feature */
  277. #define VARYSIZE 256    /* this makes a block 1024 bytes long in DECville */
  278.             /* (used by virtual array routines) */
  279.  
  280. /* Undefine any of the following features to save both I and D space */
  281. /* In general, earlier ones are easier to get along without */
  282. /* Pdp11's without split I and D may have to undefine them all */
  283. #define DEBUGGING    /* include debugging code */
  284. #define CUSTOMLINES    /* include code for HIDELINE and PAGESTOP */
  285. #define PUSHBACK    /* macros and keymaps using pushback buffer */
  286. #define SPEEDOVERMEM    /* use more memory to run faster */
  287. #define WORDERASE    /* enable ^W to erase a word */
  288. #define MAILCALL    /* check periodically for mail */
  289. #define CLEAREOL    /* use clear to end-of-line instead of clear screen */
  290. #define NOFIREWORKS    /* keep whole screen from flashing on certain */
  291.             /* terminals such as older Televideos */
  292. #define VERIFY        /* echo the command they just typed */
  293. #define HASHNG        /* hash newsgroup lines for fast lookup-- */
  294.             /* linear search used if not defined */
  295. #define CONDSUB        /* allow %(cond?text:text) */
  296. #define BACKTICK    /* allow %`command` */
  297. #define PROMPTTTY    /* allow %"prompt" */
  298. #define ULSMARTS    /* catch _^H in text and do underlining */
  299. #define TERMMOD        /* allow terminal type modifier on switches */
  300. #define BAUDMOD        /* allow baudrate modifier on switches */
  301. #define GETLOGIN    /* use getlogin() routine as backup to environment */
  302.             /* variables USER or LOGNAME */
  303. #define ORGFILE        /* if organization begins with /, look up in file */
  304. #define TILDENAME    /* allow ~logname expansion */
  305. #define SETENV        /* allow command line environment variable setting */
  306. #define GETWD        /* use our getwd() instead of piped in pwd */
  307. #define MAKEDIR        /* use our makedir() instead of shell script */
  308. #define MEMHELP        /* keep help messages in memory */
  309. #define VERBOSE        /* compile in more informative messages */
  310. #define TERSE        /* compile in shorter messages */
  311.             /* (Note: both VERBOSE and TERSE can be defined; -t
  312.              * sets terse mode.  One or the other MUST be defined.
  313.              */
  314. #ifndef pdp11
  315. #   define CACHESUBJ    /* cache subject lines in memory */
  316.             /* without this ^N still works but runs really slow */
  317.             /* but you save lots and lots of D space */
  318. #   define CACHEFIRST    /* keep absolute first article numbers in memory */
  319.             /* cost: about 2k */
  320. #endif
  321. #define ROTATION    /* enable x, X and ^X commands to work */
  322. #define DELBOGUS    /* ask if bogus newsgroups should be deleted */
  323. #define RELOCATE    /* allow newsgroup rearranging */
  324. #define ESCSUBS        /* escape substitutions in multi-character commands */
  325. #define DELAYMARK    /* allow articles to be temporarily marked as read */
  326.             /* until exit from current newsgroup or Y command */
  327. #define MCHASE        /* unmark xrefed articles on m or M */
  328. #define MUNGHEADER    /* allow alternate header formatting via */
  329.             /* environment variable ALTHEADER (not impl) */
  330. #define ASYNC_PARSE    /* allow parsing headers asyncronously to reading */
  331.             /* used by MCHASE and MUNGHEADER */
  332. #define FINDNEWNG    /* check for new newsgroups on startup */
  333. #define FASTNEW        /* do optimizations on FINDNEWNG for faster startup */
  334.             /* (this optimization can make occasional mistakes */
  335.             /* if a group is removed and another group of the */
  336.             /* same length is added, and if no softpointers are */
  337.             /* affected by said change.) */
  338. #define INNERSEARCH    /* search command 'g' with article */
  339. #define CATCHUP        /* catchup command at newsgroup level */
  340. #define NGSEARCH    /* newsgroup pattern matching */
  341. #define ONLY        /* newsgroup restrictions by pattern */
  342. #define KILLFILES    /* automatic article killer files */
  343. #define ARTSEARCH    /* pattern searches among articles */
  344.             /* /, ?, ^N, ^P, k, K */
  345.  
  346. /* some dependencies among options */
  347.  
  348. #ifndef ARTSEARCH
  349. #   undef KILLFILES
  350. #   undef INNERSEARCH
  351. #   undef CACHESUBJ
  352. #endif
  353.  
  354. #ifndef DELAYMARK
  355. #   ifndef MCHASE
  356. #    ifndef MUNGHEADER
  357. #        undef ASYNC_PARSE
  358. #    endif
  359. #   endif
  360. #endif
  361.  
  362. #ifndef SETUIDGID
  363. #   define eaccess access
  364. #endif
  365.  
  366. #ifdef ONLY                /* idiot lint doesn't grok #if */
  367. #   define NGSORONLY
  368. #else
  369. #   ifdef NGSEARCH
  370. #    define NGSORONLY
  371. #   endif
  372. #endif
  373.  
  374. #ifdef VERBOSE
  375. #   ifdef TERSE
  376. #    define IF(c) if (c)
  377. #    define ELSE else
  378. #   else !TERSE
  379. #    define IF(c)
  380. #    define ELSE
  381. #   endif
  382. #else !VERBOSE
  383. #   ifndef TERSE
  384. #    define TERSE
  385. #   endif
  386. #   define IF(c) "IF" outside of VERBOSE???
  387. #   define ELSE "ELSE" outside of VERBOSE???
  388. #endif
  389.  
  390. #ifdef DEBUGGING
  391. #   define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\n", __FILE__, __LINE__);sig_catcher(0);}}
  392. #else
  393. #   define assert(ex) ;
  394. #endif
  395.  
  396. #ifdef SPEEDOVERMEM
  397. #   define OFFSET(x) (x)
  398. #else
  399. #   define OFFSET(x) ((x)-absfirst)
  400. #endif
  401.  
  402. /* If you're strapped for space use the help messages in shell scripts */
  403. /* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */
  404. #ifdef MEMHELP  /* undef MEMHELP above to get them all as sh scripts */
  405. #   undef NGHELP
  406. #   undef ARTHELP
  407. #   undef PAGERHELP
  408. #   undef SUBSHELP
  409. #else
  410. #   ifndef NGHELP            /* % and ~ */
  411. #    define NGHELP "%X/ng.help"
  412. #   endif
  413. #   ifndef ARTHELP            /* % and ~ */
  414. #    define ARTHELP "%X/art.help"
  415. #   endif
  416. #   ifndef PAGERHELP        /* % and ~ */
  417. #    define PAGERHELP "%X/pager.help"
  418. #   endif
  419. #   ifndef SUBSHELP        /* % and ~ */
  420. #    define SUBSHELP "%X/subs.help"
  421. #   endif
  422. #endif
  423.  
  424. #ifdef CLEAREOL
  425. #   define TCSIZE 512    /* capacity for termcap strings */
  426. #else
  427. #   ifdef pdp11
  428. #    define TCSIZE 256    /* capacity for termcap strings */
  429. #   else
  430. #    define TCSIZE 512    /* capacity for termcap srings */
  431. #   endif
  432. #endif
  433.  
  434. /* Additional ideas:
  435.  *    Make the do_newsgroup() routine a separate process.
  436.  *    Keep .newsrc on disk instead of in memory.
  437.  *    Overlays, if you have them.
  438.  *    Get a bigger machine.
  439.  */
  440.  
  441. /* End of Space Conservation Section */
  442.  
  443. /* More System Dependencies */
  444.  
  445. /* news library */
  446. #ifndef LIB        /* ~ and %l only ("~%l" is permissable) */
  447. #   define LIB "/usr/lib/news"
  448. #endif
  449.  
  450. /* path to private executables */
  451. #ifndef RNLIB        /* ~, %x and %l only */
  452. #   define RNLIB "%x/rn"
  453. #endif
  454.  
  455. /* system-wide RNINIT switches */
  456. #ifndef GLOBINIT
  457. #   define GLOBINIT "%X/INIT"
  458. #endif
  459.  
  460. /* where to find news files */
  461. #ifndef SPOOL            /* % and ~ */
  462. #   define SPOOL "/usr/spool/news"
  463. #endif
  464.  
  465. /* file containing list of active newsgroups and max article numbers */
  466. #ifndef ACTIVE            /* % and ~ */
  467. #   define ACTIVE "%x/active"
  468. #endif
  469.  
  470. /* location of history file */
  471. #ifndef ARTFILE            /* % and ~ */
  472. #    define ARTFILE "%x/history"
  473. #endif
  474.  
  475. /* command to setup a new .newsrc */
  476. #ifndef NEWSETUP        /* % and ~ */
  477. #   define NEWSETUP "newsetup"
  478. #endif
  479.  
  480. /* command to display a list of un-subscribed-to newsgroups */
  481. #ifndef NEWSGROUPS        /* % and ~ */
  482. #   define NEWSGROUPS "newsgroups"
  483. #endif
  484.  
  485. /* preferred shell for use in doshell routine */
  486. /*  ksh or sh would be okay here */
  487. #ifndef PREFSHELL
  488. #   define PREFSHELL "/bin/csh"
  489. #endif
  490.  
  491. /* path to fastest starting shell */
  492. #ifndef SH
  493. #   define SH "/bin/sh"
  494. #endif
  495.  
  496. /* path to default editor */
  497. #ifndef DEFEDITOR
  498. #   define DEFEDITOR "/usr/ucb/vi"
  499. #endif
  500.  
  501. /* location of macro file */
  502. #ifndef RNMACRO
  503. #   ifdef PUSHBACK
  504. #    define RNMACRO "%./.rnmac"
  505. #   endif
  506. #endif
  507.  
  508. /* location of full name */
  509. #ifndef FULLNAMEFILE
  510. #   ifndef PASSNAMES
  511. #    define FULLNAMEFILE "%./.fullname"
  512. #   endif
  513. #endif
  514.  
  515. /* virtual array file name template */
  516. #ifndef VARYNAME        /* % and ~ */
  517. #   define VARYNAME "/tmp/rnvary.%$"
  518. #endif
  519.  
  520. /* file to pass header to followup article poster */
  521. #ifndef HEADNAME        /* % and ~ */
  522. #   define HEADNAME "%./.rnhead"
  523. /* or alternately #define HEADNAME "/tmp/rnhead.%$" */
  524. #endif
  525.  
  526. #ifndef MAKEDIR
  527. /* shell script to make n-deep subdirectories */
  528. #   ifndef DIRMAKER        /* % and ~ */
  529. #    define DIRMAKER "%X/makedir"
  530. #   endif
  531. #endif
  532.  
  533. /* location of newsrc file */
  534. #ifndef RCNAME        /* % and ~ */
  535. #   define RCNAME "%./.newsrc"
  536. #endif
  537.  
  538. /* temporary newsrc file in case we crash while writing out */
  539. #ifndef RCTNAME        /* % and ~ */
  540. #   define RCTNAME "%./.newnewsrc"
  541. #endif
  542.  
  543. /* newsrc file at the beginning of this session */
  544. #ifndef RCBNAME        /* % and ~ */
  545. #   define RCBNAME "%./.oldnewsrc"
  546. #endif
  547.  
  548. /* if existent, contains process number of current or crashed rn */
  549. #ifndef LOCKNAME        /* % and ~ */
  550. #   define LOCKNAME "%./.rnlock"
  551. #endif
  552.  
  553. /* information from last invocation of rn */
  554. #ifndef LASTNAME        /* % and ~ */
  555. #   define LASTNAME "%./.rnlast"
  556. #endif
  557.  
  558. /* file with soft pointers into the active file */
  559. #ifndef SOFTNAME        /* % and ~ */
  560. #   define SOFTNAME "%./.rnsoft"
  561. #endif
  562.  
  563. /* list of article numbers to mark as unread later (see M and Y cmmands) */
  564. #ifndef RNDELNAME        /* % and ~ */
  565. #   define RNDELNAME "%./.rndelay"
  566. #endif
  567.  
  568. /* a motd-like file for rn */
  569. #ifndef NEWSNEWSNAME        /* % and ~ */
  570. #   define NEWSNEWSNAME "%X/newsnews"
  571. #endif
  572.  
  573. /* command to send a reply */
  574. #ifndef MAILPOSTER        /* % and ~ */
  575. #   define MAILPOSTER "Rnmail -h %h"
  576. #endif
  577.  
  578. #ifdef INTERNET
  579. #   ifndef MAILHEADER        /* % */
  580. #    ifdef CONDSUB
  581. #        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  582. #    else
  583. #        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  584. #    endif
  585. #   endif
  586. #else
  587. #   ifndef MAILHEADER        /* % */
  588. #    ifdef CONDSUB
  589. #        define MAILHEADER "To: %T\nSubject: %(%i=^$?:Re: %S\nNewsgroups: %n\nIn-Reply-To: %i)\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  590. #    else
  591. #        define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  592. #    endif
  593. #   endif
  594. #endif
  595.  
  596. #ifndef YOUSAID            /* % */
  597. #   define YOUSAID "In article %i you write:"
  598. #endif
  599.  
  600. /* command to submit a followup article */
  601. #ifndef NEWSPOSTER        /* % and ~ */
  602. #   define NEWSPOSTER "Pnews -h %h"
  603. #endif
  604.  
  605. #ifndef NEWSHEADER        /* % */
  606. #   ifdef CONDSUB
  607. #ifdef INTERNET
  608. #    define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
  609. #else
  610. #    define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nReply-To: %L@%H.UUCP (%N)\nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
  611. #endif
  612. #   else
  613. #    ifdef INTERNET
  614. #        define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
  615. #    else
  616. #        define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nReply-To:%L@%H.UUCP (%N)\nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
  617. #    endif
  618. #   endif
  619. #endif
  620.  
  621. #ifndef ATTRIBUTION        /* % */
  622. #   define ATTRIBUTION "In article %i %f writes:"
  623. #endif
  624.  
  625. #ifndef PIPESAVER        /* % */
  626. #   ifdef CONDSUB
  627. #       ifdef SERVER
  628. #               define PIPESAVER "%(%B=^0$?<%P/rrn%a.%$:tail +%Bc %P/rrn%a.%$ |) %b"
  629. #       else
  630. #        define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
  631. #    endif
  632. #   else
  633. #       ifdef SERVER
  634. #               define PIPESAVER "tail +%Bc %P/rrn%a.%$ | %b"
  635. #       else
  636. #        define PIPESAVER "tail +%Bc %A | %b"
  637. #    endif
  638. #   endif
  639. #endif
  640.  
  641. #ifndef NORMSAVER        /* % and ~ */
  642. #    ifdef SERVER
  643. #    define NORMSAVER "%X/norm.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\""
  644. #    else
  645. #       define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
  646. #    endif
  647. #endif
  648.  
  649. #ifndef MBOXSAVER        /* % and ~ */
  650. #   ifdef MININACT        /* 2.10.2 site? */
  651. #       ifdef SERVER
  652. #           define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %`date`\""
  653. #       else
  654. #        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
  655. #    endif SERVER
  656. #   else
  657. #    ifdef CONDSUB
  658. #           ifdef SERVER
  659. #               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\
  660. " \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?
  661. %1 %3 %(%2=..?%2: %2) %5 19%4)\""
  662. #           else
  663. #            define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
  664. #        endif
  665.                     /* header munging with a vengeance */
  666. #    else
  667. #           ifdef SERVER
  668. #               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %[posted]\""
  669. #           else
  670. #            define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
  671. #        endif
  672. #    endif
  673. #   endif
  674. #endif
  675.  
  676. #ifdef MKDIRS
  677.  
  678. #   ifndef SAVEDIR            /* % and ~ */
  679. #    define SAVEDIR "%p/%c"
  680. #   endif
  681. #   ifndef SAVENAME        /* % */
  682. #    define SAVENAME "%a"
  683. #   endif
  684.  
  685. #else
  686.  
  687. #   ifndef SAVEDIR            /* % and ~ */
  688. #    define SAVEDIR "%p"
  689. #   endif
  690. #   ifndef SAVENAME        /* % */
  691. #    define SAVENAME "%^C"
  692. #   endif
  693.  
  694. #endif
  695.  
  696. #ifndef KILLGLOBAL        /* % and ~ */
  697. #   define KILLGLOBAL "%p/KILL"
  698. #endif
  699.  
  700. #ifndef KILLLOCAL        /* % and ~ */
  701. #   define KILLLOCAL "%p/%c/KILL"
  702. #endif
  703.  
  704. /* how to cancel an article */
  705. #ifndef CANCEL
  706. #   ifdef MININACT            /* 2.10.2 ? */
  707. #    define CANCEL "%x/inews -h < %h"
  708. #   else
  709. #    define CANCEL "inews -h < %h"
  710. #   endif
  711. #endif
  712.  
  713. /* how to cancel an article, continued */
  714. #ifndef CANCELHEADER
  715. #ifdef INTERNET
  716. #   define CANCELHEADER "Newsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nDistribution: %D\nOrganization: %o\n\nThis message was cancelled from within rn.\n"
  717. #else
  718. #   define CANCELHEADER "Newsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nReply-To: %L@%H.UUCP (%N)\nDistribution: %D\nOrganization: %o\n"
  719. #endif
  720. #endif
  721.  
  722. /* where to find the mail file */
  723. #ifndef MAILFILE
  724. #   define MAILFILE "/usr/spool/mail/%L"
  725. #endif
  726.  
  727. /* some important types */
  728.  
  729. typedef int        NG_NUM;        /* newsgroup number */
  730. typedef long        ART_NUM;    /* article number */
  731. #ifdef pdp11
  732.     typedef short    ART_UNREAD;    /* ordinarily this should be long */
  733.                     /* like ART_NUM, but assuming that */
  734.                     /* we stay less than 32767 articles */
  735.                     /* behind saves a lot of space. */
  736.                     /* NOTE: do not make unsigned. */
  737. #else
  738.     typedef long    ART_UNREAD;
  739. #endif
  740. #ifdef SERVER
  741. typedef int        ART_PART;    /* for passing to nntpopen() */
  742. #endif
  743. typedef long        ART_POS;    /* char position in article file */
  744. typedef int        ART_LINE;    /* line position in article file */
  745. typedef long        ACT_POS;    /* char position in active file */
  746. typedef unsigned int    MEM_SIZE;    /* for passing to malloc */
  747.  
  748.  
  749. /* *** end of the machine dependent stuff *** */
  750.  
  751. /* GLOBAL THINGS */
  752.  
  753. /* file statistics area */
  754.  
  755. EXT struct stat filestat;
  756.  
  757. /* various things of type char */
  758.  
  759. char    *index();
  760. char    *rindex();
  761. char    *getenv();
  762. char    *strcat();
  763. char    *strcpy();
  764.  
  765. EXT char buf[LBUFLEN+1];    /* general purpose line buffer */
  766. EXT char cmd_buf[CBUFLEN];    /* buffer for formatting system commands */
  767.  
  768. EXT char *indstr INIT(">");    /* indent for old article embedded in followup */
  769.  
  770. EXT char *cwd INIT(Nullch);        /* current working directory */
  771. EXT char *dfltcmd INIT(Nullch);    /* 1st char is default command */
  772.  
  773. /* switches */
  774.  
  775. #ifdef DEBUGGING
  776.     EXT int debug INIT(0);                /* -D */
  777. #   define DEB_INNERSRCH 32 
  778. #   define DEB_FILEXP 64 
  779. #   define DEB_HASH 128
  780. #   define DEB_XREF_MARKER 256
  781. #   define DEB_CTLAREA_BITMAP 512
  782. #   define DEB_SOFT_POINTERS 1024
  783. #   define DEB_NEWSRC_LINE 2048
  784. #   define DEB_SEARCH_AHEAD 4096
  785. #   define DEB_CHECKPOINTING 8192
  786. #   define DEB_FEED_XREF 16384
  787. #endif
  788.  
  789. #ifdef ARTSEARCH
  790.     EXT int scanon INIT(0);                /* -S */
  791. #endif
  792.  
  793. EXT bool mbox_always INIT(FALSE);            /* -M */
  794. EXT bool norm_always INIT(FALSE);            /* -N */
  795. EXT bool checkflag INIT(FALSE);            /* -c */
  796. EXT bool suppress_cn INIT(FALSE);            /* -s */
  797. EXT int countdown INIT(5);    /* how many lines to list before invoking -s */
  798. EXT bool muck_up_clear INIT(FALSE);            /* -loco */
  799. EXT bool erase_screen INIT(FALSE);            /* -e */
  800. #ifdef CLEAREOL
  801. EXT bool can_home_clear INIT(FALSE);        /* fancy -e -- PWP */
  802. #endif CLEAREOL
  803. EXT bool findlast INIT(FALSE);            /* -r */
  804. EXT bool typeahead INIT(FALSE);            /* -T */
  805. #ifdef VERBOSE
  806. #   ifdef TERSE
  807.     EXT bool verbose INIT(TRUE);            /* +t */
  808. #   endif
  809. #endif
  810. #ifdef VERIFY
  811.     EXT bool verify INIT(FALSE);            /* -v */
  812. #endif
  813.     EXT bool quickstart INIT(FALSE);            /* -q */
  814.  
  815. #define NOMARKING 0
  816. #define STANDOUT 1
  817. #define UNDERLINE 2
  818. EXT int marking INIT(NOMARKING);            /* -m */
  819.  
  820. EXT ART_LINE initlines INIT(0);        /* -i */
  821. EXT bool initlines_specified INIT(FALSE);
  822.  
  823. /* miscellania */
  824.  
  825. int fseek();
  826. long atol(), ftell();
  827. EXT bool in_ng INIT(FALSE);        /* current state of rn */
  828. EXT char mode INIT('i');        /* current state of rn */
  829.  
  830. EXT FILE *tmpfp INIT(Nullfp);    /* scratch fp used for .rnlock, .rnlast, etc. */
  831.  
  832. EXT NG_NUM nextrcline INIT(0);    /* 1st unused slot in rcline array */
  833.             /* startup to avoid checking twice in a row */
  834.  
  835. extern errno;
  836.  
  837. /* Factored strings */
  838.  
  839. EXT char nullstr[] INIT("");
  840. EXT char sh[] INIT(SH);
  841. EXT char defeditor[] INIT(DEFEDITOR);
  842. EXT char hforhelp[] INIT("Type h for help.\n");
  843. #ifdef STRICTCR
  844. EXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
  845. #endif
  846. EXT char readerr[] INIT("rn read error");
  847. EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
  848. EXT char cantopen[] INIT("Can't open %s\n");
  849. EXT char cantcreate[] INIT("Can't create %s\n");
  850.  
  851. #ifdef VERBOSE
  852.     EXT char nocd[] INIT("Can't chdir to directory %s\n");
  853. #else
  854.     EXT char nocd[] INIT("Can't find %s\n");
  855. #endif
  856.  
  857. #ifdef NOLINEBUF
  858. #define FLUSH ,fflush(stdout)
  859. #else
  860. #define FLUSH
  861. #endif
  862.  
  863. #ifdef lint
  864. #undef FLUSH
  865. #define FLUSH
  866. #undef putchar
  867. #define putchar(c)
  868. #endif
  869. !STUFFY!FUNK!
  870. echo Extracting ng.c
  871. cat >ng.c <<'!STUFFY!FUNK!'
  872. /* $Header: ng.c,v 4.3.2.7 90/04/21 14:44:23 sob Exp $
  873.  *
  874.  * $Log:    ng.c,v $
  875.  * Revision 4.3.2.7  90/04/21  14:44:23  sob
  876.  * Revised previous patch insure that it does not decrement below zero.
  877.  * 
  878.  * Revision 4.3.2.6  90/03/22  23:04:49  sob
  879.  * Fixes provided by Wayne Davison <drivax!davison>
  880.  * 
  881.  * Revision 4.3.2.5  89/12/09  01:18:42  sob
  882.  * Fixed a bad call to nntpopen().
  883.  * 
  884.  * Revision 4.3.2.4  89/11/28  01:51:20  sob
  885.  * Removed redundant #include directive.
  886.  * 
  887.  * Revision 4.3.2.3  89/11/27  01:31:03  sob
  888.  * Altered NNTP code per ideas suggested by Bela Lubkin
  889.  * <filbo@gorn.santa-cruz.ca.us>
  890.  * 
  891.  * Revision 4.3.2.2  89/11/26  22:53:35  sob
  892.  * Add new patches to make RRN be faster.
  893.  * 
  894.  * Revision 4.3.2.1  89/11/06  00:54:27  sob
  895.  * Added RRN support from NNTP 1.5
  896.  * 
  897.  * Revision 4.3.1.6  85/09/10  11:03:42  lwall
  898.  * Improved %m in in_char().
  899.  * 
  900.  * Revision 4.3.1.5  85/09/05  12:34:37  lwall
  901.  * Catchup command could make unread article count too big.
  902.  * 
  903.  * Revision 4.3.1.4  85/07/23  18:19:46  lwall
  904.  * Added MAILCALL environment variable.
  905.  * 
  906.  * Revision 4.3.1.3  85/05/16  16:48:09  lwall
  907.  * Fixed unsubsubscribe.
  908.  * 
  909.  * Revision 4.3.1.2  85/05/13  09:29:28  lwall
  910.  * Added CUSTOMLINES option.
  911.  * 
  912.  * Revision 4.3.1.1  85/05/10  11:36:00  lwall
  913.  * Branch for patches.
  914.  * 
  915.  * Revision 4.3  85/05/01  11:43:43  lwall
  916.  * Baseline for release with 4.3bsd.
  917.  * 
  918.  */
  919.  
  920. #include "EXTERN.h"
  921. #include "common.h"
  922. #include "rn.h"
  923. #include "term.h"
  924. #include "final.h"
  925. #include "util.h"
  926. #include "artsrch.h"
  927. #include "cheat.h"
  928. #include "help.h"
  929. #include "kfile.h"
  930. #include "rcstuff.h"
  931. #include "head.h"
  932. #include "bits.h"
  933. #include "art.h"
  934. #include "artio.h"
  935. #include "ngstuff.h"
  936. #include "intrp.h"
  937. #include "respond.h"
  938. #include "ngdata.h"
  939. #include "backpage.h"
  940. #include "rcln.h"
  941. #include "last.h"
  942. #include "search.h"
  943. #ifdef SERVER
  944. #include "server.h"
  945. #endif
  946. #include "INTERN.h"
  947. #include "ng.h"
  948. #include "artstate.h"            /* somebody has to do it */
  949.  
  950. /* art_switch() return values */
  951.  
  952. #define AS_NORM 0
  953. #define AS_INP 1
  954. #define AS_ASK 2
  955. #define AS_CLEAN 3
  956.  
  957. ART_NUM recent_art = 0;        /* previous article # for '-' command */
  958. ART_NUM curr_art = 0;                /* current article # */
  959. int exit_code = NG_NORM;
  960.  
  961. void
  962. ng_init()
  963. {
  964.  
  965. #ifdef KILLFILES
  966.     open_kfile(KF_GLOBAL);
  967. #endif
  968. #ifdef CUSTOMLINES
  969.     init_compex(&hide_compex);
  970.     init_compex(&page_compex);
  971. #endif
  972. }
  973.  
  974. /* do newsgroup on line ng with name ngname */
  975.  
  976. /* assumes that we are chdir'ed to SPOOL, and assures that that is
  977.  * still true upon return, but chdirs to SPOOL/ngname in between
  978.  *
  979.  * If you can understand this routine, you understand most of the program.
  980.  * The basic structure is:
  981.  *    for each desired article
  982.  *        for each desired page
  983.  *            for each line on page
  984.  *                if we need another line from file
  985.  *                    get it
  986.  *                    if it's a header line
  987.  *                        do special things
  988.  *                for each column on page
  989.  *                    put out a character
  990.  *                end loop
  991.  *            end loop
  992.  *        end loop
  993.  *    end loop
  994.  *
  995.  *    (Actually, the pager is in another routine.)
  996.  *
  997.  * The chief problem is deciding what is meant by "desired".  Most of
  998.  * the messiness of this routine is due to the fact that people want
  999.  * to do unstructured things all the time.  I have used a few judicious
  1000.  * goto's where I thought it improved readability.  The rest of the messiness
  1001.  * arises from trying to be both space and time efficient.  Have fun.
  1002.  */
  1003.  
  1004. int
  1005. do_newsgroup(start_command)
  1006. char *start_command;            /* command to fake up first */
  1007. {
  1008. #ifdef SERVER
  1009.     char ser_line[256];
  1010.     char artname[32];
  1011.     static long our_pid;
  1012. #endif SERVER
  1013.     char oldmode = mode;
  1014.     register long i;            /* scratch */
  1015.     int skipstate;            /* how many unavailable articles */
  1016.                     /*   have we skipped already? */
  1017.     
  1018.     char *whatnext = "%sWhat next? [%s]";
  1019.  
  1020. #ifdef SERVER
  1021.     if (our_pid == 0)           /* Agreed, this is gross */
  1022.         our_pid = getpid();
  1023. #endif SERVER
  1024.  
  1025. #ifdef ARTSEARCH
  1026.     srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0);
  1027.                     /* did they say -S? */
  1028. #endif
  1029.     
  1030.     mode = 'a';
  1031.     recent_art = curr_art = 0;
  1032.     exit_code = NG_NORM;
  1033.  
  1034. #ifdef SERVER
  1035.     sprintf(ser_line, "GROUP %s", ngname);
  1036.     put_server(ser_line);
  1037.     if (get_server(ser_line, sizeof(ser_line)) < 0) {
  1038.     fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  1039.     finalize(1);
  1040.     }
  1041.     if (*ser_line != CHAR_OK) {
  1042.     if (atoi(ser_line) != ERR_NOGROUP)
  1043.         fprintf(stderr, "rrn: server response to GROUP %s:\n%s\n",
  1044.             ngname, ser_line);
  1045.     return (-1);
  1046.     }
  1047. #else not SERVER
  1048.     if (eaccess(ngdir,5)) {        /* directory read protected? */
  1049.     if (eaccess(ngdir,0)) {
  1050. #ifdef VERBOSE
  1051.         IF(verbose)
  1052.         printf("\nNewsgroup %s does not have a spool directory!\n",
  1053.             ngname) FLUSH;
  1054.         ELSE
  1055. #endif
  1056. #ifdef TERSE
  1057.         printf("\nNo spool for %s!\n",ngname) FLUSH;
  1058. #endif
  1059. #ifdef CATCHUP
  1060.         catch_up(ng);
  1061. #endif
  1062.         toread[ng] = TR_NONE;
  1063.     }
  1064.     else {
  1065. #ifdef VERBOSE
  1066.         IF(verbose)
  1067.         printf("\nNewsgroup %s is not currently accessible.\n",
  1068.             ngname) FLUSH;
  1069.         ELSE
  1070. #endif
  1071. #ifdef TERSE
  1072.         printf("\n%s not readable.\n",ngname) FLUSH;
  1073. #endif
  1074.         toread[ng] = TR_NONE;    /* make this newsgroup invisible */
  1075.                     /* (temporarily) */
  1076.     }
  1077.     mode = oldmode;
  1078.     return -1;
  1079.     }
  1080.  
  1081.     /* chdir to newsgroup subdirectory */
  1082.  
  1083.     if (chdir(ngdir)) {
  1084.     printf(nocd,ngdir) FLUSH;
  1085.     mode = oldmode;
  1086.     return -1;
  1087.     }
  1088. #endif SERVER
  1089.  
  1090. #ifdef CACHESUBJ
  1091.     subj_list = Null(char **);        /* no subject list till needed */
  1092. #endif
  1093.     
  1094.     /* initialize control bitmap */
  1095.  
  1096.     if (initctl()) {
  1097.     mode = oldmode;
  1098.     return -1;
  1099.     }
  1100.  
  1101.     /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
  1102.     
  1103.     in_ng = TRUE;            /* tell the world we are here */
  1104.     forcelast = TRUE;            /* if 0 unread, do not bomb out */
  1105.     art=firstart;
  1106.     
  1107.     /* remember what newsgroup we were in for sake of posterity */
  1108.  
  1109.     writelast();
  1110.  
  1111.     /* see if there are any special searches to do */
  1112.  
  1113. #ifdef KILLFILES
  1114.     open_kfile(KF_LOCAL);
  1115. #ifdef VERBOSE
  1116.     IF(verbose)
  1117.     kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE);
  1118.     ELSE
  1119. #endif
  1120. #ifdef TERSE
  1121.     kill_unwanted(firstart,"Killing...\n\n",TRUE);
  1122. #endif
  1123. #endif
  1124.     
  1125.     /* do they want a special top line? */
  1126.  
  1127.     firstline = getval("FIRSTLINE",Nullch);
  1128.  
  1129.     /* custom line suppression, custom page ending */
  1130.  
  1131. #ifdef CUSTOMLINES
  1132.     if (hideline = getval("HIDELINE",Nullch))
  1133.     compile(&hide_compex,hideline,TRUE,TRUE);
  1134.     if (pagestop = getval("PAGESTOP",Nullch))
  1135.     compile(&page_compex,pagestop,TRUE,TRUE);
  1136. #endif
  1137.  
  1138.     /* now read each unread article */
  1139.  
  1140.     rc_changed = doing_ng = TRUE;    /* enter the twilight zone */
  1141.     skipstate = 0;            /* we have not skipped anything (yet) */
  1142.     checkcount = 0;            /* do not checkpoint for a while */
  1143.     do_fseek = FALSE;            /* start 1st article at top */
  1144.     if (art > lastart)
  1145.     art=firstart;            /* init the for loop below */
  1146.     for (; art<=lastart+1; ) {        /* for each article */
  1147.  
  1148.     /* do we need to "grow" the newsgroup? */
  1149.  
  1150.     if (art > lastart || forcegrow)
  1151.         grow_ctl();
  1152.     check_first(art);        /* make sure firstart is still 1st */
  1153.     if (start_command) {        /* fake up an initial command? */
  1154.         prompt = whatnext;
  1155.         strcpy(buf,start_command);
  1156.         free(start_command);
  1157.         start_command = Nullch;
  1158.         art = lastart+1;
  1159.         goto article_level;
  1160.     }
  1161.     if (art>lastart) {        /* are we off the end still? */
  1162.         ART_NUM ucount = 0;        /* count of unread articles left */
  1163.  
  1164.         for (i=firstart; i<=lastart; i++)
  1165.         if (!(ctl_read(i)))
  1166.             ucount++;        /* count the unread articles */
  1167. #ifdef DEBUGGING
  1168.         /*NOSTRICT*/
  1169.         if (debug && ((ART_NUM)toread[ng]) != ucount)
  1170.         printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount)
  1171.           FLUSH;
  1172. #endif
  1173.         /*NOSTRICT*/
  1174.         toread[ng] = (ART_UNREAD)ucount;    /* this is perhaps pointless */
  1175.         art = lastart + 1;        /* keep bitmap references sane */
  1176.         if (art != curr_art) {
  1177.         recent_art = curr_art;
  1178.                     /* remember last article # (for '-') */
  1179.         curr_art = art;      /* remember this article # */
  1180.         }
  1181.         if (erase_screen)
  1182.         clear();            /* clear the screen */
  1183.         else
  1184.         fputs("\n\n",stdout) FLUSH;
  1185. #ifdef VERBOSE
  1186.         IF(verbose)
  1187.         printf("End of newsgroup %s.",ngname);
  1188.                     /* print pseudo-article */
  1189.         ELSE
  1190. #endif
  1191. #ifdef TERSE
  1192.         printf("End of %s",ngname);
  1193. #endif
  1194.         if (ucount) {
  1195.         printf("  (%ld article%s still unread)",
  1196.             (long)ucount,ucount==1?nullstr:"s");
  1197.         }
  1198.         else {
  1199.         if (!forcelast)
  1200.             goto cleanup;    /* actually exit newsgroup */
  1201.         }
  1202.         prompt = whatnext;
  1203. #ifdef ARTSEARCH
  1204.         srchahead = 0;        /* no more subject search mode */
  1205. #endif
  1206.         fputs("\n\n",stdout) FLUSH;
  1207.         skipstate = 0;        /* back to none skipped */
  1208.     }
  1209.     else if (!reread && was_read(art)) {
  1210.                     /* has this article been read? */
  1211.         art++;            /* then skip it */
  1212.         continue;
  1213.     }
  1214.     else if
  1215.       (!reread && !was_read(art)
  1216. #ifdef SERVER
  1217.         && nntpopen(art,HEAD) == Nullfp) { 
  1218. #else
  1219.         && artopen(art) == Nullfp) { /* never read it, & cannot find it? */
  1220.         if (errno != ENOENT) {    /* has it not been deleted? */
  1221. #ifdef VERBOSE
  1222.         IF(verbose)
  1223.             printf("\n(Article %ld exists but is unreadable.)\n",
  1224.             (long)art) FLUSH;
  1225.         ELSE
  1226. #endif
  1227. #ifdef TERSE
  1228.             printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
  1229. #endif
  1230.         skipstate = 0;
  1231.         sleep(2);
  1232.         }
  1233. #endif
  1234.         switch(skipstate++) {
  1235.         case 0:
  1236.         clear();
  1237. #ifdef VERBOSE
  1238.         IF(verbose)
  1239.             fputs("Skipping unavailable article",stdout);
  1240.         ELSE
  1241. #endif
  1242. #ifdef TERSE
  1243.             fputs("Skipping",stdout);
  1244. #endif
  1245.         for (i = just_a_sec/3; i; --i)
  1246.             putchar(PC);
  1247.         fflush(stdout);
  1248.         sleep(1);
  1249.         break;
  1250.         case 1:
  1251.         fputs("..",stdout);
  1252.         fflush(stdout);
  1253.         break;
  1254.         default:
  1255.         putchar('.');
  1256.         fflush(stdout);
  1257. #ifndef SERVER
  1258. #define READDIR
  1259. #ifdef READDIR
  1260.         {            /* fast skip patch */
  1261.             ART_NUM newart;
  1262.             
  1263.             if (! (newart=getngmin(".",art)))
  1264.             newart = lastart+1;
  1265.             for (i=art; i<newart; i++)
  1266.             oneless(i);
  1267.             art = newart - 1;
  1268.         }
  1269. #endif
  1270. #else
  1271.         {
  1272.             char    ser_line[256];
  1273.             ART_NUM    newart;
  1274.  
  1275.             put_server("NEXT");
  1276.             if (get_server(ser_line, sizeof (ser_line)) < 0) {
  1277.                 fprintf(stderr,
  1278.             "rrn: unexpected close of server socket.\n");
  1279.                 finalize(1);
  1280.             }
  1281.             if (ser_line[0] != CHAR_OK)
  1282.                 newart = lastart + 1;
  1283.             else
  1284.                 newart = atoi(ser_line+4);
  1285.                 for (i=art; i<newart; i++)
  1286.                 oneless(i);
  1287.                 art = newart - 1;
  1288.         }
  1289. #endif SERVER
  1290.         break;
  1291.         }
  1292.         oneless(art);        /* mark deleted as read */
  1293.         art++;            /* try next article */
  1294.         continue;
  1295.     }
  1296.     else {                /* we have a real live article */
  1297.         skipstate = 0;        /* back to none skipped */
  1298.         if (art != curr_art) {
  1299.         recent_art = curr_art;
  1300.                     /* remember last article # (for '-') */
  1301.         curr_art = art;      /* remember this article # */
  1302.         }
  1303.         if (!do_fseek) {        /* starting at top of article? */
  1304.         artline = 0;        /* start at the beginning */
  1305.         topline = -1;        /* and remember top line of screen */
  1306.                     /*  (line # within article file) */
  1307.         }
  1308.         clear();            /* clear screen */
  1309.         artopen(art);        /* make sure article file is open */
  1310.         if (artfp == Nullfp) {    /* could not find article? */
  1311.         printf("Article %ld of %s is not available.\n\n",
  1312.             (long)art,ngname) FLUSH;
  1313.         prompt = whatnext;
  1314. #ifdef ARTSEARCH
  1315.         srchahead = 0;
  1316. #endif
  1317.         }
  1318.         else {            /* found it, so print it */
  1319.         switch (do_article()) {
  1320.         case DA_CLEAN:        /* quit newsgroup */
  1321.             goto cleanup;
  1322.         case DA_TOEND:        /* do not mark as read */
  1323.             goto reask_article; 
  1324.         case DA_RAISE:        /* reparse command at end of art */
  1325.             goto article_level;
  1326.         case DA_NORM:        /* normal end of article */
  1327.             break;
  1328.         }
  1329.         }
  1330.         mark_as_read(art);         /* mark current article as read */
  1331.         reread = FALSE;
  1332.         do_hiding = TRUE;
  1333. #ifdef ROTATION
  1334.         rotate = FALSE;
  1335. #endif
  1336.     }
  1337.  
  1338. /* if these gotos bother you, think of this as a little state machine */
  1339.  
  1340. reask_article:
  1341. #ifdef MAILCALL
  1342.     setmail();
  1343. #endif
  1344.     setdfltcmd();
  1345. #ifdef CLEAREOL
  1346.     if (erase_screen && can_home_clear)
  1347.         clear_rest();
  1348. #endif CLEAREOL
  1349.     unflush_output();        /* disable any ^O in effect */
  1350.     standout();            /* enter standout mode */
  1351.     printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
  1352.     un_standout();            /* leave standout mode */
  1353.     putchar(' ');
  1354.     fflush(stdout);
  1355. reinp_article:
  1356.     eat_typeahead();
  1357. #ifdef PENDING
  1358.     look_ahead();            /* see what we can do in advance */
  1359.     if (!input_pending())
  1360.         collect_subjects();        /* loads subject cache until */
  1361.                     /* input is pending */
  1362. #endif
  1363.     getcmd(buf);
  1364.     if (errno || *buf == '\f') {
  1365.         if (LINES < 100 && !int_count)
  1366.         *buf = '\f';        /* on CONT fake up refresh */
  1367.         else {
  1368.         putchar('\n') FLUSH;        /* but only on a crt */
  1369.         goto reask_article;
  1370.         }
  1371.     }
  1372. article_level:
  1373.  
  1374.     /* parse and process article level command */
  1375.  
  1376.     switch (art_switch()) {
  1377.     case AS_INP:            /* multichar command rubbed out */
  1378.         goto reinp_article;
  1379.     case AS_ASK:            /* reprompt "End of article..." */
  1380.         goto reask_article;
  1381.     case AS_CLEAN:            /* exit newsgroup */
  1382.         goto cleanup;
  1383.     case AS_NORM:            /* display article art */
  1384.         break;
  1385.     }
  1386.     }                    /* end of article selection loop */
  1387.     
  1388. /* shut down newsgroup */
  1389.  
  1390. cleanup:
  1391. #ifdef KILLFILES
  1392.     kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
  1393.                     /* do cleanup from KILL file, if any */
  1394. #endif
  1395.     in_ng = FALSE;            /* leave newsgroup state */
  1396.     if (artfp != Nullfp) {        /* article still open? */
  1397.     fclose(artfp);            /* close it */
  1398.     artfp = Nullfp;            /* and tell the world */
  1399. #ifdef SERVER
  1400.         sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
  1401.         UNLINK(artname);
  1402. #endif SERVER
  1403.     openart = 0;
  1404.     }
  1405.     putchar('\n') FLUSH;
  1406.     yankback();                /* do a Y command */
  1407.     restore_ng();            /* reconstitute .newsrc line */
  1408.     doing_ng = FALSE;            /* tell sig_catcher to cool it */
  1409.     free(ctlarea);            /* return the control area */
  1410. #ifdef CACHESUBJ
  1411.     if (subj_list) {
  1412.     for (i=OFFSET(lastart); i>=0; --i)
  1413.         if (subj_list[i])
  1414.         free(subj_list[i]);
  1415. #ifndef lint
  1416.     free((char*)subj_list);
  1417. #endif lint
  1418.     }
  1419. #endif
  1420.     write_rc();                /* and update .newsrc */
  1421.     rc_changed = FALSE;            /* tell sig_catcher it is ok */
  1422.     if (chdir(spool)) {
  1423.     printf(nocd,spool) FLUSH;
  1424.     sig_catcher(0);
  1425.     }
  1426. #ifdef KILLFILES
  1427.     if (localkfp) {
  1428.     fclose(localkfp);
  1429.     localkfp = Nullfp;
  1430.     }
  1431. #endif
  1432.     mode = oldmode;
  1433.     return exit_code;
  1434. }                    /* Whew! */
  1435.  
  1436. /* decide what to do at the end of an article */
  1437.  
  1438. int
  1439. art_switch()
  1440. {
  1441.     register ART_NUM i;
  1442.       
  1443.     setdef(buf,dfltcmd);
  1444. #ifdef VERIFY
  1445.     printcmd();
  1446. #endif
  1447.     switch (*buf) {
  1448.     case 'p':            /* find previous unread article */
  1449.     do {
  1450.         if (art <= firstart)
  1451.         break;
  1452.         art--;
  1453. #ifdef SERVER
  1454.     } while (was_read(art) || nntpopen(art,HEAD) == Nullfp);
  1455. #else
  1456.     } while (was_read(art) || artopen(art) == Nullfp);
  1457. #endif
  1458. #ifdef ARTSEARCH
  1459.     srchahead = 0;
  1460. #endif
  1461.     return AS_NORM;
  1462.     case 'P':            /* goto previous article */
  1463.     if (art > absfirst)
  1464.         art--;
  1465.     else {
  1466. #ifdef VERBOSE
  1467.         IF(verbose)
  1468.         fputs("\n\
  1469. There are no articles prior to this one.\n\
  1470. ",stdout) FLUSH;
  1471.         ELSE
  1472. #endif
  1473. #ifdef TERSE
  1474.         fputs("\nNo previous articles\n",stdout) FLUSH;
  1475. #endif
  1476.         return AS_ASK;
  1477.     }
  1478.     reread = TRUE;
  1479. #ifdef ARTSEARCH
  1480.     srchahead = 0;
  1481. #endif
  1482.     return AS_NORM;
  1483.     case '-':
  1484.     if (recent_art) {
  1485.         art = recent_art;
  1486.         reread = TRUE;
  1487. #ifdef ARTSEARCH
  1488.         srchahead = -(srchahead != 0);
  1489. #endif
  1490.         return AS_NORM;
  1491.     }
  1492.     else {
  1493.         exit_code = NG_MINUS;
  1494.         return AS_CLEAN;
  1495.     }
  1496.     case 'n':        /* find next unread article? */
  1497.     if (art > lastart) {
  1498.         if (toread[ng])
  1499.         art = firstart;
  1500.         else
  1501.         return AS_CLEAN;
  1502.     }
  1503. #ifdef ARTSEARCH
  1504.     else if (scanon && srchahead) {
  1505.         *buf = Ctl('n');
  1506.         goto normal_search;
  1507.     }
  1508. #endif
  1509.     else
  1510.         art++;
  1511. #ifdef ARTSEARCH
  1512.     srchahead = 0;
  1513. #endif
  1514.     return AS_NORM;
  1515.     case 'N':            /* goto next article */
  1516.     if (art > lastart)
  1517.         art = absfirst;
  1518.     else
  1519.         art++;
  1520.     if (art <= lastart)
  1521.         reread = TRUE;
  1522. #ifdef ARTSEARCH
  1523.     srchahead = 0;
  1524. #endif
  1525.     return AS_NORM;
  1526.     case '$':
  1527.     art = lastart+1;
  1528.     forcelast = TRUE;
  1529. #ifdef ARTSEARCH
  1530.     srchahead = 0;
  1531. #endif
  1532.     return AS_NORM;
  1533.     case '1': case '2': case '3':    /* goto specified article */
  1534.     case '4': case '5': case '6':    /* or do something with a range */
  1535.     case '7': case '8': case '9': case '.':
  1536.     forcelast = TRUE;
  1537.     switch (numnum()) {
  1538.     case NN_INP:
  1539.         return AS_INP;
  1540.     case NN_ASK:
  1541.         return AS_ASK;
  1542.     case NN_REREAD:
  1543.         reread = TRUE;
  1544. #ifdef ARTSEARCH
  1545.         if (srchahead)
  1546.         srchahead = -1;
  1547. #endif
  1548.         break;
  1549.     case NN_NORM:
  1550.         if (was_read(art)) {
  1551.         art = firstart;
  1552.         pad(just_a_sec/3);
  1553.         }
  1554.         else
  1555.         return AS_ASK;
  1556.         break;
  1557.     }
  1558.     return AS_NORM;
  1559.     case Ctl('k'):
  1560.     edit_kfile();
  1561.     return AS_ASK;
  1562.     case 'K':
  1563.     case 'k':
  1564.     case Ctl('n'): case Ctl('p'):
  1565.     case '/': case '?':
  1566. #ifdef ARTSEARCH
  1567. normal_search:
  1568.     {        /* search for article by pattern */
  1569.     char cmd = *buf;
  1570.     
  1571.     reread = TRUE;        /* assume this */
  1572.     switch (art_search(buf, (sizeof buf), TRUE)) {
  1573.     case SRCH_ERROR:
  1574.         return AS_ASK;
  1575.     case SRCH_ABORT:
  1576.         return AS_INP;
  1577.     case SRCH_INTR:
  1578. #ifdef VERBOSE
  1579.         IF(verbose)
  1580.         printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH;
  1581.         ELSE
  1582. #endif
  1583. #ifdef TERSE
  1584.         printf("\n(Intr at %ld)\n",(long)art) FLUSH;
  1585. #endif
  1586.         art = curr_art;
  1587.                 /* restore to current article */
  1588.         return AS_ASK;
  1589.     case SRCH_DONE:
  1590.         fputs("done\n",stdout) FLUSH;
  1591.         pad(just_a_sec/3);    /* 1/3 second */
  1592.         if (srchahead)
  1593.         art = firstart;
  1594.         else
  1595.         art = curr_art;
  1596.         reread = FALSE;
  1597.         return AS_NORM;
  1598.     case SRCH_SUBJDONE:
  1599. #ifdef UNDEF
  1600.         fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
  1601.         pad(just_a_sec/3);    /* 1/3 second */
  1602. #endif
  1603.         art = firstart;
  1604.         reread = FALSE;
  1605.         return AS_NORM;
  1606.     case SRCH_NOTFOUND:
  1607.         fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
  1608.         art = curr_art;  /* restore to current article */
  1609.         return AS_ASK;
  1610.     case SRCH_FOUND:
  1611.         if (cmd == Ctl('n') || cmd == Ctl('p'))
  1612.         oldsubject = TRUE;
  1613.         break;
  1614.     }
  1615.     return AS_NORM;
  1616.     }
  1617. #else
  1618.     buf[1] = '\0';
  1619.     notincl(buf);
  1620.     return AS_ASK;
  1621. #endif
  1622.     case 'u':            /* unsubscribe from this newsgroup? */
  1623.     rcchar[ng] = NEGCHAR;
  1624.     return AS_CLEAN;
  1625.     case 'M':
  1626. #ifdef DELAYMARK
  1627.     if (art <= lastart) {
  1628.         delay_unmark(art);
  1629.         printf("\nArticle %ld will return.\n",(long)art) FLUSH;
  1630.     }
  1631. #else
  1632.     notincl("M");
  1633. #endif
  1634.     return AS_ASK;
  1635.     case 'm':
  1636.     if (art <= lastart) {
  1637.         unmark_as_read(art);
  1638.         printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
  1639.     }
  1640.     return AS_ASK;
  1641.     case 'c':            /* catch up */
  1642.       reask_catchup:
  1643. #ifdef VERBOSE
  1644.     IF(verbose)
  1645.         in_char("\nDo you really want to mark everything as read? [yn] ",
  1646.         'C');
  1647.     ELSE
  1648. #endif
  1649. #ifdef TERSE
  1650.         in_char("\nReally? [ynh] ", 'C');
  1651. #endif
  1652.     putchar('\n') FLUSH;
  1653.     setdef(buf,"y");
  1654. #ifdef VERIFY
  1655.     printcmd();
  1656. #endif
  1657.     if (*buf == 'h') {
  1658. #ifdef VERBOSE
  1659.         IF(verbose)
  1660.         fputs("\
  1661. Type y or SP to mark all articles as read.\n\
  1662. Type n to leave articles marked as they are.\n\
  1663. Type u to mark everything read and unsubscribe.\n\
  1664. ",stdout) FLUSH;
  1665.         ELSE
  1666. #endif
  1667. #ifdef TERSE
  1668.         fputs("\
  1669. y or SP to mark all read.\n\
  1670. n to forget it.\n\
  1671. u to mark all and unsubscribe.\n\
  1672. ",stdout) FLUSH;
  1673. #endif
  1674.         goto reask_catchup;
  1675.     }
  1676.     else if (*buf == 'n' || *buf == 'q') {
  1677.         return AS_ASK;
  1678.     }
  1679.     else if (*buf != 'y' && *buf != 'u') {
  1680.         fputs(hforhelp,stdout) FLUSH;
  1681.         settle_down();
  1682.         goto reask_catchup;
  1683.     }
  1684.     for (i = firstart; i <= lastart; i++) {
  1685.         oneless(i);        /* mark as read */
  1686.     }
  1687. #ifdef DELAYMARK
  1688.     if (dmfp)
  1689.         yankback();
  1690. #endif
  1691.     if (*buf == 'u') {
  1692.         rcchar[ng] = NEGCHAR;
  1693.         return AS_CLEAN;
  1694.     }
  1695.     art = lastart+1;
  1696.     forcelast = FALSE;
  1697.     return AS_NORM;
  1698.     case 'Q':
  1699.     exit_code = NG_ASK;
  1700.     /* FALL THROUGH */
  1701.     case 'q':            /* go back up to newsgroup level? */
  1702.     return AS_CLEAN;
  1703.     case 'j':
  1704.     putchar('\n') FLUSH;
  1705.     if (art <= lastart)
  1706.         mark_as_read(art);
  1707.     return AS_ASK;
  1708.     case 'h': {            /* help? */
  1709.     int cmd;
  1710.  
  1711.     if ((cmd = help_art()) > 0)
  1712.         pushchar(cmd);
  1713.     return AS_ASK;
  1714.     }
  1715.     case '&':
  1716.     if (switcheroo()) /* get rest of command */
  1717.         return AS_INP;    /* if rubbed out, try something else */
  1718.     return AS_ASK;
  1719.     case '#':
  1720. #ifdef VERBOSE
  1721.     IF(verbose)
  1722.         printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
  1723.     ELSE
  1724. #endif
  1725. #ifdef TERSE
  1726.         printf("\n%ld\n",(long)lastart) FLUSH;
  1727. #endif
  1728.     return AS_ASK;
  1729.     case '=': {
  1730.     char tmpbuf[256];
  1731.     ART_NUM oldart = art;
  1732.     int cmd;
  1733.     char *subjline = getval("SUBJLINE",Nullch);
  1734. #ifndef CACHESUBJ
  1735.     char *s;
  1736. #endif
  1737.     
  1738.     page_init();
  1739. #ifdef CACHESUBJ
  1740.     if (!subj_list)
  1741.         fetchsubj(art,TRUE,FALSE);
  1742. #endif
  1743.     for (i=firstart; i<=lastart && !int_count; i++) {
  1744. #ifdef CACHESUBJ
  1745.         if (!was_read(i) &&
  1746.           (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
  1747.           *subj_list[OFFSET(i)] ) {
  1748.         sprintf(tmpbuf,"%5ld ", i);
  1749.         if (subjline) {
  1750.             art = i;
  1751.             interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  1752.         }
  1753.         else
  1754.             safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
  1755.             (sizeof tmpbuf) - 6);
  1756.         if (cmd = print_lines(tmpbuf,NOMARKING)) {
  1757.             if (cmd > 0)
  1758.             pushchar(cmd);
  1759.             break;
  1760.         }
  1761.         }
  1762. #else
  1763.         if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
  1764.         sprintf(tmpbuf,"%5ld ", i);
  1765.         if (subjline) {    /* probably fetches it again! */
  1766.             art = i;
  1767.             interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  1768.         }
  1769.         else
  1770.             safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
  1771.         if (cmd = print_lines(tmpbuf,NOMARKING)) {
  1772.             if (cmd > 0)
  1773.             pushchar(cmd);
  1774.             break;
  1775.         }
  1776.         }
  1777. #endif
  1778.     }
  1779.     int_count = 0;
  1780.     art = oldart;
  1781.     return AS_ASK;
  1782.     }
  1783.     case '^':
  1784.     art = firstart;
  1785. #ifdef ARTSEARCH
  1786.     srchahead = 0;
  1787. #endif
  1788.     return AS_NORM;
  1789. #if defined(CACHESUBJ) && defined(DEBUGGING)
  1790.     case 'D':
  1791.     printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
  1792.     if (!subj_list)
  1793.         fetchsubj(art,TRUE,FALSE);
  1794.     if (subj_list != Null(char **)) {
  1795.         for (i=1; i<=lastart && !int_count; i++) {
  1796.         if (subj_list[OFFSET(i)])
  1797.             printf("%5ld %c %s\n",
  1798.             i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
  1799.         }
  1800.     }
  1801.     int_count = 0;
  1802.     return AS_ASK;
  1803. #endif
  1804.     case 'v':
  1805.     if (art <= lastart) {
  1806.         reread = TRUE;
  1807.         do_hiding = FALSE;
  1808.     }
  1809.     return AS_NORM;
  1810. #ifdef ROTATION
  1811.     case Ctl('x'):
  1812. #endif
  1813.     case Ctl('r'):
  1814. #ifdef ROTATION
  1815.     rotate = (*buf==Ctl('x'));
  1816. #endif
  1817.     if (art <= lastart)
  1818.         reread = TRUE;
  1819.     return AS_NORM;
  1820. #ifdef ROTATION
  1821.     case 'X':
  1822.     rotate = !rotate;
  1823.     /* FALL THROUGH */
  1824. #else
  1825.     case Ctl('x'):
  1826.     case 'x':
  1827.     case 'X':
  1828.     notincl("x");
  1829.     return AS_ASK;
  1830. #endif
  1831.     case 'l': case Ctl('l'):        /* refresh screen */
  1832.     if (art <= lastart) {
  1833.         reread = TRUE;
  1834.         clear();
  1835.         do_fseek = TRUE;
  1836.         artline = topline;
  1837.         if (artline < 0)
  1838.         artline = 0;
  1839.     }
  1840.     return AS_NORM;
  1841.     case 'b': case Ctl('b'):        /* back up a page */
  1842.     if (art <= lastart) {
  1843.         ART_LINE target;
  1844.  
  1845.         reread = TRUE;
  1846.         clear();
  1847.         do_fseek = TRUE;
  1848.         target = topline - (LINES - 2);
  1849.         artline = topline;
  1850.         if (artline > 0) do {
  1851.         artline--;
  1852.         } while (artline >= 0 && artline > target &&
  1853.         vrdary(artline-1) >= 0);
  1854.         topline = artline;
  1855.         if (artline < 0)
  1856.         artline = 0;
  1857.     }
  1858.     return AS_NORM;
  1859.     case '!':            /* shell escape */
  1860.     if (escapade())
  1861.         return AS_INP;
  1862.     return AS_ASK;
  1863.     case 'C': {
  1864.     cancel_article();
  1865.     return AS_ASK;
  1866.     }
  1867.     case 'R':
  1868.     case 'r': {            /* reply? */
  1869.     reply();
  1870.     return AS_ASK;
  1871.     }
  1872.     case 'F':
  1873.     case 'f': {            /* followup command */
  1874.     followup();
  1875.     forcegrow = TRUE;        /* recalculate lastart */
  1876.     return AS_ASK;
  1877.     }
  1878.     case '|':
  1879.     case 'w': case 'W':
  1880.     case 's': case 'S':        /* save command */
  1881.     if (save_article() == SAVE_ABORT)
  1882.         return AS_INP;
  1883.     return AS_ASK;
  1884. #ifdef DELAYMARK
  1885.     case 'Y':                /* yank back M articles */
  1886.     yankback();
  1887.     art = firstart;            /* from the beginning */
  1888.     return AS_NORM;            /* pretend nothing happened */
  1889. #endif
  1890. #ifdef STRICTCR
  1891.     case '\n':
  1892.     fputs(badcr,stdout) FLUSH;
  1893.     return AS_ASK;
  1894. #endif
  1895.     default:
  1896.     printf("\n%s",hforhelp) FLUSH;
  1897.     settle_down();
  1898.     return AS_ASK;
  1899.     }
  1900. }
  1901.  
  1902. #ifdef MAILCALL
  1903. /* see if there is any mail */
  1904.  
  1905. void
  1906. setmail()
  1907. {
  1908.     if (! (mailcount++)) {
  1909.     char *mailfile = filexp(getval("MAILFILE",MAILFILE));
  1910.     
  1911.     if (stat(mailfile,&filestat) < 0 || !filestat.st_size
  1912.         || filestat.st_atime > filestat.st_mtime)
  1913.         mailcall = nullstr;
  1914.     else
  1915.         mailcall = getval("MAILCALL","(Mail) ");
  1916.     }
  1917.     mailcount %= 10;            /* check every 10 articles */
  1918. }
  1919. #endif
  1920.  
  1921. void
  1922. setdfltcmd()
  1923. {
  1924.     if (toread[ng]) {
  1925. #ifdef ARTSEARCH
  1926.     if (srchahead)
  1927.         dfltcmd = "^Nnpq";
  1928.     else
  1929. #endif
  1930.         dfltcmd = "npq";
  1931.     }
  1932.     else {
  1933.     if (art > lastart)
  1934.         dfltcmd = "qnp";
  1935.     else
  1936.         dfltcmd = "npq";
  1937.     }
  1938. }
  1939.  
  1940. !STUFFY!FUNK!
  1941. echo Extracting rcln.c
  1942. cat >rcln.c <<'!STUFFY!FUNK!'
  1943. /* $Header: rcln.c,v 4.3.2.1 90/04/23 00:22:22 sob Exp $
  1944.  *
  1945.  * $Log:    rcln.c,v $
  1946.  * Revision 4.3.2.1  90/04/23  00:22:22  sob
  1947.  * Changed atoi to atol and fixed RCS information.
  1948.  * 
  1949.  * Revision 4.3.1.2  85/07/23  17:39:08  lwall
  1950.  * Oops, was freeing a static buf on -c in checkexpired.
  1951.  * 
  1952.  * Revision 4.3.1.1  85/05/10  11:37:08  lwall
  1953.  * Branch for patches.
  1954.  * 
  1955.  * Revision 4.3  85/05/01  11:45:36  lwall
  1956.  * Baseline for release with 4.3bsd.
  1957.  * 
  1958.  */
  1959.  
  1960. #include "EXTERN.h"
  1961. #include "common.h"
  1962. #include "util.h"
  1963. #include "rcstuff.h"
  1964. #include "ngdata.h"
  1965. #include "INTERN.h"
  1966. #include "rcln.h"
  1967.  
  1968. void
  1969. rcln_init()
  1970. {
  1971.     ;
  1972. }
  1973.  
  1974. #ifdef CATCHUP
  1975. void
  1976. catch_up(ngx)
  1977. NG_NUM ngx;
  1978. {
  1979.     char tmpbuf[128];
  1980.     char *tmpp;
  1981.     
  1982. #ifdef VERBOSE
  1983.     IF(verbose)
  1984.     printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
  1985.     ELSE
  1986. #endif
  1987. #ifdef TERSE
  1988.     fputs("\nMarked read\n",stdout) FLUSH;
  1989. #endif
  1990.     sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
  1991.     free(rcline[ngx]);
  1992.     rcline[ngx] = savestr(tmpbuf);
  1993.     tmpp = rcline[ngx] + rcnums[ngx] - 1;
  1994.     *tmpp = '\0';
  1995.     write_rc();
  1996. }
  1997. #endif
  1998.  
  1999. /* add an article number to a newsgroup, if it isn't already read */
  2000.  
  2001. int
  2002. addartnum(artnum,ngnam)
  2003. ART_NUM artnum;
  2004. char *ngnam;
  2005. {
  2006.     register NG_NUM ngnum = find_ng(ngnam);
  2007.     register char *s, *t, *maxt = Nullch;
  2008.     ART_NUM min = 0, max = -1, lastnum = 0;
  2009.     char *mbuf;
  2010.     bool morenum;
  2011.  
  2012.     if (!artnum)
  2013.     return 0;
  2014.     if (ngnum == nextrcline || !rcnums[ngnum])
  2015.                     /* not found in newsrc? */
  2016.     return 0;
  2017. #ifdef CACHEFIRST
  2018.     if (!abs1st[ngnum])
  2019. #else
  2020.     if (!toread[ngnum])
  2021. #endif
  2022.                     /* now is a good time to trim down */
  2023.     set_toread(ngnum);        /* the list due to expires if we */
  2024.                     /* have not yet. */
  2025. #ifdef DEBUGGING
  2026.     if (artnum > ngmax[ngnum] + 10    /* allow for incoming articles */
  2027.        ) {
  2028.     printf("\nCorrupt Xref line!!!  %ld --> %s(1..%ld)\n",
  2029.         artnum,ngnam,
  2030.         ngmax[ngnum]) FLUSH;
  2031.     paranoid = TRUE;        /* paranoia reigns supreme */
  2032.     return -1;            /* hope this was the first newsgroup */
  2033.     }
  2034. #endif
  2035.  
  2036.     if (toread[ngnum] == TR_BOGUS)
  2037.     return 0;
  2038. #ifdef DEBUGGING
  2039.     if (debug & DEB_XREF_MARKER) {
  2040.     printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  2041.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2042.     }
  2043. #endif
  2044.     s = rcline[ngnum] + rcnums[ngnum];
  2045.     while (*s == ' ') s++;        /* skip spaces */
  2046.     t = s;
  2047.     while (isdigit(*s) && artnum >= (min = atol(s))) {
  2048.                     /* while it might have been read */
  2049.     for (t = s; isdigit(*t); t++) ;    /* skip number */
  2050.     if (*t == '-') {        /* is it a range? */
  2051.         t++;            /* skip to next number */
  2052.         if (artnum <= (max = atol(t)))
  2053.         return 0;        /* it is in range => already read */
  2054.         lastnum = max;        /* remember it */
  2055.         maxt = t;            /* remember position in case we */
  2056.                     /* want to overwrite the max */
  2057.         while (isdigit(*t)) t++;    /* skip second number */
  2058.     }
  2059.     else {
  2060.         if (artnum == min)        /* explicitly a read article? */
  2061.         return 0;
  2062.         lastnum = min;        /* remember what the number was */
  2063.         maxt = Nullch;        /* last one was not a range */
  2064.     }
  2065.     while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  2066.     s = t;
  2067.     }
  2068.     
  2069.     /* we have not read it, so insert the article number before s */
  2070.     
  2071.     morenum = isdigit(*s);        /* will it need a comma after? */
  2072.     *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  2073.     mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
  2074.     strcpy(mbuf,rcline[ngnum]);        /* make new rc line */
  2075.     if (maxt && lastnum && artnum == lastnum+1)
  2076.                         /* can we just extend last range? */
  2077.     t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
  2078.     else {
  2079.     t = mbuf + (t-rcline[ngnum]);    /* point t into new line instead */
  2080.     if (lastnum) {            /* have we parsed any line? */
  2081.         if (!morenum)        /* are we adding to the tail? */
  2082.         *t++ = ',';        /* supply comma before */
  2083.         if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
  2084.                     /* adjacent singletons? */
  2085.         *(t-1) = '-';        /* turn them into a range */
  2086.     }
  2087.     }
  2088.     if (morenum) {            /* is there more to life? */
  2089.     if (min == artnum+1) {        /* can we consolidate further? */
  2090.         bool range_before = (*(t-1) == '-');
  2091.         bool range_after;
  2092.         char *nextmax;
  2093.  
  2094.         for (nextmax = s; isdigit(*nextmax); nextmax++) ;
  2095.         range_after = *nextmax++ == '-';
  2096.         
  2097.         if (range_before)
  2098.         *t = '\0';        /* artnum is redundant */
  2099.         else
  2100.         sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
  2101.         
  2102.         if (range_after)
  2103.         s = nextmax;        /* *s is redundant */
  2104.     /*  else
  2105.         s = s */        /* *s is new max */
  2106.     }
  2107.     else
  2108.         sprintf(t,"%ld,",(long)artnum);    /* put the number and comma */
  2109.     }
  2110.     else
  2111.     sprintf(t,"%ld",(long)artnum);    /* put the number there (wherever) */
  2112.     strcat(t,s);            /* copy remainder of line */
  2113. #ifdef DEBUGGING
  2114.     if (debug & DEB_XREF_MARKER) {
  2115.     printf("%s\n",mbuf) FLUSH;
  2116.     }
  2117. #endif
  2118.     free(rcline[ngnum]);
  2119.     rcline[ngnum] = mbuf;        /* pull the switcheroo */
  2120.     *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  2121.                     /* wipe out : or ! */
  2122.     if (toread[ngnum] > TR_NONE)    /* lest we turn unsub into bogus */
  2123.     --toread[ngnum];
  2124.     return 0;
  2125. }
  2126.  
  2127. #ifdef MCHASE
  2128. /* delete an article number from a newsgroup, if it is there */
  2129.  
  2130. void
  2131. subartnum(artnum,ngnam)
  2132. register ART_NUM artnum;
  2133. char *ngnam;
  2134. {
  2135.     register NG_NUM ngnum = find_ng(ngnam);
  2136.     register char *s, *t;
  2137.     register ART_NUM min, max;
  2138.     char *mbuf;
  2139.     int curlen;
  2140.  
  2141.     if (!artnum)
  2142.     return;
  2143.     if (ngnum == nextrcline || !rcnums[ngnum])
  2144.     return;                /* not found in newsrc? */
  2145. #ifdef DEBUGGING
  2146.     if (debug & DEB_XREF_MARKER) {
  2147.     printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  2148.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2149.     }
  2150. #endif
  2151.     s = rcline[ngnum] + rcnums[ngnum];
  2152.     while (*s == ' ') s++;        /* skip spaces */
  2153.     
  2154.     /* a little optimization, since it is almost always the last number */
  2155.     
  2156.     for (t=s; *t; t++) ;        /* find end of string */
  2157.     curlen = t-rcline[ngnum];
  2158.     for (t--; isdigit(*t); t--) ;    /* find previous delim */
  2159.     if (*t == ',' && atol(t+1) == artnum) {
  2160.     *t = '\0';
  2161.     if (toread[ngnum] >= TR_NONE)
  2162.         ++toread[ngnum];
  2163. #ifdef DEBUGGING
  2164.     if (debug & DEB_XREF_MARKER)
  2165.         printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
  2166. #endif
  2167.     return;
  2168.     }
  2169.  
  2170.     /* not the last number, oh well, we may need the length anyway */
  2171.  
  2172.     while (isdigit(*s) && artnum >= (min = atol(s))) {
  2173.                     /* while it might have been read */
  2174.     for (t = s; isdigit(*t); t++) ;    /* skip number */
  2175.     if (*t == '-') {        /* is it a range? */
  2176.         t++;            /* skip to next number */
  2177.         max = atol(t);
  2178.         while (isdigit(*t)) t++;    /* skip second number */
  2179.         if (artnum <= max) {
  2180.                     /* it is in range => already read */
  2181.         if (artnum == min) {
  2182.             min++;
  2183.             artnum = 0;
  2184.         }
  2185.         else if (artnum == max) {
  2186.             max--;
  2187.             artnum = 0;
  2188.         }
  2189.         *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  2190.         mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
  2191.         *s = '\0';
  2192.         strcpy(mbuf,rcline[ngnum]);    /* make new rc line */
  2193.         s = mbuf + (s-rcline[ngnum]);
  2194.                     /* point s into mbuf now */
  2195.         if (artnum) {        /* split into two ranges? */
  2196.             prange(s,min,artnum-1);
  2197.             s += strlen(s);
  2198.             *s++ = ',';
  2199.             prange(s,artnum+1,max);
  2200.         }
  2201.         else            /* only one range */
  2202.             prange(s,min,max);
  2203.         s += strlen(s);
  2204.         strcpy(s,t);        /* copy remainder over */
  2205. #ifdef DEBUGGING
  2206.         if (debug & DEB_XREF_MARKER) {
  2207.             printf("%s\n",mbuf) FLUSH;
  2208.         }
  2209. #endif
  2210.         free(rcline[ngnum]);
  2211.         rcline[ngnum] = mbuf;    /* pull the switcheroo */
  2212.         *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  2213.                     /* wipe out : or ! */
  2214.         if (toread[ngnum] >= TR_NONE)
  2215.             ++toread[ngnum];
  2216.         return;
  2217.         }
  2218.     }
  2219.     else {
  2220.         if (artnum == min) {    /* explicitly a read article? */
  2221.         if (*t == ',')        /* pick a comma, any comma */
  2222.             t++;
  2223.         else if (s[-1] == ',')
  2224.             s--;
  2225.         else if (s[-2] == ',')    /* (in case of space) */
  2226.             s -= 2;
  2227.         strcpy(s,t);        /* no need to realloc */
  2228.         if (toread[ngnum] >= TR_NONE)
  2229.             ++toread[ngnum];
  2230. #ifdef DEBUGGING
  2231.         if (debug & DEB_XREF_MARKER) {
  2232.             printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  2233.               rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2234.         }
  2235. #endif
  2236.         return;
  2237.         }
  2238.     }
  2239.     while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  2240.     s = t;
  2241.     }
  2242. }
  2243.  
  2244. void
  2245. prange(where,min,max)
  2246. char *where;
  2247. ART_NUM min,max;
  2248. {
  2249.     if (min == max)
  2250.     sprintf(where,"%ld",(long)min);
  2251.     else
  2252.     sprintf(where,"%ld-%ld",(long)min,(long)max);
  2253. }
  2254. #endif
  2255.  
  2256. /* calculate the number of unread articles for a newsgroup */
  2257.  
  2258. void
  2259. set_toread(ngnum)
  2260. register NG_NUM ngnum;
  2261. {
  2262.     register char *s, *c, *h;
  2263.     char tmpbuf[64], *mybuf = tmpbuf;
  2264.     char *nums;
  2265.     int length;
  2266. #ifdef CACHEFIRST
  2267.     bool virgin_ng = (!abs1st[ngnum]);
  2268. #endif
  2269.     ART_NUM ngsize = getngsize(ngnum);
  2270.     ART_NUM unread = ngsize;
  2271.     ART_NUM newmax;
  2272.  
  2273. #ifdef DEBUGGING
  2274.     ngmax[ngnum] = ngsize;        /* for checking out-of-range Xrefs */
  2275. #endif
  2276.     if (ngsize == TR_BOGUS) {
  2277.     printf("Warning!  Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
  2278.     paranoid = TRUE;
  2279.     toread[ngnum] = TR_BOGUS;
  2280.     return;
  2281.     }
  2282. #ifdef CACHEFIRST
  2283.     if (virgin_ng)
  2284. #else
  2285.     if (!toread[ngnum])
  2286. #endif
  2287.     {
  2288.     sprintf(tmpbuf," 1-%ld",(long)ngsize);
  2289.     if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
  2290.         checkexpired(ngnum,ngsize);    /* this might realloc rcline */
  2291.     }
  2292.     nums = rcline[ngnum]+rcnums[ngnum];
  2293.     length = strlen(nums);
  2294.     if (length >= 60)
  2295.     mybuf = safemalloc((MEM_SIZE)(length+5));
  2296.     strcpy(mybuf,nums);
  2297.     mybuf[length++] = ',';
  2298.     mybuf[length] = '\0';
  2299.     for (s = mybuf; isspace(*s); s++)
  2300.         ;
  2301.     for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
  2302.                     /* for each range */
  2303.     *c = '\0';            /* keep index from running off */
  2304.     if ((h = index(s,'-')) != Nullch)    /* find - in range, if any */
  2305.         unread -= (newmax = atol(h+1)) - atol(s) + 1;
  2306.     else if (newmax = atol(s))
  2307.         unread--;        /* recalculate length */
  2308.     if (newmax > ngsize) {    /* paranoia check */
  2309.         unread = -1;
  2310.         break;
  2311.     }
  2312.     }
  2313.     if (unread >= 0)        /* reasonable number? */
  2314.     toread[ngnum] = (ART_UNREAD)unread;
  2315.                     /* remember how many are left */
  2316.     else {                /* SOMEONE RESET THE NEWSGROUP!!! */
  2317.     toread[ngnum] = (ART_UNREAD)ngsize;
  2318.                     /* assume nothing carried over */
  2319.     printf("Warning!  Somebody reset %s--assuming nothing read.\n",
  2320.         rcline[ngnum]) FLUSH;
  2321.     *(rcline[ngnum] + rcnums[ngnum]) = '\0';
  2322.     paranoid = TRUE;        /* enough to make a guy paranoid */
  2323.     }
  2324.     if (mybuf != tmpbuf)
  2325.     free(mybuf);
  2326.     if (rcchar[ngnum] == NEGCHAR)
  2327.     toread[ngnum] = TR_UNSUB;
  2328. }
  2329.  
  2330. /* make sure expired articles are marked as read */
  2331.  
  2332. void
  2333. checkexpired(ngnum,ngsize)
  2334. register NG_NUM ngnum;
  2335. ART_NUM ngsize;
  2336. {
  2337.     register ART_NUM a1st = getabsfirst(ngnum,ngsize);
  2338.     register char *s, *t;
  2339.     register ART_NUM num, lastnum = 0;
  2340.     char *mbuf, *newnum;
  2341.  
  2342.     if (a1st<=1)
  2343.     return;
  2344. #ifdef DEBUGGING
  2345.     if (debug & DEB_XREF_MARKER) {
  2346.     printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
  2347.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2348.     }
  2349. #endif
  2350.     for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
  2351.     while (*s && (num = atol(s)) <= a1st) {
  2352.     while (isdigit(*s)) s++;
  2353.     while (*s && !isdigit(*s)) s++;
  2354.     lastnum = num;
  2355.     }
  2356.     if (*s) {
  2357.     if (s[-1] == '-') {            /* landed in a range? */
  2358.         if (lastnum != 1) {
  2359.         if (3 + strlen(s) > strlen(rcline[ngnum]+rcnums[ngnum])) {
  2360.             mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + 3 +
  2361.             strlen(s) + 1));
  2362.             strcpy(mbuf, rcline[ngnum]);
  2363.             sprintf(mbuf+rcnums[ngnum]," 1-%s",s);
  2364.             free(rcline[ngnum]);
  2365.             rcline[ngnum] = mbuf;
  2366.         } else {
  2367.             sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
  2368.         }
  2369.         }
  2370.         goto ret;
  2371.     }
  2372.     }
  2373.     /* s now points to what should follow first range */
  2374.     if (s - rcline[ngnum] > rcnums[ngnum] + 10) 
  2375.     mbuf = rcline[ngnum];
  2376.     else {
  2377.     mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
  2378.     strcpy(mbuf,rcline[ngnum]);
  2379.     }
  2380.     newnum = t = mbuf+rcnums[ngnum];
  2381.     sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
  2382.     if (*s) {
  2383.     t += strlen(t);
  2384.     *t++ = ',';
  2385.     strcpy(t,s);
  2386.     }
  2387.     if (!checkflag && mbuf == rcline[ngnum]) {
  2388.     rcline[ngnum] = saferealloc(rcline[ngnum],
  2389.         (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
  2390.     }
  2391.     else {
  2392.     if (!checkflag)
  2393.         free(rcline[ngnum]);
  2394.     rcline[ngnum] = mbuf;
  2395.     }
  2396.  
  2397. ret:;        /* semicolon in case DEBUGGING undefined */
  2398. #ifdef DEBUGGING
  2399.     if (debug & DEB_XREF_MARKER) {
  2400.     printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  2401.       rcline[ngnum] + rcnums[ngnum]) FLUSH;
  2402.     }
  2403. #endif
  2404. }
  2405.  
  2406. !STUFFY!FUNK!
  2407. echo Extracting ngstuff.h
  2408. cat >ngstuff.h <<'!STUFFY!FUNK!'
  2409. /* $Header: ngstuff.h,v 4.3 85/05/01 11:45:12 lwall Exp $
  2410.  *
  2411.  * $Log:    ngstuff.h,v $
  2412.  * Revision 4.3  85/05/01  11:45:12  lwall
  2413.  * Baseline for release with 4.3bsd.
  2414.  * 
  2415.  */
  2416.  
  2417. #define NN_NORM 0
  2418. #define NN_INP 1
  2419. #define NN_REREAD 2
  2420. #define NN_ASK 3
  2421.  
  2422. void    ngstuff_init();
  2423. int    escapade();
  2424. int    switcheroo();
  2425. int    numnum();
  2426. int    perform();
  2427. !STUFFY!FUNK!
  2428. echo ""
  2429. echo "End of kit 3 (of 9)"
  2430. cat /dev/null >kit3isdone
  2431. config=true
  2432. for iskit in 1 2 3 4 5 6 7 8 9 ; do
  2433.     if test -f kit${iskit}isdone; then
  2434.     echo "You have run kit ${iskit}."
  2435.     else
  2436.     echo "You still need to run kit ${iskit}."
  2437.     config=false
  2438.     fi
  2439. done
  2440. case $config in
  2441.     true)
  2442.     echo "You have run all your kits.  Please read README and then type Configure."
  2443.     chmod 755 Configure
  2444.     ;;
  2445. esac
  2446. : I do not append .signature, but someone might mail this.
  2447. exit
  2448.