home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume1 / rn / part03 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  61.8 KB

  1. Date: Tue, 7 May 85 13:43:09 pdt
  2. From: allegra!sdcrdcf!RDCF.SDC.UUCP!lwall (Larry Wall)
  3. Newsgroups: mod.sources
  4. Subject: rn version 4.3 (kit 3 of 9)
  5. Reply-To: lwall@sdcrdcf.UUCP
  6. Organization: System Development Corporation R&D, Santa Monica
  7.  
  8. #! /bin/sh
  9.  
  10. # Make a new directory for the rn sources, cd to it, and run kits 1 thru 9 
  11. # through sh.  When all 9 kits have been run, read README.
  12.  
  13. echo "This is rn kit 3 (of 9).  If kit 3 is complete, the line"
  14. echo '"'"End of kit 3 (of 9)"'" will echo at the end.'
  15. echo ""
  16. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  17. echo Extracting intrp.c
  18. cat >intrp.c <<'!STUFFY!FUNK!'
  19. /* $Header: intrp.c,v 4.3 85/05/01 11:40:54 lwall Exp $
  20.  *
  21.  * $Log:    intrp.c,v $
  22.  * Revision 4.3  85/05/01  11:40:54  lwall
  23.  * Baseline for release with 4.3bsd.
  24.  * 
  25.  */
  26.  
  27. #include "EXTERN.h"
  28. #include "common.h"
  29. #include "util.h"
  30. #include "search.h"
  31. #include "head.h"
  32. #include "rn.h"
  33. #include "artsrch.h"
  34. #include "ng.h"
  35. #include "util.h"
  36. #include "respond.h"
  37. #include "rcstuff.h"
  38. #include "bits.h"
  39. #include "artio.h"
  40. #include "term.h"
  41. #include "final.h"
  42. #include "INTERN.h"
  43. #include "intrp.h"
  44.  
  45. char orgname[] = ORGNAME;
  46.  
  47. /* name of this site */
  48. #ifdef GETHOSTNAME
  49.     char *hostname;
  50. #   undef SITENAME
  51. #   define SITENAME hostname
  52. #else !GETHOSTNAME
  53. #   ifdef DOUNAME
  54. #    include <sys/utsname.h>
  55.     struct utsname uts;
  56. #    undef SITENAME
  57. #    define SITENAME uts.nodename
  58. #   else !DOUNAME
  59. #    ifdef PHOSTNAME
  60.         char *hostname;
  61. #        undef SITENAME
  62. #        define SITENAME hostname
  63. #    else !PHOSTNAME
  64. #        ifdef WHOAMI
  65. #        undef SITENAME
  66. #        define SITENAME sysname
  67. #        endif WHOAMI
  68. #    endif PHOSTNAME
  69. #   endif DOUNAME
  70. #endif GETHOSTNAME
  71.  
  72. #ifdef TILDENAME
  73. static char *tildename = Nullch;
  74. static char *tildedir = Nullch;
  75. #endif
  76.  
  77. char *realname INIT(Nullch);    /* real name of sender from /etc/passwd */
  78.  
  79. char *dointerp();
  80. char *getrealname();
  81. #ifdef CONDSUB
  82. char *skipinterp();
  83. #endif
  84.  
  85. static void abort_interp();
  86.  
  87. void
  88. intrp_init(tcbuf)
  89. char *tcbuf;
  90. {
  91.     char *getlogin();
  92.  
  93.     spool = savestr(filexp(SPOOL));    /* usually /usr/spool/news */
  94.     
  95.     getwd(tcbuf);            /* find working directory name */
  96.     origdir = savestr(tcbuf);        /* and remember it */
  97.     
  98.     /* get environmental stuff */
  99.  
  100.     /* get home directory */
  101.  
  102.     homedir = getenv("HOME");
  103.     if (homedir == Nullch)
  104.     homedir = getenv("LOGDIR");
  105.  
  106.     dotdir = getval("DOTDIR",homedir);
  107.  
  108.     /* get login name */
  109.  
  110.     logname = getenv("USER");
  111.     if (logname == Nullch)
  112.     logname = getenv("LOGNAME");
  113. #ifdef GETLOGIN
  114.     if (logname == Nullch)
  115.     logname = savestr(getlogin());
  116. #endif
  117.  
  118.     /* get the real name of the person (%N) */
  119.     /* Must be done after logname is read in because BERKNAMES uses that */
  120.  
  121.     strcpy(tcbuf,getrealname(getuid()));
  122.     realname = savestr(tcbuf);
  123.  
  124.     /* name of header file (%h) */
  125.  
  126.     headname = savestr(filexp(HEADNAME));
  127.  
  128.     /* name of this site (%H) */
  129.  
  130. #ifdef GETHOSTNAME
  131.     gethostname(buf,sizeof buf);
  132.     hostname = savestr(buf);
  133. #else
  134. #ifdef DOUNAME
  135.     /* get sysname */
  136.     uname(&uts);
  137. #else
  138. #ifdef PHOSTNAME
  139.     {
  140.     FILE *popen();
  141.     FILE *pipefp = popen(PHOSTNAME,"r");
  142.     
  143.     if (pipefp == Nullfp) {
  144.         printf("Can't find hostname\n");
  145.         sig_catcher(0);
  146.     }
  147.     fgets(buf,sizeof buf,pipefp);
  148.     buf[strlen(buf)-1] = '\0';    /* wipe out newline */
  149.     hostname = savestr(buf);
  150.     pclose(pipefp);
  151.     }
  152. #endif
  153. #endif
  154. #endif
  155.     sitename = savestr(SITENAME);
  156. }
  157.  
  158. /* expand filename via %, ~, and $ interpretation */
  159. /* returns pointer to static area */
  160. /* Note that there is a 1-deep cache of ~name interpretation */
  161.  
  162. char *
  163. filexp(s)
  164. register char *s;
  165. {
  166.     static char filename[CBUFLEN];
  167.     char scrbuf[CBUFLEN];
  168.     register char *d;
  169.  
  170. #ifdef DEBUGGING
  171.     if (debug & DEB_FILEXP)
  172.     printf("< %s\n",s) FLUSH;
  173. #endif
  174.     interp(filename, (sizeof filename), s);            /* interpret any % escapes */
  175. #ifdef DEBUGGING
  176.     if (debug & DEB_FILEXP)
  177.     printf("%% %s\n",filename) FLUSH;
  178. #endif
  179.     s = filename;
  180.     if (*s == '~') {    /* does destination start with ~? */
  181.     if (!*(++s) || *s == '/') {
  182.         sprintf(scrbuf,"%s%s",homedir,s);
  183.                 /* swap $HOME for it */
  184. #ifdef DEBUGGING
  185.     if (debug & DEB_FILEXP)
  186.     printf("~ %s\n",scrbuf) FLUSH;
  187. #endif
  188.         strcpy(filename,scrbuf);
  189.     }
  190.     else {
  191. #ifdef TILDENAME
  192.         for (d=scrbuf; isalnum(*s); s++,d++)
  193.         *d = *s;
  194.         *d = '\0';
  195.         if (tildedir && strEQ(tildename,scrbuf)) {
  196.         strcpy(scrbuf,tildedir);
  197.         strcat(scrbuf, s);
  198.         strcpy(filename, scrbuf);
  199. #ifdef DEBUGGING
  200.         if (debug & DEB_FILEXP)
  201.             printf("r %s %s\n",tildename,tildedir) FLUSH;
  202. #endif
  203.         }
  204.         else {
  205.         if (tildename) {
  206.             free(tildename);
  207.             free(tildedir);
  208.         }
  209.         tildedir = Nullch;
  210.         tildename = savestr(scrbuf);
  211. #ifdef GETPWENT        /* getpwnam() is not the paragon of efficiency */
  212.         {
  213.             struct passwd *getpwnam();
  214.             struct passwd *pwd = getpwnam(tildename);
  215.  
  216.             sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
  217.             tildedir = savestr(pwd->pw_dir);
  218. #ifdef NEWSADMIN
  219.             if (strEQ(newsadmin,tildename))
  220.             newsuid = atoi(pwd->pw_uid);
  221. #endif
  222.             strcpy(filename,scrbuf);
  223. #ifdef GETPWENT
  224.             endpwent();
  225. #endif
  226.         }
  227. #else            /* this will run faster, and is less D space */
  228.         {    /* just be sure LOGDIRFIELD is correct */
  229.             FILE *pfp = fopen("/etc/passwd","r");
  230.             char tmpbuf[512];
  231.             int i;
  232.             
  233.             if (pfp == Nullfp) {
  234.             printf(cantopen,"passwd") FLUSH;
  235.             sig_catcher(0);
  236.             }
  237.             while (fgets(tmpbuf,512,pfp) != Nullch) {
  238.             d = cpytill(scrbuf,tmpbuf,':');
  239. #ifdef DEBUGGING
  240.             if (debug & DEB_FILEXP)
  241.                 printf("p %s\n",tmpbuf) FLUSH;
  242. #endif
  243.             if (strEQ(scrbuf,tildename)) {
  244. #ifdef NEWSADMIN
  245.                 if (strEQ(newsadmin,tildename))
  246.                 newsuid = atoi(index(d,':')+1);
  247. #endif
  248.                 for (i=LOGDIRFIELD-2; i; i--) {
  249.                 if (d)
  250.                     d = index(d+1,':');
  251.                 }
  252.                 if (d) {
  253.                 cpytill(scrbuf,d+1,':');
  254.                 tildedir = savestr(scrbuf);
  255.                 strcat(scrbuf,s);
  256.                 strcpy(filename,scrbuf);
  257.                 }
  258.                 break;
  259.             }
  260.             }
  261.             fclose(pfp);
  262.         }
  263. #endif
  264.         }
  265. #else !TILDENAME
  266. #ifdef VERBOSE
  267.         IF(verbose)
  268.         fputs("~loginname not implemented.\n",stdout) FLUSH;
  269.         ELSE
  270. #endif
  271. #ifdef TERSE
  272.         fputs("~login not impl.\n",stdout) FLUSH;
  273. #endif
  274. #endif
  275.     }
  276.     }
  277.     else if (*s == '$') {    /* starts with some env variable? */
  278.     d = scrbuf;
  279.     *d++ = '%';
  280.     if (s[1] == '{')
  281.         strcpy(d,s+2);
  282.     else {
  283.         *d++ = '{';
  284.         for (s++; isalnum(*s); s++) *d++ = *s;
  285.                 /* skip over token */
  286.         *d++ = '}';
  287.         strcpy(d,s);
  288.     }
  289. #ifdef DEBUGGING
  290.     if (debug & DEB_FILEXP)
  291.         printf("$ %s\n",scrbuf) FLUSH;
  292. #endif
  293.     interp(filename, (sizeof filename), scrbuf);
  294.                     /* this might do some extra '%'s but */
  295.                     /* that is how the Mercedes Benz */
  296.     }
  297. #ifdef DEBUGGING
  298.     if (debug & DEB_FILEXP)
  299.     printf("> %s\n",filename) FLUSH;
  300. #endif
  301.     return filename;
  302. }
  303.  
  304. #ifdef CONDSUB
  305. /* skip interpolations */
  306.  
  307. char *
  308. skipinterp(pattern,stoppers)
  309. register char *pattern;
  310. char *stoppers;
  311. {
  312.  
  313.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  314. #ifdef DEBUGGING
  315.     if (debug & 8)
  316.         printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
  317. #endif
  318.     if (*pattern == '%' && pattern[1]) {
  319.         switch (*++pattern) {
  320.         case '{':
  321.         for (pattern++; *pattern && *pattern != '}'; pattern++)
  322.             if (*pattern == '\\')
  323.             pattern++;
  324.         break;
  325.         case '[':
  326.         for (pattern++; *pattern && *pattern != ']'; pattern++)
  327.             if (*pattern == '\\')
  328.             pattern++;
  329.         break;
  330. #ifdef CONDSUB
  331.         case '(': {
  332.         pattern = skipinterp(pattern+1,"!=");
  333.         if (!*pattern)
  334.             goto getout;
  335.         for (pattern++; *pattern && *pattern != '?'; pattern++)
  336.             if (*pattern == '\\')
  337.             pattern++;
  338.         if (!*pattern)
  339.             goto getout;
  340.         pattern = skipinterp(pattern+1,":)");
  341.         if (*pattern == ':')
  342.             pattern = skipinterp(pattern+1,")");
  343.         break;
  344.         }
  345. #endif
  346. #ifdef BACKTICK
  347.         case '`': {
  348.         pattern = skipinterp(pattern+1,"`");
  349.         break;
  350.         }
  351. #endif
  352. #ifdef PROMPTTTY
  353.         case '"':
  354.         pattern = skipinterp(pattern+1,"\"");
  355.         break;
  356. #endif
  357.         default:
  358.         break;
  359.         }
  360.         pattern++;
  361.     }
  362.     else {
  363.         if (*pattern == '^' && pattern[1])
  364.         pattern += 2;
  365.         else if (*pattern == '\\' && pattern[1])
  366.         pattern += 2;
  367.         else
  368.         pattern++;
  369.     }
  370.     }
  371. getout:
  372.     return pattern;            /* where we left off */
  373. }
  374. #endif
  375.  
  376. /* interpret interpolations */
  377.  
  378. char *
  379. dointerp(dest,destsize,pattern,stoppers)
  380. register char *dest;
  381. register int destsize;
  382. register char *pattern;
  383. char *stoppers;
  384. {
  385.     char *subj_buf = Nullch;
  386.     char *ngs_buf = Nullch;
  387.     char *refs_buf = Nullch;
  388.     char *artid_buf = Nullch;
  389.     char *reply_buf = Nullch;
  390.     char *from_buf = Nullch;
  391.     char *path_buf = Nullch;
  392.     char *follow_buf = Nullch;
  393.     char *dist_buf = Nullch;
  394.     char *line_buf = Nullch;
  395.     register char *s, *h;
  396.     register int i;
  397.     char scrbuf[512];
  398.     bool upper = FALSE;
  399.     bool lastcomp = FALSE;
  400.     int metabit = 0;
  401.  
  402.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  403. #ifdef DEBUGGING
  404.     if (debug & 8)
  405.         printf("dointerp till %s at %s\n",stoppers?stoppers:"",pattern);
  406. #endif
  407.     if (*pattern == '%' && pattern[1]) {
  408.         upper = FALSE;
  409.         lastcomp = FALSE;
  410.         for (s=Nullch; !s; ) {
  411.         switch (*++pattern) {
  412.         case '^':
  413.             upper = TRUE;
  414.             break;
  415.         case '_':
  416.             lastcomp = TRUE;
  417.             break;
  418.         case '/':
  419. #ifdef ARTSRCH
  420.             s = scrbuf;
  421.             if (!index("/?g",pattern[-2]))
  422.             *s++ = '/';
  423.             strcpy(s,lastpat);
  424.             s += strlen(s);
  425.             if (pattern[-2] != 'g') {
  426.             if (index("/?",pattern[-2]))
  427.                 *s++ = pattern[-2];
  428.             else
  429.                 *s++ = '/';
  430.             if (art_howmuch == 1)
  431.                 *s++ = 'h';
  432.             else if (art_howmuch == 2)
  433.                 *s++ = 'a';
  434.             if (art_doread)
  435.                 *s++ = 'r';
  436.             }
  437.             *s = '\0';
  438.             s = scrbuf;
  439. #else
  440.             s = nullstr;
  441. #endif
  442.             break;
  443.         case '{':
  444.             pattern = cpytill(scrbuf,pattern+1,'}');
  445.             if (s = index(scrbuf,'-'))
  446.             *s++ = '\0';
  447.             else
  448.             s = nullstr;
  449.             s = getval(scrbuf,s);
  450.             break;
  451.         case '[':
  452.             pattern = cpytill(scrbuf,pattern+1,']');
  453.             i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
  454.             if (line_buf)
  455.             free(line_buf);
  456.             s = line_buf = fetchlines(art,i);
  457.             break;
  458. #ifdef CONDSUB
  459.         case '(': {
  460.             COMPEX *oldbra_compex = bra_compex;
  461.             COMPEX cond_compex;
  462.             char rch;
  463.             bool matched;
  464.             
  465.             init_compex(&cond_compex);
  466.             pattern = dointerp(dest,destsize,pattern+1,"!=");
  467.             rch = *pattern;
  468.             if (rch == '!')
  469.             pattern++;
  470.             if (*pattern != '=')
  471.             goto getout;
  472.             pattern = cpytill(scrbuf,pattern+1,'?');
  473.             if (!*pattern)
  474.             goto getout;
  475.             if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
  476.             printf("%s: %s\n",scrbuf,s) FLUSH;
  477.             pattern += strlen(pattern);
  478.             goto getout;
  479.             }
  480.             matched = (execute(&cond_compex,dest) != Nullch);
  481.             if (cond_compex.nbra)    /* were there brackets? */
  482.             bra_compex = &cond_compex;
  483.             if (matched==(rch == '=')) {
  484.             pattern = dointerp(dest,destsize,pattern+1,":)");
  485.             if (*pattern == ':')
  486.                 pattern = skipinterp(pattern+1,")");
  487.             }
  488.             else {
  489.             pattern = skipinterp(pattern+1,":)");
  490.             if (*pattern == ':')
  491.                 pattern++;
  492.             pattern = dointerp(dest,destsize,pattern,")");
  493.             }
  494.             s = dest;
  495.             bra_compex = oldbra_compex;
  496.             free_compex(&cond_compex);
  497.             break;
  498.         }
  499. #endif
  500. #ifdef BACKTICK
  501.         case '`': {
  502.             FILE *pipefp, *popen();
  503.  
  504.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
  505.             pipefp = popen(scrbuf,"r");
  506.             if (pipefp != Nullfp) {
  507.             int len;
  508.  
  509.             len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
  510.                 pipefp);
  511.             scrbuf[len] = '\0';
  512.             pclose(pipefp);
  513.             }
  514.             else {
  515.             printf("\nCan't run %s\n",scrbuf);
  516.             *scrbuf = '\0';
  517.             }
  518.             for (s=scrbuf; *s; s++) {
  519.             if (*s == '\n') {
  520.                 if (s[1])
  521.                 *s = ' ';
  522.                 else
  523.                 *s = '\0';
  524.             }
  525.             }
  526.             s = scrbuf;
  527.             break;
  528.         }
  529. #endif
  530. #ifdef PROMPTTTY
  531.         case '"':
  532.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
  533.             fputs(scrbuf,stdout) FLUSH;
  534.             resetty();
  535.             gets(scrbuf);
  536.             noecho();
  537.             crmode();
  538.             s = scrbuf;
  539.             break;
  540. #endif
  541.         case '~':
  542.             s = homedir;
  543.             break;
  544.         case '.':
  545.             s = dotdir;
  546.             break;
  547.         case '$':
  548.             s = scrbuf;
  549.             sprintf(s,"%d",getpid());
  550.             break;
  551.         case '0': case '1': case '2': case '3': case '4':
  552.         case '5': case '6': case '7': case '8': case '9':
  553. #ifdef CONDSUB
  554.             s = getbracket(bra_compex,*pattern - '0');
  555. #else
  556.             s = nullstr;
  557. #endif
  558.             break;
  559.         case 'a':
  560.             s = scrbuf;
  561.             sprintf(s,"%ld",(long)art);
  562.             break;
  563.         case 'A':
  564. #ifdef LINKART
  565.             s = linkartname;    /* so Eunice people get right file */
  566. #else
  567.             s = scrbuf;
  568.             sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
  569. #endif
  570.             break;
  571.         case 'b':
  572.             s = savedest;
  573.             break;
  574.         case 'B':
  575.             s = scrbuf;
  576.             sprintf(s,"%ld",(long)savefrom);
  577.             break;
  578.         case 'c':
  579.             s = ngdir;
  580.             break;
  581.         case 'C':
  582.             s = ngname;
  583.             break;
  584.         case 'd':
  585.             s = scrbuf;
  586.             sprintf(s,"%s/%s",spool,ngdir);
  587.             break;
  588.         case 'D':
  589.             s = dist_buf = fetchlines(art,DIST_LINE);
  590.             break;
  591.         case 'f':            /* from line */
  592. #ifdef ASYNC_PARSE
  593.             parse_maybe(art);
  594. #endif
  595.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  596.                         /* was there a reply line? */
  597.             if (!(s=reply_buf))
  598.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  599.             }
  600.             else if (!(s = from_buf))
  601.             s = from_buf = fetchlines(art,FROM_LINE);
  602.             break;
  603.         case 'F':
  604. #ifdef ASYNC_PARSE
  605.             parse_maybe(art);
  606. #endif
  607.             if (htype[FOLLOW_LINE].ht_minpos >= 0)
  608.                     /* is there a Followup-To line? */
  609.             s = follow_buf = fetchlines(art,FOLLOW_LINE);
  610.             else {
  611.             int off;
  612.         
  613.             s = ngs_buf = fetchlines(art,NGS_LINE);
  614.             if (h = instr(s,"net.general")) {
  615.                 off = h-s;
  616.                 strncpy(scrbuf,s,off+4);
  617.                 strcpy(scrbuf+off+4,"followup");
  618.                 safecpy(scrbuf+off+12,h+11,sizeof(scrbuf));
  619.                 s = scrbuf;
  620.             }
  621.             }
  622.             break;
  623.         case 'h':            /* header file name */
  624.             s = headname;
  625.             break;
  626.         case 'H':            /* host name */
  627.             s = sitename;
  628.             break;
  629.         case 'i':
  630.             if (!(s=artid_buf))
  631.             s = artid_buf = fetchlines(art,MESSID_LINE);
  632.             if (*s != '<') {
  633.             sprintf(scrbuf,"<%s>",artid_buf);
  634.             s = scrbuf;
  635.             }
  636.             break;
  637.         case 'I':            /* ref article indicator */
  638.             s = scrbuf;
  639.             sprintf(scrbuf,"'%s'",indstr);
  640.             break;
  641.         case 'l':            /* rn library */
  642. #ifdef NEWSADMIN
  643.             s = newsadmin;
  644. #else
  645.             s = "???";
  646. #endif
  647.             break;
  648.         case 'L':            /* login id */
  649.             s = logname;
  650.             break;
  651.         case 'm':        /* current mode */
  652.             s = scrbuf;
  653.             *s = mode;
  654.             s[1] = '\0';
  655.             break;
  656.         case 'M':
  657. #ifdef DELAYMARK
  658.             sprintf(scrbuf,"%ld",(long)dmcount);
  659.             s = scrbuf;
  660. #else
  661.             s = nullstr;
  662. #endif
  663.             break;
  664.         case 'n':            /* newsgroups */
  665.             s = ngs_buf = fetchlines(art,NGS_LINE);
  666.             break;
  667.         case 'N':            /* full name */
  668.             s = getval("NAME",realname);
  669.             break;
  670.         case 'o':            /* organization */
  671.             s = getval("ORGANIZATION",orgname);
  672. #ifdef ORGFILE
  673.             if (*s == '/') {
  674.             FILE *ofp = fopen(s,"r");
  675.  
  676.             if (ofp) {
  677.                 fgets(scrbuf,sizeof scrbuf,ofp);
  678.                 fclose(ofp);
  679.                 s = scrbuf;
  680.                 s[strlen(s)-1] = '\0';
  681.             }
  682.             }
  683. #endif
  684.             break;
  685.         case 'O':
  686.             s = origdir;
  687.             break;
  688.         case 'p':
  689.             s = cwd;
  690.             break;
  691.         case 'P':
  692.             s = spool;
  693.             break;
  694.         case 'r':
  695. #ifdef ASYNC_PARSE
  696.             parse_maybe(art);
  697. #endif
  698.             if (htype[REFS_LINE].ht_minpos >= 0) {
  699.             refs_buf = fetchlines(art,REFS_LINE);
  700.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  701.             }
  702.             else
  703.             *scrbuf = '\0';
  704.             s = rindex(scrbuf,'<');
  705.             break;
  706.         case 'R':
  707. #ifdef ASYNC_PARSE
  708.             parse_maybe(art);
  709. #endif
  710.             if (htype[REFS_LINE].ht_minpos >= 0) {
  711.             refs_buf = fetchlines(art,REFS_LINE);
  712.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  713.             }
  714.             else
  715.             *scrbuf = '\0';
  716.             if (!artid_buf)
  717.             artid_buf = fetchlines(art,MESSID_LINE);
  718.             if (artid_buf[0] == '<')
  719.             safecat(scrbuf,artid_buf,sizeof(scrbuf));
  720.             else {
  721.             char tmpbuf[64];
  722.     
  723.             sprintf(tmpbuf,"<%s>",artid_buf);
  724.             safecat(scrbuf,tmpbuf,sizeof(scrbuf));
  725.             }
  726.             s = scrbuf;
  727.             break;
  728.         case 's':
  729.             if (!(s=subj_buf))
  730.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  731.                         /* get subject handy */
  732.             while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  733.                         /* skip extra Re: */
  734.             s += 3;
  735.             if (*s == ' ')
  736.                 s++;
  737.             }
  738.             if (h = instr(s,"- (nf"))
  739.             *h = '\0';
  740.             break;
  741.         case 'S':
  742.             if (!(s=subj_buf))
  743.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  744.                         /* get subject handy */
  745.             if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  746.                         /* skip extra Re: */
  747.             s += 3;
  748.             if (*s == ' ')
  749.                 s++;
  750.             }
  751.             break;
  752.         case 't':
  753.         case 'T':
  754. #ifdef ASYNC_PARSE
  755.             parse_maybe(art);
  756. #endif
  757.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  758.                     /* was there a reply line? */
  759.             if (!(s=reply_buf))
  760.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  761.             }
  762.             else if (!(s = from_buf))
  763.             s = from_buf = fetchlines(art,FROM_LINE);
  764.             if (*pattern == 'T') {
  765.             if (htype[PATH_LINE].ht_minpos >= 0) {
  766.                     /* should we substitute path? */
  767.                 s = path_buf = fetchlines(art,PATH_LINE);
  768.             }
  769.             i = strlen(sitename);
  770.             if (strnEQ(sitename,s,i) && s[i] == '!')
  771.                 s += i + 1;
  772.             }
  773.             if ((h=index(s,'(')) != Nullch)
  774.                         /* strip garbage from end */
  775.             *(h-1) = '\0';
  776.             else if ((h=index(s,'<')) != Nullch) {
  777.                         /* or perhaps from beginning */
  778.             s = h+1;
  779.             if ((h=index(s,'>')) != Nullch)
  780.                 *h = '\0';
  781.             }
  782.             break;
  783.         case 'u':
  784.             sprintf(scrbuf,"%ld",(long)toread[ng]);
  785.             s = scrbuf;
  786.             break;
  787.         case 'U':
  788.             sprintf(scrbuf,"%ld",
  789.             (long)(((ART_NUM)toread[ng]) - 1 + was_read(art)));
  790.             s = scrbuf;
  791.             break;
  792.         case 'x':            /* news library */
  793.             s = lib;
  794.             break;
  795.         case 'X':            /* rn library */
  796.             s = rnlib;
  797.             break;
  798.         case 'z':
  799. #ifdef LINKART
  800.             s = linkartname;    /* so Eunice people get right file */
  801. #else
  802.             s = scrbuf;
  803.             sprintf(s,"%ld",(long)art);
  804. #endif
  805.             if (stat(s,&filestat) < 0)
  806.             filestat.st_size = 0L;
  807.             sprintf(scrbuf,"%5ld",(long)filestat.st_size);
  808.             s = scrbuf;
  809.             break;
  810.         default:
  811.             if (--destsize <= 0)
  812.             abort_interp();
  813.             *dest++ = *pattern | metabit;
  814.             s = nullstr;
  815.             break;
  816.         }
  817.         }
  818.         if (!s)
  819.         s = nullstr;
  820.         pattern++;
  821.         if (upper || lastcomp) {
  822.         char *t;
  823.  
  824.         if (s != scrbuf) {
  825.             safecpy(scrbuf,s,(sizeof scrbuf));
  826.             s = scrbuf;
  827.         }
  828.         if (upper || !(t=rindex(s,'/')))
  829.             t = s;
  830.         while (*t && !isalpha(*t))
  831.             t++;
  832.         if (islower(*t))
  833.             *t = toupper(*t);
  834.         }
  835.         i = metabit;        /* maybe get into register */
  836.         if (s == dest) {
  837.         while (*dest) {
  838.             if (--destsize <= 0)
  839.             abort_interp();
  840.             *dest++ |= i;
  841.         }
  842.         }
  843.         else {
  844.         while (*s) {
  845.             if (--destsize <= 0)
  846.             abort_interp();
  847.             *dest++ = *s++ | i;
  848.         }
  849.         }
  850.     }
  851.     else {
  852.         if (--destsize <= 0)
  853.         abort_interp();
  854.         if (*pattern == '^' && pattern[1]) {
  855.         ++pattern;            /* skip uparrow */
  856.         i = *pattern;        /* get char into a register */
  857.         if (i == '?')
  858.             *dest++ = '\177' | metabit;
  859.         else if (i == '(') {
  860.             metabit = 0200;
  861.             destsize++;
  862.         }
  863.         else if (i == ')') {
  864.             metabit = 0;
  865.             destsize++;
  866.         }
  867.         else
  868.             *dest++ = i & 037 | metabit;
  869.         pattern++;
  870.         }
  871.         else if (*pattern == '\\' && pattern[1]) {
  872.         ++pattern;            /* skip backslash */
  873.         i = *pattern;        /* get char into a register */
  874.     
  875.         /* this used to be a switch but the if may save space */
  876.         
  877.         if (i >= '0' && i <= '7') {
  878.             i = 1;
  879.             while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
  880.             i <<= 3;
  881.             i += *pattern++ - '0';
  882.             }
  883.             *dest++ = i & 0377 | metabit;
  884.             --pattern;
  885.         }
  886.         else if (i == 'b')
  887.             *dest++ = '\b' | metabit;
  888.         else if (i == 'f')
  889.             *dest++ = '\f' | metabit;
  890.         else if (i == 'n')
  891.             *dest++ = '\n' | metabit;
  892.         else if (i == 'r')
  893.             *dest++ = '\r' | metabit;
  894.         else if (i == 't')
  895.             *dest++ = '\t' | metabit;
  896.         else
  897.             *dest++ = i | metabit;
  898.         pattern++;
  899.         }
  900.         else
  901.         *dest++ = *pattern++ | metabit;
  902.     }
  903.     }
  904.     *dest = '\0';
  905. getout:
  906.     if (subj_buf != Nullch)    /* return any checked out storage */
  907.     free(subj_buf);
  908.     if (ngs_buf != Nullch)
  909.     free(ngs_buf);
  910.     if (refs_buf != Nullch)
  911.     free(refs_buf);
  912.     if (artid_buf != Nullch)
  913.     free(artid_buf);
  914.     if (reply_buf != Nullch)
  915.     free(reply_buf);
  916.     if (from_buf != Nullch)
  917.     free(from_buf);
  918.     if (path_buf != Nullch)
  919.     free(path_buf);
  920.     if (follow_buf != Nullch)
  921.     free(follow_buf);
  922.     if (dist_buf != Nullch)
  923.     free(dist_buf);
  924.     if (line_buf != Nullch)
  925.     free(line_buf);
  926.     return pattern;            /* where we left off */
  927. }
  928.  
  929. void
  930. interp(dest,destsize,pattern)
  931. char *dest;
  932. int destsize;
  933. char *pattern;
  934. {
  935.     dointerp(dest,destsize,pattern,Nullch);
  936. #ifdef DEBUGGING
  937.     if (debug & DEB_FILEXP)
  938.     fputs(dest,stdout);
  939. #endif
  940. }
  941.  
  942. /* copy a references line, normalizing as we go */
  943.  
  944. void
  945. refscpy(dest,destsize,src)
  946. register char *dest, *src;
  947. register int destsize;
  948. {
  949.     register char *dot, *at, *beg;
  950.     char tmpbuf[64];
  951.     
  952.     while (*src) {
  953.     if (*src != '<') {
  954.         if (--destsize <= 0)
  955.         break;
  956.         *dest++ = '<';
  957.         at = dot = Nullch;
  958.         beg = src;
  959.         while (*src && *src != ' ' && *src != ',') {
  960.         if (*src == '.')
  961.             dot = src;
  962.         else if (*src == '@')
  963.             at = src;
  964.         if (--destsize <= 0)
  965.             break;
  966.         *dest++ = *src++;
  967.         }
  968.         if (destsize <= 0)
  969.         break;
  970.         if (dot && !at) {
  971.         int len;
  972.  
  973.         *dest = *dot++ = '\0';
  974.         sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
  975.         len = strlen(tmpbuf);
  976.         if (destsize > len) {
  977.             strcpy(dest,tmpbuf);
  978.             dest = dest + len;
  979.             destsize -= len;
  980.         }
  981.         }
  982.         if (--destsize <= 0)
  983.         break;
  984.         *dest++ = '>';
  985.     }
  986.     else {
  987.         while (*src && --destsize > 0 && (*dest++ = *src++) != '>') ;
  988.         if (destsize <= 0)
  989.         break;
  990.     }
  991.     while (*src == ' ' || *src == ',') src++;
  992.     if (*src && --destsize > 0)
  993.         *dest++ = ' ';
  994.     }
  995.     *dest = '\0';
  996.  
  997. /* get the person's real name from /etc/passwd */
  998. /* (string is overwritten, so it must be copied) */
  999.  
  1000. char *
  1001. getrealname(uid)
  1002. int uid;
  1003. {
  1004.     char *s, *c;
  1005.  
  1006. #ifdef PASSNAMES
  1007. #ifdef GETPWENT
  1008.     struct passwd *pwd = getpwuid(uid);
  1009.     
  1010.     s = pwd->pw_gcos;
  1011. #else
  1012.     char tmpbuf[512];
  1013.     int i;
  1014.  
  1015.     getpw(uid, tmpbuf);
  1016.     for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
  1017.     if (s)
  1018.         s = index(s,':')+1;
  1019.     }
  1020.     if (!s)
  1021.     return nullstr;
  1022.     cpytill(tmpbuf,s,':');
  1023.     s = tmpbuf;
  1024. #endif
  1025. #ifdef BERKNAMES
  1026. #ifdef BERKJUNK
  1027.     while (*s && !isalnum(*s) && *s != '&') s++;
  1028. #endif
  1029.     if ((c = index(s, ',')) != Nullch)
  1030.     *c = '\0';
  1031.     if ((c = index(s, ';')) != Nullch)
  1032.     *c = '\0';
  1033.     s = cpytill(buf,s,'&');
  1034.     if (*s == '&') {            /* whoever thought this one up was */
  1035.     strcat(buf,logname);        /* in the middle of the night */
  1036.     strcat(buf,s+1);        /* before the morning after */
  1037.     if (islower(*buf))
  1038.         *buf = toupper(*buf);    /* gack and double gack */
  1039.     }
  1040. #else
  1041.     if ((c = index(s, '(')) != Nullch)
  1042.     *c = '\0';
  1043.     if ((c = index(s, '-')) != Nullch)
  1044.     s = c;
  1045.     strcpy(buf,tmpbuf);
  1046. #endif
  1047. #ifdef GETPWENT
  1048.     endpwent();
  1049. #endif
  1050.     return buf;                /* return something static */
  1051. #else
  1052.     if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
  1053.     fgets(buf,sizeof buf,tmpfp);
  1054.     fclose(tmpfp);
  1055.     buf[strlen(buf)-1] = '\0';
  1056.     return buf;
  1057.     }
  1058.     return "PUT YOUR NAME HERE";
  1059. #endif
  1060. }
  1061.  
  1062. static void
  1063. abort_interp()
  1064. {
  1065.     fputs("\n% interp buffer overflow!\n",stdout) FLUSH;
  1066.     sig_catcher(0);
  1067. }
  1068. !STUFFY!FUNK!
  1069. echo Extracting common.h
  1070. cat >common.h <<'!STUFFY!FUNK!'
  1071. /* $Header: common.h,v 4.3 85/05/01 11:37:11 lwall Exp $
  1072.  * 
  1073.  * $Log:    common.h,v $
  1074.  * Revision 4.3  85/05/01  11:37:11  lwall
  1075.  * Baseline for release with 4.3bsd.
  1076.  * 
  1077.  */
  1078.  
  1079. #include "config.h"    /* generated by installation script */
  1080. #ifdef WHOAMI
  1081. #    include <whoami.h>
  1082. #endif
  1083.  
  1084. #include <stdio.h>
  1085. #include <sys/types.h>
  1086. #include <sys/stat.h>
  1087. #include <ctype.h>
  1088.  
  1089. #ifndef isalnum
  1090. #   define isalnum(c) (isalpha(c) || isdigit(c))
  1091. #endif
  1092.  
  1093. #include <errno.h>
  1094. #include <signal.h>
  1095. #ifdef IOCTL
  1096. #include <sys/ioctl.h>
  1097. #endif IOCTL
  1098.  
  1099. #ifdef FCNTL
  1100. #   include <fcntl.h>
  1101. #endif
  1102.  
  1103. #ifdef TERMIO
  1104. #   include <termio.h>
  1105. #else
  1106. #   include <sgtty.h>
  1107. #endif
  1108.  
  1109. #ifdef GETPWENT
  1110. #   include <pwd.h>
  1111. #endif
  1112.  
  1113. #define BITSPERBYTE 8
  1114. #define LBUFLEN 512    /* line buffer length */
  1115.             /* (don't worry, .newsrc lines can exceed this) */
  1116. #ifdef pdp11
  1117. #   define CBUFLEN 256    /* command buffer length */
  1118. #   define PUSHSIZE 128
  1119. #else
  1120. #   define CBUFLEN 512    /* command buffer length */
  1121. #   define PUSHSIZE 256
  1122. #endif
  1123. #ifdef pdp11
  1124. #   define MAXFILENAME 128
  1125. #else
  1126. #   define MAXFILENAME 512
  1127. #endif
  1128. #define LONGKEY 15    /* longest keyword: currently "posting-version" */
  1129. #define FINISHCMD 0177
  1130.  
  1131. /* some handy defs */
  1132.  
  1133. #define bool char
  1134. #define TRUE (1)
  1135. #define FALSE (0)
  1136. #define Null(t) ((t)0)
  1137. #define Nullch Null(char *)
  1138. #define Nullfp Null(FILE *)
  1139.  
  1140. #define Ctl(ch) (ch & 037)
  1141.  
  1142. #define strNE(s1,s2) (strcmp(s1,s2))
  1143. #define strEQ(s1,s2) (!strcmp(s1,s2))
  1144. #define strnNE(s1,s2,l) (strncmp(s1,s2,l))
  1145. #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
  1146.  
  1147. /* Things we can figure out ourselves */
  1148.  
  1149. #ifdef SIGTSTP
  1150. #   define BERKELEY     /* include job control signals? */
  1151. #endif
  1152.  
  1153. #ifdef SIGPROF
  1154. #   define BSD42        /* do we have Berkeley 4.2? */
  1155. #endif
  1156.  
  1157. #ifdef FIONREAD
  1158. #   define PENDING
  1159. #else
  1160. #   ifdef O_NDELAY
  1161. #    define PENDING
  1162. #   endif
  1163. #endif
  1164.  
  1165. #ifdef EUNICE
  1166. #   define LINKART        /* add 1 level of possible indirection */
  1167. #   define UNLINK(victim) while (!unlink(victim))
  1168. #else
  1169. #   define UNLINK(victim) unlink(victim)
  1170. #endif
  1171.  
  1172. /* Valid substitutions for strings marked with % comment are:
  1173.  *    %a    Current article number
  1174.  *    %A    Full name of current article (%P/%c/%a)
  1175.  *        (if LINKART defined, is the name of the real article)
  1176.  *    %b    Destination of a save command, a mailbox or command
  1177.  *    %B    The byte offset to the beginning of the article for saves
  1178.  *        with or without the header
  1179.  *    %c    Current newsgroup, directory form
  1180.  *    %C    Current newsgroup, dot form
  1181.  *    %d    %P/%c
  1182.  *    %D    Old Distribution: line
  1183.  *    %f    Old From: line or Reply-To: line
  1184.  *    %F    Newsgroups to followup to from Newsgroups: and Followup-To:
  1185.  *    %h    Name of header file to pass to mail or news poster
  1186.  *    %H    Host name (yours)
  1187.  *    %i    Old Message-I.D.: line, with <>
  1188.  *    %I    Inclusion indicator
  1189.  *    %l    News administrator login name
  1190.  *    %L    Login name (yours)
  1191.  *    %M    Number of articles markd with M
  1192.  *    %n    Newsgroups from source article
  1193.  *    %N    Full name (yours)
  1194.  *    %o    Organization (yours)
  1195.  *    %O    Original working directory (where you ran rn from)
  1196.  *    %p    Your private news directory (-d switch)
  1197.  *    %P    Public news spool directory (SPOOLDIR)
  1198.  *    %r    Last reference (parent article id)
  1199.  *    %R    New references list
  1200.  *    %s    Subject, with all Re's and (nf)'s stripped off
  1201.  *    %S    Subject, with one Re stripped off
  1202.  *    %t    New To: line derived from From: and Reply-To (Internet always)
  1203.  *    %T    New To: line derived from Path:
  1204.  *    %u    Number of unread articles
  1205.  *    %U    Number of unread articles disregarding current article
  1206.  *    %x    News library directory, usually /usr/lib/news
  1207.  *    %X    Rn library directory, usually %x/rn
  1208.  *    %z    Size of current article in bytes.
  1209.  *    %~    Home directory
  1210.  *    %.    Directory containing . files
  1211.  *    %$    current process number
  1212.  *    %{name} Environment variable "name".  %{name-default} form allowed.
  1213.  *    %[name]    Header line beginning with "Name: ", without "Name: " 
  1214.  *    %"prompt"
  1215.  *        Print prompt and insert what is typed.
  1216.  *    %`command`
  1217.  *        Insert output of command.
  1218.  *    %(test_text=pattern?if_text:else_text)
  1219.  *        Substitute if_text if test_text matches pattern, otherwise
  1220.  *        substitute else_text.  Use != for negated match.
  1221.  *        % substitutions are done on test_text, if_text, and else_text.
  1222.  *        (Note: %() only works if CONDSUB defined.)
  1223.  *    %digit    Substitute the text matched by the nth bracket in the last
  1224.  *        pattern that had brackets.  %0 matches the last bracket
  1225.  *        matched, in case you had alternatives.
  1226.  *
  1227.  *    Put ^ in the middle to capitalize the first letter: %^C = Net.jokes
  1228.  *    Put _ in the middle to capitalize last component: %_c = net/Jokes
  1229.  *
  1230.  *    ~ interpretation in filename expansion happens after % expansion, so
  1231.  *    you could put ~%{NEWSLOGNAME-news} and it will expand correctly.
  1232.  */
  1233.  
  1234. /* *** System Dependent Stuff *** */
  1235.  
  1236. /* NOTE: many of these are defined in the config.h file */
  1237.  
  1238. /* name of organization */
  1239. #ifndef ORGNAME
  1240. #   define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota"
  1241. #endif
  1242.  
  1243. #ifndef MBOXCHAR
  1244. #   define MBOXCHAR 'F'    /* how to recognize a mailbox by 1st char */
  1245. #endif
  1246.  
  1247. #ifndef ROOTID
  1248. #   define ROOTID 0        /* uid of superuser */
  1249. #endif
  1250.  
  1251. #ifdef NORMSIG
  1252. #   define sigset signal
  1253. #   define sigignore(sig) signal(sig,SIG_IGN)
  1254. #endif
  1255.  
  1256. #ifndef LOGDIRFIELD
  1257. #   define LOGDIRFIELD 6        /* Which field (origin 1) is the */
  1258.                     /* login directory in /etc/passwd? */
  1259.                     /* (If it is not kept in passwd, */
  1260.                     /* but getpwnam() returns it, */
  1261.                     /* define the symbol GETPWENT) */
  1262. #endif
  1263. #ifndef GCOSFIELD
  1264. #   define GCOSFIELD 5
  1265. #endif
  1266.  
  1267. #ifndef NEGCHAR
  1268. #   define NEGCHAR '!'
  1269. #endif
  1270.  
  1271. /* Space conservation section */
  1272.  
  1273. /* To save D space, cut down size of MAXRCLINE, NGMAX, VARYSIZE. */
  1274. #define MAXRCLINE 500    /* number of lines allowed in .newsrc */
  1275.             /* several parallel arrays affected. */
  1276.             /* (You can have more lines in the active file, */
  1277.             /* just not in the .newsrc) */
  1278. #define HASHSIZ 547    /* should be prime, and at least MAXRCLINE + 10% */
  1279. #define NGMAX 100    /* number of newsgroups allowed on command line */
  1280.             /* undefine ONLY symbol to disable "only" feature */
  1281. #define VARYSIZE 256    /* this makes a block 1024 bytes long in DECville */
  1282.             /* (used by virtual array routines) */
  1283.  
  1284. /* Undefine any of the following features to save both I and D space */
  1285. /* In general, earlier ones are easier to get along without */
  1286. /* Pdp11's without split I and D may have to undefine them all */
  1287. #define DEBUGGING    /* include debugging code */
  1288. #define PUSHBACK    /* macros and keymaps using pushback buffer */
  1289. #define SPEEDOVERMEM    /* use more memory to run faster */
  1290. #define WORDERASE    /* enable ^W to erase a word */
  1291. #define MAILCALL    /* check periodically for mail */
  1292. #define CLEAREOL    /* use clear to end-of-line instead of clear screen */
  1293. #define NOFIREWORKS    /* keep whole screen from flashing on certain */
  1294.             /* terminals such as older Televideos */
  1295. #define VERIFY        /* echo the command they just typed */
  1296. #define HASHNG        /* hash newsgroup lines for fast lookup-- */
  1297.             /* linear search used if not defined */
  1298. #define CONDSUB        /* allow %(cond?text:text) */
  1299. #define BACKTICK    /* allow %`command` */
  1300. #define PROMPTTTY    /* allow %"prompt" */
  1301. #define ULSMARTS    /* catch _^H in text and do underlining */
  1302. #define TERMMOD        /* allow terminal type modifier on switches */
  1303. #define BAUDMOD        /* allow baudrate modifier on switches */
  1304. #define GETLOGIN    /* use getlogin() routine as backup to environment */
  1305.             /* variables USER or LOGNAME */
  1306. #define ORGFILE        /* if organization begins with /, look up in file */
  1307. #define TILDENAME    /* allow ~logname expansion */
  1308. #define SETENV        /* allow command line environment variable setting */
  1309. #define GETWD        /* use our getwd() instead of piped in pwd */
  1310. #ifndef BSD42        /* 4.2 sites should just use groups for this */
  1311. #define SETUIDGID    /* substitute eaccess() for access() so that rn */
  1312.             /* can run setuid or setgid */
  1313.             /* if not setuid or setgid, you don't need it */
  1314. #endif
  1315. #define MAKEDIR        /* use our makedir() instead of shell script */
  1316. #define MEMHELP        /* keep help messages in memory */
  1317. #define VERBOSE        /* compile in more informative messages */
  1318. #define TERSE        /* compile in shorter messages */
  1319.             /* (Note: both VERBOSE and TERSE can be defined; -t
  1320.              * sets terse mode.  One or the other MUST be defined.
  1321.              */
  1322. #ifndef pdp11
  1323. #   define CACHESUBJ    /* cache subject lines in memory */
  1324.             /* without this ^N still works but runs really slow */
  1325.             /* but you save lots and lots of D space */
  1326. #   define CACHEFIRST    /* keep absolute first article numbers in memory */
  1327.             /* cost: about 2k */
  1328. #endif
  1329. #define ROTATION    /* enable x, X and ^X commands to work */
  1330. #define DELBOGUS    /* ask if bogus newsgroups should be deleted */
  1331. #define RELOCATE    /* allow newsgroup rearranging */
  1332. #define ESCSUBS        /* escape substitutions in multi-character commands */
  1333. #define DELAYMARK    /* allow articles to be temporarily marked as read */
  1334.             /* until exit from current newsgroup or Y command */
  1335. #define MCHASE        /* unmark xrefed articles on m or M */
  1336. #define MUNGHEADER    /* allow alternate header formatting via */
  1337.             /* environment variable ALTHEADER (not impl) */
  1338. #define ASYNC_PARSE    /* allow parsing headers asyncronously to reading */
  1339.             /* used by MCHASE and MUNGHEADER */
  1340. #define FINDNEWNG    /* check for new newsgroups on startup */
  1341. #define FASTNEW        /* do optimizations on FINDNEWNG for faster startup */
  1342.             /* (this optimization can make occasional mistakes */
  1343.             /* if a group is removed and another group of the */
  1344.             /* same length is added, and if no softpointers are */
  1345.             /* affected by said change.) */
  1346. #define INNERSEARCH    /* search command 'g' with article */
  1347. #define CATCHUP        /* catchup command at newsgroup level */
  1348. #define NGSEARCH    /* newsgroup pattern matching */
  1349. #define ONLY        /* newsgroup restrictions by pattern */
  1350. #define KILLFILES    /* automatic article killer files */
  1351. #define ARTSEARCH    /* pattern searches among articles */
  1352.             /* /, ?, ^N, ^P, k, K */
  1353.  
  1354. /* some dependencies among options */
  1355.  
  1356. #ifndef ARTSEARCH
  1357. #   undef KILLFILES
  1358. #   undef INNERSEARCH
  1359. #   undef CACHESUBJ
  1360. #endif
  1361.  
  1362. #ifndef DELAYMARK
  1363. #   ifndef MCHASE
  1364. #    ifndef MUNGHEADER
  1365. #        undef ASYNC_PARSE
  1366. #    endif
  1367. #   endif
  1368. #endif
  1369.  
  1370. #ifndef SETUIDGID
  1371. #   define eaccess access
  1372. #endif
  1373.  
  1374. #ifdef ONLY                /* idiot lint doesn't grok #if */
  1375. #   define NGSORONLY
  1376. #else
  1377. #   ifdef NGSEARCH
  1378. #    define NGSORONLY
  1379. #   endif
  1380. #endif
  1381.  
  1382. #ifdef VERBOSE
  1383. #   ifdef TERSE
  1384. #    define IF(c) if (c)
  1385. #    define ELSE else
  1386. #   else !TERSE
  1387. #    define IF(c)
  1388. #    define ELSE
  1389. #   endif
  1390. #else !VERBOSE
  1391. #   ifndef TERSE
  1392. #    define TERSE
  1393. #   endif
  1394. #   define IF(c) "IF" outside of VERBOSE???
  1395. #   define ELSE "ELSE" outside of VERBOSE???
  1396. #endif
  1397.  
  1398. #ifdef DEBUGGING
  1399. #   define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\n", __FILE__, __LINE__);sig_catcher(0);}}
  1400. #else
  1401. #   define assert(ex) ;
  1402. #endif
  1403.  
  1404. #ifdef SPEEDOVERMEM
  1405. #   define OFFSET(x) (x)
  1406. #else
  1407. #   define OFFSET(x) ((x)-absfirst)
  1408. #endif
  1409.  
  1410. /* If you're strapped for space use the help messages in shell scripts */
  1411. /* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */
  1412. #ifdef MEMHELP  /* undef MEMHELP above to get them all as sh scripts */
  1413. #   undef NGHELP
  1414. #   undef ARTHELP
  1415. #   undef PAGERHELP
  1416. #   undef SUBSHELP
  1417. #else
  1418. #   ifndef NGHELP            /* % and ~ */
  1419. #    define NGHELP "%X/ng.help"
  1420. #   endif
  1421. #   ifndef ARTHELP            /* % and ~ */
  1422. #    define ARTHELP "%X/art.help"
  1423. #   endif
  1424. #   ifndef PAGERHELP        /* % and ~ */
  1425. #    define PAGERHELP "%X/pager.help"
  1426. #   endif
  1427. #   ifndef SUBSHELP        /* % and ~ */
  1428. #    define SUBSHELP "%X/subs.help"
  1429. #   endif
  1430. #endif
  1431.  
  1432. #ifdef CLEAREOL
  1433. #   define TCSIZE 512    /* capacity for termcap strings */
  1434. #else
  1435. #   ifdef pdp11
  1436. #    define TCSIZE 256    /* capacity for termcap strings */
  1437. #   else
  1438. #    define TCSIZE 512    /* capacity for termcap srings */
  1439. #   endif
  1440. #endif
  1441.  
  1442. /* Additional ideas:
  1443.  *    Make the do_newsgroup() routine a separate process.
  1444.  *    Keep .newsrc on disk instead of in memory.
  1445.  *    Overlays, if you have them.
  1446.  *    Get a bigger machine.
  1447.  */
  1448.  
  1449. /* End of Space Conservation Section */
  1450.  
  1451. /* More System Dependencies */
  1452.  
  1453. /* news library */
  1454. #ifndef LIB        /* ~ and %l only ("~%l" is permissable) */
  1455. #   define LIB "/usr/lib/news"
  1456. #endif
  1457.  
  1458. /* path to private executables */
  1459. #ifndef RNLIB        /* ~, %x and %l only */
  1460. #   define RNLIB "%x/rn"
  1461. #endif
  1462.  
  1463. /* system-wide RNINIT switches */
  1464. #ifndef GLOBINIT
  1465. #   define GLOBINIT "%X/INIT"
  1466. #endif
  1467.  
  1468. /* where to find news files */
  1469. #ifndef SPOOL            /* % and ~ */
  1470. #   define SPOOL "/usr/spool/news"
  1471. #endif
  1472.  
  1473. /* file containing list of active newsgroups and max article numbers */
  1474. #ifndef ACTIVE            /* % and ~ */
  1475. #   define ACTIVE "%x/active"
  1476. #endif
  1477.  
  1478. /* location of history file */
  1479. #ifndef ARTFILE            /* % and ~ */
  1480. #    define ARTFILE "%x/history"
  1481. #endif
  1482.  
  1483. /* command to setup a new .newsrc */
  1484. #ifndef NEWSETUP        /* % and ~ */
  1485. #   define NEWSETUP "newsetup"
  1486. #endif
  1487.  
  1488. /* command to display a list of un-subscribed-to newsgroups */
  1489. #ifndef NEWSGROUPS        /* % and ~ */
  1490. #   define NEWSGROUPS "newsgroups"
  1491. #endif
  1492.  
  1493. /* preferred shell for use in doshell routine */
  1494. /*  ksh or sh would be okay here */
  1495. #ifndef PREFSHELL
  1496. #   define PREFSHELL "/bin/csh"
  1497. #endif
  1498.  
  1499. /* path to fastest starting shell */
  1500. #ifndef SH
  1501. #   define SH "/bin/sh"
  1502. #endif
  1503.  
  1504. /* path to default editor */
  1505. #ifndef DEFEDITOR
  1506. #   define DEFEDITOR "/usr/ucb/vi"
  1507. #endif
  1508.  
  1509. /* location of macro file */
  1510. #ifndef RNMACRO
  1511. #   ifdef PUSHBACK
  1512. #    define RNMACRO "%./.rnmac"
  1513. #   endif
  1514. #endif
  1515.  
  1516. /* location of full name */
  1517. #ifndef FULLNAMEFILE
  1518. #   ifndef PASSNAMES
  1519. #    define FULLNAMEFILE "%./.fullname"
  1520. #   endif
  1521. #endif
  1522.  
  1523. /* virtual array file name template */
  1524. #ifndef VARYNAME        /* % and ~ */
  1525. #   define VARYNAME "/tmp/rnvary.%$"
  1526. #endif
  1527.  
  1528. /* file to pass header to followup article poster */
  1529. #ifndef HEADNAME        /* % and ~ */
  1530. #   define HEADNAME "%./.rnhead"
  1531. /* or alternately #define HEADNAME "/tmp/rnhead.%$" */
  1532. #endif
  1533.  
  1534. #ifndef MAKEDIR
  1535. /* shell script to make n-deep subdirectories */
  1536. #   ifndef DIRMAKER        /* % and ~ */
  1537. #    define DIRMAKER "%X/makedir"
  1538. #   endif
  1539. #endif
  1540.  
  1541. /* location of newsrc file */
  1542. #ifndef RCNAME        /* % and ~ */
  1543. #   define RCNAME "%./.newsrc"
  1544. #endif
  1545.  
  1546. /* temporary newsrc file in case we crash while writing out */
  1547. #ifndef RCTNAME        /* % and ~ */
  1548. #   define RCTNAME "%./.newnewsrc"
  1549. #endif
  1550.  
  1551. /* newsrc file at the beginning of this session */
  1552. #ifndef RCBNAME        /* % and ~ */
  1553. #   define RCBNAME "%./.oldnewsrc"
  1554. #endif
  1555.  
  1556. /* if existent, contains process number of current or crashed rn */
  1557. #ifndef LOCKNAME        /* % and ~ */
  1558. #   define LOCKNAME "%./.rnlock"
  1559. #endif
  1560.  
  1561. /* information from last invocation of rn */
  1562. #ifndef LASTNAME        /* % and ~ */
  1563. #   define LASTNAME "%./.rnlast"
  1564. #endif
  1565.  
  1566. /* file with soft pointers into the active file */
  1567. #ifndef SOFTNAME        /* % and ~ */
  1568. #   define SOFTNAME "%./.rnsoft"
  1569. #endif
  1570.  
  1571. /* list of article numbers to mark as unread later (see M and Y cmmands) */
  1572. #ifndef RNDELNAME        /* % and ~ */
  1573. #   define RNDELNAME "%./.rndelay"
  1574. #endif
  1575.  
  1576. /* a motd-like file for rn */
  1577. #ifndef NEWSNEWSNAME        /* % and ~ */
  1578. #   define NEWSNEWSNAME "%X/newsnews"
  1579. #endif
  1580.  
  1581. /* command to send a reply */
  1582. #ifndef MAILPOSTER        /* % and ~ */
  1583. #   define MAILPOSTER "Rnmail -h %h"
  1584. #endif
  1585.  
  1586. #ifdef INTERNET
  1587. #   ifndef MAILHEADER        /* % */
  1588. #    ifdef CONDSUB
  1589. #        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  1590. #    else
  1591. #        define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  1592. #    endif
  1593. #   endif
  1594. #else
  1595. #   ifndef MAILHEADER        /* % */
  1596. #    ifdef CONDSUB
  1597. #        define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
  1598. #    else
  1599. #        define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
  1600. #    endif
  1601. #   endif
  1602. #endif
  1603.  
  1604. #ifndef YOUSAID            /* % */
  1605. #   define YOUSAID "In article %i you write:"
  1606. #endif
  1607.  
  1608. /* command to submit a followup article */
  1609. #ifndef NEWSPOSTER        /* % and ~ */
  1610. #   define NEWSPOSTER "Pnews -h %h"
  1611. #endif
  1612.  
  1613. #ifndef NEWSHEADER        /* % */
  1614. #   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"
  1615. #endif
  1616.  
  1617. #ifndef ATTRIBUTION        /* % */
  1618. #   define ATTRIBUTION "In article %i %f writes:"
  1619. #endif
  1620.  
  1621. #ifndef PIPESAVER        /* % */
  1622. #   ifdef CONDSUB
  1623. #    define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
  1624. #   else
  1625. #    define PIPESAVER "tail +%Bc %A | %b"
  1626. #   endif
  1627. #endif
  1628.  
  1629. #ifndef NORMSAVER        /* % and ~ */
  1630. #   define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
  1631. #endif
  1632.  
  1633. #ifndef MBOXSAVER        /* % and ~ */
  1634. #   ifdef MININACT        /* 2.10.2 site? */
  1635. #    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
  1636. #   else
  1637. #    ifdef CONDSUB
  1638. #        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)\""
  1639.                     /* header munging with a vengeance */
  1640. #    else
  1641. #        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
  1642. #    endif
  1643. #   endif
  1644. #endif
  1645.  
  1646. #ifdef MKDIRS
  1647.  
  1648. #   ifndef SAVEDIR            /* % and ~ */
  1649. #    define SAVEDIR "%p/%c"
  1650. #   endif
  1651. #   ifndef SAVENAME        /* % */
  1652. #    define SAVENAME "%a"
  1653. #   endif
  1654.  
  1655. #else
  1656.  
  1657. #   ifndef SAVEDIR            /* % and ~ */
  1658. #    define SAVEDIR "%p"
  1659. #   endif
  1660. #   ifndef SAVENAME        /* % */
  1661. #    define SAVENAME "%^C"
  1662. #   endif
  1663.  
  1664. #endif
  1665.  
  1666. #ifndef KILLGLOBAL        /* % and ~ */
  1667. #   define KILLGLOBAL "%p/KILL"
  1668. #endif
  1669.  
  1670. #ifndef KILLLOCAL        /* % and ~ */
  1671. #   define KILLLOCAL "%p/%c/KILL"
  1672. #endif
  1673.  
  1674. /* how to cancel an article */
  1675. #ifndef CANCEL
  1676. #   ifdef MININACT            /* 2.10.2 ? */
  1677. #    define CANCEL "%x/inews -h < %h"
  1678. #   else
  1679. #    define CANCEL "inews -h < %h"
  1680. #   endif
  1681. #endif
  1682.  
  1683. /* how to cancel an article, continued */
  1684. #ifndef CANCELHEADER
  1685. #   define CANCELHEADER "Newsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nReply-To: %L@%H.UUCP (%N)\nDistribution: %D\nOrganization: %o\n"
  1686. #endif
  1687.  
  1688. /* where to find the mail file */
  1689. #ifndef MAILFILE
  1690. #   define MAILFILE "/usr/spool/mail/%L"
  1691. #endif
  1692.  
  1693. /* some important types */
  1694.  
  1695. typedef int        NG_NUM;        /* newsgroup number */
  1696. typedef long        ART_NUM;    /* article number */
  1697. #ifdef pdp11
  1698.     typedef short    ART_UNREAD;    /* ordinarily this should be long */
  1699.                     /* like ART_NUM, but assuming that */
  1700.                     /* we stay less than 32767 articles */
  1701.                     /* behind saves a lot of space. */
  1702.                     /* NOTE: do not make unsigned. */
  1703. #else
  1704.     typedef long    ART_UNREAD;
  1705. #endif
  1706. typedef long        ART_POS;    /* char position in article file */
  1707. typedef int        ART_LINE;    /* line position in article file */
  1708. typedef short        ACT_POS;    /* char position in active file */
  1709. typedef unsigned int    MEM_SIZE;    /* for passing to malloc */
  1710.  
  1711. /* *** end of the machine dependent stuff *** */
  1712.  
  1713. /* GLOBAL THINGS */
  1714.  
  1715. /* file statistics area */
  1716.  
  1717. EXT struct stat filestat;
  1718.  
  1719. /* various things of type char */
  1720.  
  1721. char    *index();
  1722. char    *rindex();
  1723. char    *getenv();
  1724. char    *strcat();
  1725. char    *strcpy();
  1726. char    *sprintf();
  1727.  
  1728. EXT char buf[LBUFLEN+1];    /* general purpose line buffer */
  1729. EXT char cmd_buf[CBUFLEN];    /* buffer for formatting system commands */
  1730.  
  1731. EXT char *indstr INIT(">");    /* indent for old article embedded in followup */
  1732.  
  1733. EXT char *cwd INIT(Nullch);        /* current working directory */
  1734. EXT char *dfltcmd INIT(Nullch);    /* 1st char is default command */
  1735.  
  1736. /* switches */
  1737.  
  1738. #ifdef DEBUGGING
  1739.     EXT int debug INIT(0);                /* -D */
  1740. #   define DEB_INNERSRCH 32 
  1741. #   define DEB_FILEXP 64 
  1742. #   define DEB_HASH 128
  1743. #   define DEB_XREF_MARKER 256
  1744. #   define DEB_CTLAREA_BITMAP 512
  1745. #   define DEB_SOFT_POINTERS 1024
  1746. #   define DEB_NEWSRC_LINE 2048
  1747. #   define DEB_SEARCH_AHEAD 4096
  1748. #   define DEB_CHECKPOINTING 8192
  1749. #   define DEB_FEED_XREF 16384
  1750. #endif
  1751.  
  1752. #ifdef ARTSEARCH
  1753.     EXT int scanon INIT(0);                /* -S */
  1754. #endif
  1755.  
  1756. EXT bool mbox_always INIT(FALSE);            /* -M */
  1757. EXT bool norm_always INIT(FALSE);            /* -N */
  1758. EXT bool checkflag INIT(FALSE);            /* -c */
  1759. EXT bool suppress_cn INIT(FALSE);            /* -s */
  1760. EXT int countdown INIT(5);    /* how many lines to list before invoking -s */
  1761. EXT bool muck_up_clear INIT(FALSE);            /* -loco */
  1762. EXT bool erase_screen INIT(FALSE);            /* -e */
  1763. #ifdef CLEAREOL
  1764. EXT bool can_home_clear INIT(FALSE);        /* fancy -e -- PWP */
  1765. #endif CLEAREOL
  1766. EXT bool findlast INIT(FALSE);            /* -r */
  1767. EXT bool typeahead INIT(FALSE);            /* -T */
  1768. #ifdef VERBOSE
  1769. #   ifdef TERSE
  1770.     EXT bool verbose INIT(TRUE);            /* +t */
  1771. #   endif
  1772. #endif
  1773. #ifdef VERIFY
  1774.     EXT bool verify INIT(FALSE);            /* -v */
  1775. #endif
  1776.  
  1777. #define NOMARKING 0
  1778. #define STANDOUT 1
  1779. #define UNDERLINE 2
  1780. EXT int marking INIT(NOMARKING);            /* -m */
  1781.  
  1782. EXT ART_LINE initlines INIT(0);        /* -i */
  1783.  
  1784. /* miscellania */
  1785.  
  1786. long atol(), fseek(), ftell();
  1787. EXT bool in_ng INIT(FALSE);        /* current state of rn */
  1788. EXT char mode INIT('i');        /* current state of rn */
  1789.  
  1790. EXT FILE *tmpfp INIT(Nullfp);    /* scratch fp used for .rnlock, .rnlast, etc. */
  1791.  
  1792. EXT NG_NUM nextrcline INIT(0);    /* 1st unused slot in rcline array */
  1793.             /* startup to avoid checking twice in a row */
  1794.  
  1795. extern errno;
  1796.  
  1797. /* Factored strings */
  1798.  
  1799. EXT char nullstr[] INIT("");
  1800. EXT char sh[] INIT(SH);
  1801. EXT char defeditor[] INIT(DEFEDITOR);
  1802. EXT char hforhelp[] INIT("Type h for help.\n");
  1803. #ifdef STRICTCR
  1804. EXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
  1805. #endif
  1806. EXT char readerr[] INIT("rn read error");
  1807. EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
  1808. EXT char cantopen[] INIT("Can't open %s\n");
  1809. EXT char cantcreate[] INIT("Can't create %s\n");
  1810.  
  1811. #ifdef VERBOSE
  1812.     EXT char nocd[] INIT("Can't chdir to directory %s\n");
  1813. #else
  1814.     EXT char nocd[] INIT("Can't find %s\n");
  1815. #endif
  1816.  
  1817. #ifdef NOLINEBUF
  1818. #define FLUSH ,fflush(stdout)
  1819. #else
  1820. #define FLUSH
  1821. #endif
  1822.  
  1823. #ifdef lint
  1824. #undef FLUSH
  1825. #define FLUSH
  1826. #undef putchar
  1827. #define putchar(c)
  1828. #endif
  1829. !STUFFY!FUNK!
  1830. echo Extracting bits.c
  1831. cat >bits.c <<'!STUFFY!FUNK!'
  1832. /* $Header: bits.c,v 4.3 85/05/01 11:36:15 lwall Exp $
  1833.  *
  1834.  * $Log:    bits.c,v $
  1835.  * Revision 4.3  85/05/01  11:36:15  lwall
  1836.  * Baseline for release with 4.3bsd.
  1837.  * 
  1838.  */
  1839.  
  1840. #include "EXTERN.h"
  1841. #include "common.h"
  1842. #include "rcstuff.h"
  1843. #include "head.h"
  1844. #include "util.h"
  1845. #include "final.h"
  1846. #include "rn.h"
  1847. #include "cheat.h"
  1848. #include "ng.h"
  1849. #include "artio.h"
  1850. #include "intrp.h"
  1851. #include "ngdata.h"
  1852. #include "rcln.h"
  1853. #include "kfile.h"
  1854. #include "INTERN.h"
  1855. #include "bits.h"
  1856.  
  1857. #ifdef DBM
  1858. #    ifdef NULL
  1859. #    undef NULL
  1860. #    endif NULL
  1861. #    include <dbm.h>
  1862. #endif DBM
  1863. MEM_SIZE ctlsize;            /* size of bitmap in bytes */
  1864.  
  1865. void
  1866. bits_init()
  1867. {
  1868. #ifdef DELAYMARK
  1869.     dmname = savestr(filexp(RNDELNAME));
  1870. #else
  1871.     ;
  1872. #endif
  1873. }
  1874.  
  1875. /* checkpoint the .newsrc */
  1876.  
  1877. void
  1878. checkpoint_rc()
  1879. {
  1880. #ifdef DEBUGGING
  1881.     if (debug & DEB_CHECKPOINTING) {
  1882.     fputs("(ckpt)",stdout);
  1883.     fflush(stdout);
  1884.     }
  1885. #endif
  1886.     if (doing_ng)
  1887.     restore_ng();            /* do not restore M articles */
  1888.     if (rc_changed)
  1889.     write_rc();
  1890. #ifdef DEBUGGING
  1891.     if (debug & DEB_CHECKPOINTING) {
  1892.     fputs("(done)",stdout);
  1893.     fflush(stdout);
  1894.     }
  1895. #endif
  1896. }
  1897.  
  1898. /* reconstruct the .newsrc line in a human readable form */
  1899.  
  1900. void
  1901. restore_ng()
  1902. {
  1903.     register char *s, *mybuf = buf;
  1904.     register ART_NUM i;
  1905.     ART_NUM count=0;
  1906.     int safelen = LBUFLEN - 16;
  1907.  
  1908.     strcpy(buf,rcline[ng]);        /* start with the newsgroup name */
  1909.     s = buf + rcnums[ng] - 1;        /* use s for buffer pointer */
  1910.     *s++ = rcchar[ng];            /* put the requisite : or !*/
  1911.     *s++ = ' ';                /* put the not-so-requisite space */
  1912.     for (i=1; i<=lastart; i++) {    /* for each article in newsgroup */
  1913.     if (s-mybuf > safelen) {    /* running out of room? */
  1914.         safelen *= 2;
  1915.         if (mybuf == buf) {        /* currently static? */
  1916.         *s = '\0';
  1917.         mybuf = safemalloc((MEM_SIZE)safelen + 16);
  1918.         strcpy(mybuf,buf);    /* so we must copy it */
  1919.         s = mybuf + (s-buf);
  1920.                     /* fix the pointer, too */
  1921.         }
  1922.         else {            /* just grow in place, if possible */
  1923.         char *newbuf;
  1924.  
  1925.         newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
  1926.         s = newbuf + (s-mybuf);
  1927.         mybuf = newbuf;
  1928.         }
  1929.     }
  1930.     if (!was_read(i))        /* still unread? */
  1931.         count++;            /* then count it */
  1932.     else {                /* article was read */
  1933.         ART_NUM oldi;
  1934.  
  1935.         sprintf(s,"%ld",(long)i);    /* put out the min of the range */
  1936.         s += strlen(s);        /* keeping house */
  1937.         oldi = i;            /* remember this spot */
  1938.         do i++; while (i <= lastart && was_read(i));
  1939.                     /* find 1st unread article or end */
  1940.         i--;            /* backup to last read article */
  1941.         if (i > oldi) {        /* range of more than 1? */
  1942.         sprintf(s,"-%ld,",(long)i);
  1943.                     /* then it out as a range */
  1944.         s += strlen(s);        /* and housekeep */
  1945.         }
  1946.         else
  1947.         *s++ = ',';        /* otherwise, just a comma will do */
  1948.     }
  1949.     }
  1950.     if (*(s-1) == ',')            /* is there a final ','? */
  1951.     s--;                /* take it back */
  1952.     *s++ = '\0';            /* and terminate string */
  1953. #ifdef DEBUGGING
  1954.     if (debug & DEB_NEWSRC_LINE && !panic) {
  1955.     printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
  1956.     printf("%s\n",mybuf) FLUSH;
  1957.     }
  1958. #endif
  1959.     free(rcline[ng]);            /* return old rc line */
  1960.     if (mybuf == buf) {
  1961.     rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
  1962.                     /* grab a new rc line */
  1963.     strcpy(rcline[ng], buf);    /* and load it */
  1964.     }
  1965.     else {
  1966.     mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
  1967.                     /* be nice to the heap */
  1968.     rcline[ng] = mybuf;
  1969.     }
  1970.     *(rcline[ng] + rcnums[ng] - 1) = '\0';
  1971.     if (rcchar[ng] == NEGCHAR) {    /* did they unsubscribe? */
  1972.     printf(unsubto,ngname) FLUSH;
  1973.     toread[ng] = TR_UNSUB;        /* make line invisible */
  1974.     }
  1975.     else
  1976.     /*NOSTRICT*/
  1977.     toread[ng] = (ART_UNREAD)count;        /* remember how many unread there are */
  1978. }
  1979.  
  1980. /* mark an article unread, keeping track of toread[] */
  1981.  
  1982. void
  1983. onemore(artnum)
  1984. ART_NUM artnum;
  1985. {
  1986. #ifdef DEBUGGING
  1987.     if (debug && artnum < firstart) {
  1988.     printf("onemore: %d < %d\n",artnum,firstart) FLUSH;
  1989.     return;
  1990.     }
  1991. #endif
  1992.     if (ctl_read(artnum)) {
  1993.     ctl_clear(artnum);
  1994.     ++toread[ng];
  1995.     }
  1996. }
  1997.  
  1998. /* mark an article read, keeping track of toread[] */
  1999.  
  2000. void
  2001. oneless(artnum)
  2002. ART_NUM artnum;
  2003. {
  2004. #ifdef DEBUGGING
  2005.     if (debug && artnum < firstart) {
  2006.     printf("oneless: %d < %d\n",artnum,firstart) FLUSH;
  2007.     return;
  2008.     }
  2009. #endif
  2010.     if (!ctl_read(artnum)) {
  2011.     ctl_set(artnum);
  2012.     if (toread[ng] > TR_NONE)
  2013.         --toread[ng];
  2014.     }
  2015. }
  2016.  
  2017. /* mark an article as unread, making sure that firstart is properly handled */
  2018. /* cross-references are left as read in the other newsgroups */
  2019.  
  2020. void
  2021. unmark_as_read(artnum)
  2022. ART_NUM artnum;
  2023. {
  2024.     check_first(artnum);
  2025.     onemore(artnum);
  2026. #ifdef MCHASE
  2027.     if (!parse_maybe(artnum))
  2028.     chase_xrefs(artnum,FALSE);
  2029. #endif
  2030. }
  2031.  
  2032. #ifdef DELAYMARK
  2033. /* temporarily mark article as read.  When newsgroup is exited, articles */
  2034. /* will be marked as unread.  Called via M command */
  2035.  
  2036. void
  2037. delay_unmark(artnum)
  2038. ART_NUM artnum;
  2039. {
  2040.     if (dmfp == Nullfp) {
  2041.     dmfp = fopen(dmname,"w");
  2042.     if (dmfp == Nullfp) {
  2043.         printf(cantcreate,dmname) FLUSH;
  2044.         sig_catcher(0);
  2045.     }
  2046.     }
  2047.     oneless(artnum);            /* set the correct bit */
  2048.     dmcount++;
  2049.     fprintf(dmfp,"%ld\n",(long)artnum);
  2050. }
  2051. #endif
  2052.  
  2053. /* mark article as read.  If article is cross referenced to other */
  2054. /* newsgroups, mark them read there also. */
  2055.  
  2056. void
  2057. mark_as_read(artnum)
  2058. ART_NUM artnum;
  2059. {
  2060.     oneless(artnum);            /* set the correct bit */
  2061.     checkcount++;            /* get more worried about crashes */
  2062.     chase_xrefs(artnum,TRUE);
  2063. }
  2064.  
  2065. /* make sure we have bits set correctly down to firstart */
  2066.  
  2067. void
  2068. check_first(min)
  2069. ART_NUM min;
  2070. {
  2071.     register ART_NUM i = firstart;
  2072.  
  2073.     if (min < absfirst)
  2074.     min = absfirst;
  2075.     if (min < i) {
  2076.     for (i--; i>=min; i--)
  2077.         ctl_set(i);        /* mark as read */
  2078.     firstart = min;
  2079.     }
  2080. }
  2081.  
  2082. /* bring back articles marked with M */
  2083.  
  2084. #ifdef DELAYMARK
  2085. void
  2086. yankback()
  2087. {
  2088.     register ART_NUM anum;
  2089.  
  2090.     if (dmfp) {            /* delayed unmarks pending? */
  2091. #ifdef VERBOSE
  2092.     printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
  2093.         dmcount == 1 ? nullstr : "s") FLUSH;
  2094. #endif
  2095.     fclose(dmfp);
  2096.     if (dmfp = fopen(dmname,"r")) {
  2097.         while (fgets(buf,sizeof buf,dmfp) != Nullch) {
  2098.         anum = (ART_NUM)atol(buf);
  2099.         /*NOSTRICT*/
  2100.         onemore(anum);             /* then unmark them */
  2101. #ifdef MCHASE
  2102.         chase_xrefs(anum,FALSE);
  2103. #endif
  2104.         }
  2105.         fclose(dmfp);
  2106.         dmfp = Nullfp;
  2107.         UNLINK(dmname);        /* and be tidy */
  2108.     }
  2109.     else {
  2110.         printf(cantopen,dmname) FLUSH;
  2111.         sig_catcher(0);
  2112.     }
  2113.     }
  2114.     dmcount = 0;
  2115. }
  2116. #endif
  2117.     
  2118. /* run down xref list and mark as read or unread */
  2119.  
  2120. int
  2121. chase_xrefs(artnum,markread)
  2122. ART_NUM artnum;
  2123. int markread;
  2124. {
  2125. #ifdef ASYNC_PARSE
  2126.     if (parse_maybe(artnum))        /* make sure we have right header */
  2127.     return -1;
  2128. #endif
  2129. #ifdef DBM
  2130.     {
  2131.     datum lhs, rhs;
  2132.     datum fetch();
  2133.     register char *idp;
  2134.     char *ident_buf;
  2135.     static FILE * hist_file = Nullfp;
  2136. #else
  2137.     if (
  2138. #ifdef DEBUGGING
  2139.     debug & DEB_FEED_XREF ||
  2140. #endif
  2141.     htype[XREF_LINE].ht_minpos >= 0) {
  2142.                     /* are there article# xrefs? */
  2143. #endif DBM
  2144.     char *xref_buf, *curxref;
  2145.     register char *xartnum;
  2146.     char *rver_buf = Nullch;
  2147.     static char *inews_site = Nullch;
  2148.     register ART_NUM x;
  2149.     char tmpbuf[128];
  2150.  
  2151. #ifdef DBM
  2152.     rver_buf = fetchlines(artnum,NGS_LINE);
  2153.                     /* get Newsgroups */
  2154.     if (!index(rver_buf,','))    /* if no comma, no Xref! */
  2155.         return 0;
  2156.     if (hist_file == Nullfp) {    /* Init. file accesses */
  2157. #ifdef DEBUGGING
  2158.         if (debug)
  2159.         printf ("chase_xref: opening files\n");
  2160. #endif
  2161.         dbminit(filexp(ARTFILE));
  2162.         if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
  2163.         return 0;
  2164.     }
  2165.     xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
  2166.     ident_buf = fetchlines(artnum,MESSID_LINE);
  2167.                     /* get Message-ID */
  2168. #ifdef DEBUGGING
  2169.     if (debug)
  2170.         printf ("chase_xref: Message-ID: %s\n", ident_buf);
  2171. #endif
  2172.     idp = ident_buf;
  2173.     while (*++idp)            /* make message-id case insensitive */
  2174.         if (isupper(*idp))
  2175.             *idp = tolower (*idp);
  2176.     lhs.dptr = ident_buf;        /* look up article by id */
  2177.     lhs.dsize = strlen(lhs.dptr) + 1;
  2178.     rhs = fetch(lhs);        /* fetch the record */
  2179.     if (rhs.dptr == NULL)        /* if null, nothing there */
  2180.         goto wild_goose;
  2181.     fseek (hist_file, *((long *)rhs.dptr), 0);
  2182.                     /* datum returned is position in hist file */
  2183.     fgets (xref_buf, BUFSIZ, hist_file);
  2184. #ifdef DEBUGGING
  2185.     if (debug)
  2186.         printf ("Xref from history: %s\n", xref_buf);
  2187. #endif
  2188.     curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
  2189.     curxref = cpytill(tmpbuf, curxref, '\t') + 1;
  2190. #ifdef DEBUGGING
  2191.     if (debug)
  2192.         printf ("chase_xref: curxref: %s\n", curxref);
  2193. #endif
  2194. #else !DBM
  2195. #ifdef DEBUGGING
  2196.     if (htype[XREF_LINE].ht_minpos >= 0)
  2197. #endif
  2198.         xref_buf = fetchlines(artnum,XREF_LINE);
  2199.                     /* get xrefs list */
  2200. #ifdef DEBUGGING
  2201.     else {
  2202.         xref_buf = safemalloc((MEM_SIZE)100);
  2203.         printf("Give Xref: ") FLUSH;
  2204.         gets(xref_buf);
  2205.     }
  2206. #endif
  2207. #ifdef DEBUGGING
  2208.     if (debug & DEB_XREF_MARKER)
  2209.         printf("Xref: %s\n",xref_buf) FLUSH;
  2210. #endif
  2211.     curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
  2212.  
  2213.     /* Make sure site name on Xref matches what inews thinks site is.
  2214.      * Check first against last inews_site.  If it matches, fine.
  2215.      * If not, fetch inews_site from current Relay-Version line and
  2216.      * check again.  This is so that if the new administrator decides
  2217.      * to change the system name as known to inews, rn will still do
  2218.      * Xrefs correctly--each article need only match itself to be valid.
  2219.      */ 
  2220.     if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
  2221.         char *t;
  2222.  
  2223.         if (inews_site != Nullch)
  2224.         free(inews_site);
  2225.         rver_buf = fetchlines(artnum,RVER_LINE);
  2226.         if ((t = instr(rver_buf,"; site ")) == Nullch)
  2227.         inews_site = savestr(nullstr);
  2228.         else {
  2229.         char new_site[128];
  2230.  
  2231.         cpytill(new_site,t + 7,'.');
  2232.         inews_site = savestr(new_site);
  2233.         }
  2234.         if (strNE(tmpbuf,inews_site)) {
  2235. #ifdef DEBUGGING
  2236.         if (debug)
  2237.             printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
  2238. #endif
  2239.         goto wild_goose;
  2240.         }
  2241.     }
  2242. #endif DBM
  2243.     while (*curxref) {
  2244.                     /* for each newsgroup */
  2245.         curxref = cpytill(tmpbuf,curxref,' ');
  2246. #ifdef DBM
  2247.         xartnum = index(tmpbuf,'/');
  2248. #else
  2249.         xartnum = index(tmpbuf,':');
  2250. #endif DBM
  2251.         if (!xartnum)        /* probably an old-style Xref */
  2252.         break;
  2253.         *xartnum++ = '\0';
  2254.         if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
  2255.         x = atol(xartnum);
  2256.         if (x)
  2257.             if (markread) {
  2258.             if (addartnum(x,tmpbuf))
  2259.                 goto wild_goose;
  2260.             }
  2261. #ifdef MCHASE
  2262.             else
  2263.             subartnum(x,tmpbuf);
  2264. #endif
  2265.         }
  2266.         while (*curxref && isspace(*curxref))
  2267.         curxref++;
  2268.     }
  2269.       wild_goose:
  2270.     free(xref_buf);
  2271. #ifdef DBM
  2272.     free(ident_buf);
  2273. #endif DBM
  2274.     if (rver_buf != Nullch)
  2275.         free(rver_buf);
  2276.     }
  2277.     return 0;
  2278. }
  2279.  
  2280. int
  2281. initctl()
  2282. {
  2283.     char *mybuf = buf;            /* place to decode rc line */
  2284.     register char *s, *c, *h;
  2285.     register long i;
  2286.     register ART_NUM unread;
  2287.     
  2288. #ifdef DELAYMARK
  2289.     dmcount = 0;
  2290. #endif
  2291.     if ((lastart = getngsize(ng)) < 0)    /* this cannot happen (laugh here) */
  2292.     return -1;
  2293.  
  2294.     absfirst = getabsfirst(ng,lastart);    /* remember first existing article */
  2295.     if (!absfirst)            /* no articles at all? */
  2296.     absfirst = 1;            /* pretend there is one */
  2297. #ifndef lint
  2298.     ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
  2299. #endif lint
  2300.     ctlarea = safemalloc(ctlsize);    /* allocate control area */
  2301.  
  2302.     /* now modify ctlarea to reflect what has already been read */
  2303.  
  2304.     for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
  2305.                     /* find numbers in rc line */
  2306.     i = strlen(s);
  2307. #ifndef lint
  2308.     if (i >= LBUFLEN-2)            /* bigger than buf? */
  2309.     mybuf = safemalloc((MEM_SIZE)(i+2));
  2310. #endif lint
  2311.     strcpy(mybuf,s);            /* make scratch copy of line */
  2312.     mybuf[i++] = ',';            /* put extra comma on the end */
  2313.     mybuf[i] = '\0';
  2314.     s = mybuf;                /* initialize the for loop below */
  2315.     if (strnEQ(s,"1-",2)) {        /* can we save some time here? */
  2316.     firstart = atol(s+2)+1;        /* ignore first range thusly */
  2317.     s=index(s,',') + 1;
  2318.     }
  2319.     else
  2320.     firstart = 1;            /* all the bits are valid for now */
  2321.     if (absfirst > firstart) {        /* do we know already? */
  2322.     firstart = absfirst;        /* no point calling getngmin again */
  2323.     }
  2324.     else if (artopen(firstart) == Nullfp) {
  2325.                     /* first unread article missing? */
  2326.     i = getngmin(".",firstart);    /* see if expire has been busy */
  2327.     if (i) {            /* avoid a bunch of extra opens */
  2328.         firstart = i;
  2329.     }
  2330.     }
  2331. #ifdef PENDING
  2332. #   ifdef CACHESUBJ
  2333.     subj_to_get = firstart;
  2334. #   endif
  2335. #endif
  2336.     unread = lastart - firstart + 1;    /* assume this range unread */
  2337.     for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++)
  2338.     ctlarea[i] = 0;            /* assume unread */
  2339. #ifdef DEBUGGING
  2340.     if (debug & DEB_CTLAREA_BITMAP) {
  2341.     printf("\n%s\n",mybuf) FLUSH;
  2342.     for (i=1; i <= lastart; i++)
  2343.         if (! was_read(i))
  2344.         printf("%ld ",(long)i) FLUSH;
  2345.     }
  2346. #endif
  2347.     for ( ; (c = index(s,',')) != Nullch; s = ++c) {
  2348.                     /* for each range */
  2349.     ART_NUM min, max;
  2350.  
  2351.     *c = '\0';            /* do not let index see past comma */
  2352.     if ((h = index(s,'-')) != Nullch) {    /* is there a -? */
  2353.         min = atol(s);
  2354.         max = atol(h+1);
  2355.         if (min < firstart)        /* make sure range is in range */
  2356.         min = firstart;
  2357.         if (max > lastart)
  2358.         max = lastart;
  2359.         if (min <= max)        /* non-null range? */
  2360.         unread -= max - min + 1;/* adjust unread count */
  2361.         for (i=min; i<=max; i++)    /* for all articles in range */
  2362.         ctl_set(i);        /* mark them read */
  2363.     }
  2364.     else if ((i = atol(s)) >= firstart && i <= lastart) {
  2365.                     /* is single number reasonable? */
  2366.         ctl_set(i);            /* mark it read */
  2367.         unread--;            /* decrement articles to read */
  2368.     }
  2369. #ifdef DEBUGGING
  2370.     if (debug & DEB_CTLAREA_BITMAP) {
  2371.         printf("\n%s\n",s) FLUSH;
  2372.         for (i=1; i <= lastart; i++)
  2373.         if (! was_read(i))
  2374.             printf("%ld ",(long)i) FLUSH;
  2375.     }
  2376. #endif
  2377.     }
  2378. #ifdef DEBUGGING
  2379.     if (debug & DEB_CTLAREA_BITMAP) {
  2380.     fputs("\n(hit CR)",stdout) FLUSH;
  2381.     gets(cmd_buf);
  2382.     }
  2383. #endif
  2384.     if (mybuf != buf)
  2385.     free(mybuf);
  2386.     toread[ng] = unread;
  2387.     return 0;
  2388. }
  2389.  
  2390. void
  2391. grow_ctl()
  2392. {
  2393.     ART_NUM newlast;
  2394.     ART_NUM tmpfirst;
  2395.     MEM_SIZE newsize;
  2396.     register ART_NUM i;
  2397.  
  2398.     forcegrow = FALSE;
  2399.     newlast = getngsize(ng);
  2400.     if (newlast > lastart) {
  2401.     ART_NUM tmpart = art;
  2402. #ifndef lint
  2403.     newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
  2404. #else
  2405.     newsize = Null(MEM_SIZE);
  2406. #endif lint
  2407.     if (newsize > ctlsize) {
  2408.         newsize += 20;
  2409.         ctlarea = saferealloc(ctlarea,newsize);
  2410.         ctlsize = newsize;
  2411.     }
  2412.     toread[ng] += (ART_UNREAD)(newlast-lastart);
  2413.     for (i=lastart+1; i<=newlast; i++)
  2414.         ctl_clear(i);    /* these articles are unread */
  2415. #ifdef CACHESUBJ
  2416.     if (subj_list != Null(char**)) {
  2417. #ifndef lint
  2418.         subj_list = (char**)saferealloc((char*)subj_list,
  2419.           (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
  2420. #endif lint
  2421.         for (i=lastart+1; i<=newlast; i++)
  2422.         subj_list[OFFSET(i)] = Nullch;
  2423.     }
  2424. #endif
  2425.     tmpfirst = lastart+1;
  2426.     lastart = newlast;
  2427. #ifdef KILLFILES
  2428. #ifdef VERBOSE
  2429.     IF(verbose)
  2430.         sprintf(buf,
  2431.         "%ld more article%s arrived--looking for more to kill...\n\n",
  2432.         (long)(lastart - firstart + 1),
  2433.         (lastart > firstart ? "s have" : " has" ) );
  2434.     ELSE            /* my, my, how clever we are */
  2435. #endif
  2436. #ifdef TERSE
  2437.         strcpy(buf, "More news--killing...\n\n");
  2438. #endif
  2439.     kill_unwanted(tmpfirst,buf,TRUE);
  2440. #endif
  2441.     art = tmpart;
  2442.     }
  2443. }
  2444.  
  2445. !STUFFY!FUNK!
  2446. echo Extracting NEW
  2447. cat >NEW <<'!STUFFY!FUNK!'
  2448.             NEW FEATURES WITH RN 4.3
  2449.  
  2450. New commands
  2451.     TAB (pager)    scan for end of quoted text.
  2452.     && (anywhere)    set or display macros.
  2453.     Q (art level)    exit this newsgroup but stay on it.
  2454.     x (ng level)    exit rn without changing .newsrc.
  2455.  
  2456. New switch
  2457.     -=TERM-switch    apply switch if terminal is TERM.        
  2458.  
  2459. New environment variables
  2460.     RNMACRO        name of your macro and keymap file, if any.
  2461.     SUBJLINE    controls format of = article listing.
  2462.  
  2463. New % interpolations.
  2464.     %I        inclusion indicator (-F argument).
  2465.     %m        current mode of rn (newsgroup, pager, etc.)
  2466.     %z        length of current article.
  2467.     %"prompt"    prompt for input from keyboard.
  2468.     %`command`    same as shell backquotes.
  2469.     ^char        now produces control-char.
  2470.  
  2471. Macros and Keymaps
  2472.     You may now define macros of any reasonable length and map those
  2473.     macros onto your keyboard in any way.  You can completely remap the
  2474.     keyboard if you wish.  Macros may contain % interpolations.
  2475.  
  2476. Global RNINIT file
  2477.     You can now set pseudo-environment variables on a system-wide basis
  2478.     in the file %X/INIT.  You don't have to recompile rn when you want 
  2479.     to try something different.
  2480.  
  2481. Pnews
  2482.     Can append your .signature if you like.
  2483.     Now knows how to mail to moderators.
  2484.     Runs somewhat faster now when invoked with -h.
  2485.     Will use %x/distributions if it exists.
  2486.     Doesn't ask for Distribution on local newsgroups.
  2487.     Doesn't ask for editor if EDITOR or VISUAL is set.
  2488.  
  2489. Terminal handling
  2490.     -L switch uses erase-to-end-of-line to leave info on screen as long
  2491.         as possible.
  2492.     rn -c will not flush typeahead in your login script now.
  2493.     In multi-character commands, \ now quotes the next character.
  2494.     Support for non-line-buffered machines.  Certain V7 machines will
  2495.         appreciate the speedup.
  2496.  
  2497. Configure
  2498.     Lets the poor people without job control do shell escapes.
  2499.     Now remembers your old answers and uses them for defaults.
  2500.     Searches much more widely for libraries.
  2501.     Looks for Mcc or cc -M if it needs to.
  2502.     Finds pg if it needs to.  (Note, pg users: you can use macros to
  2503.         reverse the sense of CR and SP in rn now.)
  2504.     Figures out where manual pages go.
  2505.     Figures out where mail is spooled.
  2506.     Looks for ioctl.h, if any.
  2507.     Determines if you have a builtin echo that works differently than
  2508.         /bin/echo.
  2509.     Asks if your mail takes Internet addresses.
  2510.     Works reasonably on more systems, such as "Pyramids".
  2511.  
  2512. Miscellaneous
  2513.     Commands may be typed directly to a help menu or subject list without
  2514.         having to type 'q' first.
  2515.     - command on first displayed article of a newsgroup takes you out to
  2516.         the previous newsgroup.  (Someday it will take you to the
  2517.         previous article in the previous newsgroup.)
  2518.     You can now easily get into a newsgroup with a KILL file and no
  2519.         unread articles.
  2520.     The catchup command at the top level now asks for confirmation.
  2521.     Interpretation routines now check for output buffer overflow.
  2522.     The pager no longer get hung up on non-initial ^L.
  2523.     The negative unread articles bug was fixed.
  2524.     Numerous small bug fixes.
  2525. !STUFFY!FUNK!
  2526. echo Extracting INIT
  2527. cat >INIT <<'!STUFFY!FUNK!'
  2528. -ESAMPLE="sample"
  2529. !STUFFY!FUNK!
  2530. echo ""
  2531. echo "End of kit 3 (of 9)"
  2532. cat /dev/null >kit3isdone
  2533. config=true
  2534. for iskit in 1 2 3 4 5 6 7 8 9; do
  2535.     if test -f kit${iskit}isdone; then
  2536.     echo "You have run kit ${iskit}."
  2537.     else
  2538.     echo "You still need to run kit ${iskit}."
  2539.     config=false
  2540.     fi
  2541. done
  2542. case $config in
  2543.     true)
  2544.     echo "You have run all your kits.  Please read README and then type Configure."
  2545.     chmod 755 Configure
  2546.     ;;
  2547. esac
  2548. : I do not append .signature, but someone might mail this.
  2549. exit
  2550.  
  2551.