home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume1 / rn / part06 < prev    next >
Internet Message Format  |  1986-11-30  |  63KB

  1. Date: Tue, 7 May 85 13:58:01 pdt
  2. From: allegra!sdcrdcf!RDCF.SDC.UUCP!lwall (Larry Wall)
  3. Newsgroups: mod.sources
  4. Subject: rn version 4.3 (kit 6 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 6 (of 9).  If kit 6 is complete, the line"
  14. echo '"'"End of kit 6 (of 9)"'" will echo at the end.'
  15. echo ""
  16. export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
  17. echo Extracting util.c
  18. cat >util.c <<'!STUFFY!FUNK!'
  19. /* $Header: util.c,v 4.3 85/05/01 11:51:44 lwall Exp $
  20.  *
  21.  * $Log:    util.c,v $
  22.  * Revision 4.3  85/05/01  11:51:44  lwall
  23.  * Baseline for release with 4.3bsd.
  24.  * 
  25.  */
  26.  
  27. #include "EXTERN.h"
  28. #include "common.h"
  29. #include "final.h"
  30. #include "ndir.h"
  31. #include "INTERN.h"
  32. #include "util.h"
  33.  
  34. void
  35. util_init()
  36. {
  37.     ;
  38. }
  39.     
  40. /* fork and exec a shell command */
  41.  
  42. int
  43. doshell(shl,s)
  44. char *s, *shl;
  45. {
  46.     int status, pid, w;
  47.     register int (*istat)(), (*qstat)();
  48.     int (*signal())();
  49.     char *shell;
  50.  
  51. #ifdef SIGTSTP
  52.     sigset(SIGTSTP,SIG_DFL);
  53.     sigset(SIGCONT,SIG_DFL);
  54. #endif
  55.     if (shl != Nullch)
  56.     shell = shl;
  57.     else if ((shell = getenv("SHELL")) == Nullch || !*shell)
  58.     shell = PREFSHELL;
  59.     if ((pid = vfork()) == 0) {
  60.     if (*s)
  61.         execl(shell, shell, "-c", s, 0);
  62.     else
  63.         execl(shell, shell, Nullch, Nullch, 0);
  64.     _exit(127);
  65.     }
  66. #ifndef lint
  67.     istat = signal(SIGINT, SIG_IGN);
  68.     qstat = signal(SIGQUIT, SIG_IGN);
  69. #else
  70.     istat = Null(int (*)());
  71.     qstat = Null(int (*)());
  72. #endif lint
  73.     waiting = TRUE;
  74.     while ((w = wait(&status)) != pid && w != -1)
  75.     ;
  76.     if (w == -1)
  77.     status = -1;
  78.     waiting = FALSE;
  79.     signal(SIGINT, istat);
  80.     signal(SIGQUIT, qstat);
  81. #ifdef SIGTSTP
  82.     sigset(SIGTSTP,stop_catcher);
  83.     sigset(SIGCONT,cont_catcher);
  84. #endif
  85.     return status;
  86. }
  87.  
  88. static char nomem[] = "rn: out of memory!\n";
  89.  
  90. /* paranoid version of malloc */
  91.  
  92. char *
  93. safemalloc(size)
  94. MEM_SIZE size;
  95. {
  96.     char *ptr;
  97.     char *malloc();
  98.  
  99.     ptr = malloc(size?size:1);    /* malloc(0) is NASTY on our system */
  100.     if (ptr != Nullch)
  101.     return ptr;
  102.     else {
  103.     fputs(nomem,stdout) FLUSH;
  104.     sig_catcher(0);
  105.     }
  106.     /*NOTREACHED*/
  107. }
  108.  
  109. /* paranoid version of realloc */
  110.  
  111. char *
  112. saferealloc(where,size)
  113. char *where;
  114. MEM_SIZE size;
  115. {
  116.     char *ptr;
  117.     char *realloc();
  118.  
  119.     ptr = realloc(where,size?size:1);    /* realloc(0) is NASTY on our system */
  120.     if (ptr != Nullch)
  121.     return ptr;
  122.     else {
  123.     fputs(nomem,stdout) FLUSH;
  124.     sig_catcher(0);
  125.     }
  126.     /*NOTREACHED*/
  127. }
  128.  
  129. /* safe version of string copy */
  130.  
  131. char *
  132. safecpy(to,from,len)
  133. char *to;
  134. register char *from;
  135. register int len;
  136. {
  137.     register char *dest = to;
  138.  
  139.     if (from != Nullch) 
  140.     for (len--; len && (*dest++ = *from++); len--) ;
  141.     *dest = '\0';
  142.     return to;
  143. }
  144.  
  145. /* safe version of string concatenate, with \n deletion and space padding */
  146.  
  147. char *
  148. safecat(to,from,len)
  149. char *to;
  150. register char *from;
  151. register int len;
  152. {
  153.     register char *dest = to;
  154.  
  155.     len--;                /* leave room for null */
  156.     if (*dest) {
  157.     while (len && *dest++) len--;
  158.     if (len) {
  159.         len--;
  160.         *(dest-1) = ' ';
  161.     }
  162.     }
  163.     if (from != Nullch)
  164.     while (len && (*dest++ = *from++)) len--;
  165.     if (len)
  166.     dest--;
  167.     if (*(dest-1) == '\n')
  168.     dest--;
  169.     *dest = '\0';
  170.     return to;
  171. }
  172.  
  173. /* copy a string up to some (non-backslashed) delimiter, if any */
  174.  
  175. char *
  176. cpytill(to,from,delim)
  177. register char *to, *from;
  178. register int delim;
  179. {
  180.     for (; *from; from++,to++) {
  181.     if (*from == '\\' && from[1] == delim)
  182.         from++;
  183.     else if (*from == delim)
  184.         break;
  185.     *to = *from;
  186.     }
  187.     *to = '\0';
  188.     return from;
  189. }
  190.  
  191. /* return ptr to little string in big string, NULL if not found */
  192.  
  193. char *
  194. instr(big, little)
  195. char *big, *little;
  196.  
  197. {
  198.     register char *t, *s, *x;
  199.  
  200.     for (t = big; *t; t++) {
  201.     for (x=t,s=little; *s; x++,s++) {
  202.         if (!*x)
  203.         return Nullch;
  204.         if (*s != *x)
  205.         break;
  206.     }
  207.     if (!*s)
  208.         return t;
  209.     }
  210.     return Nullch;
  211. }
  212.  
  213. /* effective access */
  214.  
  215. #ifdef SETUIDGID
  216. int
  217. eaccess(filename, mod)
  218. char *filename;
  219. int mod;
  220. {
  221.     int protection, euid;
  222.     
  223.     mod &= 7;                /* remove extraneous garbage */
  224.     if (stat(filename, &filestat) < 0)
  225.     return -1;
  226.     euid = geteuid();
  227.     if (euid == ROOTID)
  228.     return 0;
  229.     protection = 7 & (filestat.st_mode >>
  230.       (filestat.st_uid == euid ? 6 :
  231.         (filestat.st_gid == getegid() ? 3 : 0)
  232.       ));
  233.     if ((mod & protection) == mod)
  234.     return 0;
  235.     errno = EACCES;
  236.     return -1;
  237. }
  238. #endif
  239.  
  240. /*
  241.  * Get working directory
  242.  */
  243.  
  244. #ifdef GETWD
  245. #define    dot    "."
  246. #define    dotdot    ".."
  247.  
  248. static    char    *name;
  249.  
  250. static    DIR    *dirp;
  251. static    int    off;
  252. static    struct    stat    d, dd;
  253. static    struct    direct    *dir;
  254.  
  255. char *
  256. getwd(np)
  257. char *np;
  258. {
  259.     long rdev, rino;
  260.  
  261.     *np++ = '/';
  262.     *np = 0;
  263.     name = np;
  264.     off = -1;
  265.     stat("/", &d);
  266.     rdev = d.st_dev;
  267.     rino = d.st_ino;
  268.     for (;;) {
  269.         stat(dot, &d);
  270.         if (d.st_ino==rino && d.st_dev==rdev)
  271.             goto done;
  272.         if ((dirp = opendir(dotdot)) == Null(DIR *))
  273.             prexit("getwd: cannot open ..\n");
  274.         stat(dotdot, &dd);
  275.         chdir(dotdot);
  276.         if(d.st_dev == dd.st_dev) {
  277.             if(d.st_ino == dd.st_ino)
  278.                 goto done;
  279.             do
  280.                 if ((dir = readdir(dirp)) == Null(struct direct *))
  281.                     prexit("getwd: read error in ..\n");
  282.             while (dir->d_ino != d.st_ino);
  283.         }
  284.         else do {
  285.                 if ((dir = readdir(dirp)) == Null(struct direct *))
  286.                     prexit("getwd: read error in ..\n");
  287.                 stat(dir->d_name, &dd);
  288.             } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
  289.         cat();
  290.         closedir(dirp);
  291.     }
  292. done:
  293.     name--;
  294.     if (chdir(name) < 0) {
  295.         printf("getwd: can't cd back to %s\n",name) FLUSH;
  296.         sig_catcher(0);
  297.     }
  298.     return (name);
  299. }
  300.  
  301. void
  302. cat()
  303. {
  304.     register i, j;
  305.  
  306.     i = -1;
  307.     while (dir->d_name[++i] != 0);
  308.     if ((off+i+2) > 1024-1)
  309.         return;
  310.     for(j=off+1; j>=0; --j)
  311.         name[j+i+1] = name[j];
  312.     if (off >= 0)
  313.         name[i] = '/';
  314.     off=i+off+1;
  315.     name[off] = 0;
  316.     for(--i; i>=0; --i)
  317.         name[i] = dir->d_name[i];
  318. }
  319.  
  320. void
  321. prexit(cp)
  322. char *cp;
  323. {
  324.     write(2, cp, strlen(cp));
  325.     sig_catcher(0);
  326. }
  327. #else
  328. char *
  329. getwd(np)            /* shorter but slower */
  330. char *np;
  331. {
  332.     FILE *popen();
  333.     FILE *pipefp = popen("/bin/pwd","r");
  334.  
  335.     if (pipefd == Nullfp) {
  336.     printf("Can't run /bin/pwd\n") FLUSH;
  337.     finalize(1);
  338.     }
  339.     fgets(np,512,pipefp);
  340.     np[strlen(np)-1] = '\0';    /* wipe out newline */
  341.     pclose(pipefp);
  342.     return np;
  343. }
  344. #endif
  345.  
  346. /* just like fgets but will make bigger buffer as necessary */
  347.  
  348. char *
  349. get_a_line(original_buffer,buffer_length,fp)
  350. char *original_buffer;
  351. register int buffer_length;
  352. FILE *fp;
  353. {
  354.     register int bufix = 0;
  355.     register int nextch;
  356.     register char *some_buffer_or_other = original_buffer;
  357.  
  358.     do {
  359.     if (bufix >= buffer_length) {
  360.         buffer_length *= 2;
  361.         if (some_buffer_or_other == original_buffer) {
  362.                     /* currently static? */
  363.         some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
  364.         strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
  365.                     /* so we must copy it */
  366.         }
  367.         else {            /* just grow in place, if possible */
  368.         some_buffer_or_other = saferealloc(some_buffer_or_other,
  369.             (MEM_SIZE)buffer_length+1);
  370.         }
  371.     }
  372.     if ((nextch = getc(fp)) == EOF)
  373.         return Nullch;
  374.     some_buffer_or_other[bufix++] = (char) nextch;
  375.     } while (nextch && nextch != '\n');
  376.     some_buffer_or_other[bufix] = '\0';
  377.     len_last_line_got = bufix;
  378.     return some_buffer_or_other;
  379. }
  380.  
  381. /* copy a string to a safe spot */
  382.  
  383. char *
  384. savestr(str)
  385. char *str;
  386. {
  387.     register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
  388.  
  389.     strcpy(newaddr,str);
  390.     return newaddr;
  391. }
  392.  
  393. int
  394. makedir(dirname,nametype)
  395. register char *dirname;
  396. int nametype;
  397. {
  398. #ifdef MAKEDIR
  399.     register char *end;
  400.     register char *s;
  401.     char tmpbuf[1024];
  402.     register char *tbptr = tmpbuf+5;
  403.  
  404.     for (end = dirname; *end; end++) ;    /* find the end */
  405.     if (nametype == MD_FILE) {        /* not to create last component? */
  406.     for (--end; end != dirname && *end != '/'; --end) ;
  407.     if (*end != '/')
  408.         return 0;            /* nothing to make */
  409.     *end = '\0';            /* isolate file name */
  410.     }
  411.     strcpy(tmpbuf,"mkdir");
  412.  
  413.     s = end;
  414.     for (;;) {
  415.     if (stat(dirname,&filestat) >= 0) {
  416.                     /* does this much exist? */
  417.         *s = '/';            /* mark this as existing */
  418.         break;
  419.     }
  420.     s = rindex(dirname,'/');    /* shorten name */
  421.     if (!s)                /* relative path! */
  422.         break;            /* hope they know what they are doing */
  423.     *s = '\0';            /* mark as not existing */
  424.     }
  425.     
  426.     for (s=dirname; s <= end; s++) {    /* this is grody but efficient */
  427.     if (!*s) {            /* something to make? */
  428.         sprintf(tbptr," %s",dirname);
  429.         tbptr += strlen(tbptr);    /* make it, sort of */
  430.         *s = '/';            /* mark it made */
  431.     }
  432.     }
  433.     if (nametype == MD_DIR)        /* don't need final slash unless */
  434.     *end = '\0';            /*  a filename follows the dir name */
  435.  
  436.     return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
  437.                     /* exercise our faith */
  438. #else
  439.     sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
  440.     return doshell(sh,cmd_buf);
  441. #endif
  442. }
  443.  
  444. #ifdef SETENV
  445. static bool firstsetenv = TRUE;
  446. extern char **environ;
  447.  
  448. void
  449. setenv(nam,val)
  450. char *nam, *val;
  451. {
  452.     register int i=envix(nam);        /* where does it go? */
  453.  
  454.     if (!environ[i]) {            /* does not exist yet */
  455.     if (firstsetenv) {        /* need we copy environment? */
  456.         int j;
  457. #ifndef lint
  458.         char **tmpenv = (char**)    /* point our wand at memory */
  459.         safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
  460. #else
  461.         char **tmpenv = Null(char **);
  462. #endif lint
  463.     
  464.         firstsetenv = FALSE;
  465.         for (j=0; j<i; j++)        /* copy environment */
  466.         tmpenv[j] = environ[j];
  467.         environ = tmpenv;        /* tell exec where it is now */
  468.     }
  469. #ifndef lint
  470.     else
  471.         environ = (char**) saferealloc((char*) environ,
  472.         (MEM_SIZE) (i+2) * sizeof(char*));
  473.                     /* just expand it a bit */
  474. #endif lint
  475.     environ[i+1] = Nullch;    /* make sure it's null terminated */
  476.     }
  477.     environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
  478.                     /* this may or may not be in */
  479.                     /* the old environ structure */
  480.     sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
  481. }
  482.  
  483. int
  484. envix(nam)
  485. char *nam;
  486. {
  487.     register int i, len = strlen(nam);
  488.  
  489.     for (i = 0; environ[i]; i++) {
  490.     if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
  491.         break;            /* strnEQ must come first to avoid */
  492.     }                    /* potential SEGV's */
  493.     return i;
  494. }
  495. #endif
  496.  
  497. void
  498. notincl(feature)
  499. char *feature;
  500. {
  501.     printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
  502. }
  503.  
  504. char *
  505. getval(nam,def)
  506. char *nam,*def;
  507. {
  508.     char *val;
  509.  
  510.     if ((val = getenv(nam)) == Nullch || !*val)
  511.     val = def;
  512.     return val;
  513. }
  514.  
  515. /* grow a static string to at least a certain length */
  516.  
  517. void
  518. growstr(strptr,curlen,newlen)
  519. char **strptr;
  520. int *curlen;
  521. int newlen;
  522. {
  523.     if (newlen > *curlen) {        /* need more room? */
  524.     if (*curlen)
  525.         *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
  526.     else
  527.         *strptr = safemalloc((MEM_SIZE)newlen);
  528.     *curlen = newlen;
  529.     }
  530. }
  531.  
  532. void
  533. setdef(buffer,dflt)
  534. char *buffer,*dflt;
  535. {
  536. #ifdef STRICTCR
  537.     if (*buffer == ' ')
  538. #else
  539.     if (*buffer == ' ' || *buffer == '\n')
  540. #endif
  541.     {
  542.     if (*dflt == '^' && isupper(dflt[1]))
  543.         *buffer = Ctl(dflt[1]);
  544.     else
  545.         *buffer = *dflt;
  546.     }
  547. }
  548. !STUFFY!FUNK!
  549. echo Extracting respond.c
  550. cat >respond.c <<'!STUFFY!FUNK!'
  551. /* $Header: respond.c,v 4.3 85/05/01 11:47:04 lwall Exp $
  552.  *
  553.  * $Log:    respond.c,v $
  554.  * Revision 4.3  85/05/01  11:47:04  lwall
  555.  * Baseline for release with 4.3bsd.
  556.  * 
  557.  */
  558.  
  559. #include "EXTERN.h"
  560. #include "common.h"
  561. #include "intrp.h"
  562. #include "head.h"
  563. #include "term.h"
  564. #include "ng.h"
  565. #include "util.h"
  566. #include "rn.h"
  567. #include "intrp.h"
  568. #include "artio.h"
  569. #include "final.h"
  570. #include "INTERN.h"
  571. #include "respond.h"
  572.  
  573. static char nullart[] = "\nNull article\n";
  574.  
  575. void
  576. respond_init()
  577. {
  578.     ;
  579. }
  580.  
  581. int
  582. save_article()
  583. {
  584.     bool use_pref;
  585.     register char *s, *c;
  586.     char altbuf[CBUFLEN];
  587.     int iter;
  588.     bool interactive = (buf[1] == FINISHCMD);
  589.     
  590.     if (!finish_command(interactive))    /* get rest of command */
  591.     return SAVE_ABORT;
  592.     use_pref = isupper(*buf);
  593. #ifdef ASYNC_PARSE
  594.     parse_maybe(art);
  595. #endif
  596.     savefrom = (*buf=='w' || *buf=='W' ? htype[PAST_HEADER].ht_minpos : 0);
  597.     if (artopen(art) == Nullfp) {
  598. #ifdef VERBOSE
  599.     IF(verbose)
  600.         fputs("\n\
  601. Saving null articles is not very productive!  :-)\n\
  602. ",stdout) FLUSH;
  603.     ELSE
  604. #endif
  605. #ifdef TERSE
  606.         fputs(nullart,stdout) FLUSH;
  607. #endif
  608.     return SAVE_DONE;
  609.     }
  610.     if (chdir(cwd)) {
  611.     printf(nocd,cwd) FLUSH;
  612.     sig_catcher(0);
  613.     }
  614.     if (savedest)
  615.     free(savedest);
  616.     if ((s = index(buf,'|')) != Nullch) {
  617.                 /* is it a pipe command? */
  618.     s++;            /* skip the | */
  619.     while (*s == ' ') s++;
  620.     safecpy(altbuf,filexp(s),sizeof altbuf);
  621.     savedest = altbuf;
  622.     interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
  623.                 /* then set up for command */
  624.     resetty();        /* restore tty state */
  625.     if (use_pref)        /* use preferred shell? */
  626.         doshell(Nullch,cmd_buf);
  627.                 /* do command with it */
  628.     else
  629.         doshell(sh,cmd_buf);    /* do command with sh */
  630.     noecho();        /* and stop echoing */
  631.     crmode();        /* and start cbreaking */
  632.     savedest = savestr(savedest);
  633.     }
  634.     else {            /* normal save */
  635.     bool there, mailbox;
  636.     char *savename = getval("SAVENAME",SAVENAME);
  637.  
  638.     s = buf+1;        /* skip s or S */
  639.     if (*s == '-') {    /* if they are confused, skip - also */
  640. #ifdef VERBOSE
  641.         IF(verbose)
  642.         fputs("Warning: '-' ignored.  This isn't readnews.\n",stdout)
  643.           FLUSH;
  644.         ELSE
  645. #endif
  646. #ifdef TERSE
  647.         fputs("'-' ignored.\n",stdout) FLUSH;
  648. #endif
  649.         s++;
  650.     }
  651.     for (; *s == ' '; s++);    /* skip spaces */
  652.     safecpy(altbuf,filexp(s),sizeof altbuf);
  653.     s = altbuf;
  654.     if (! index(s,'/')) {
  655.         interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
  656.         if (makedir(buf,MD_DIR))    /* ensure directory exists */
  657.         strcpy(buf,cwd);
  658.         if (*s) {
  659.         for (c = buf; *c; c++) ;
  660.         *c++ = '/';
  661.         strcpy(c,s);        /* add filename */
  662.         }
  663.         s = buf;
  664.     }
  665.     for (iter = 0;
  666.         (there = stat(s,&filestat) >= 0) &&
  667.         (filestat.st_mode & S_IFDIR);
  668.         iter++) {            /* is it a directory? */
  669.  
  670.         c = (s+strlen(s));
  671.         *c++ = '/';            /* put a slash before filename */
  672.         interp(c, s==buf?(sizeof buf):(sizeof altbuf),
  673.         iter ? "News" : savename );
  674.                 /* generate a default name somehow or other */
  675.         if (index(c,'/')) {        /* yikes, a '/' in the filename */
  676.         makedir(s,MD_FILE);
  677.         }
  678.     }
  679.     if (*s != '/') {        /* relative path? */
  680.         c = (s==buf ? altbuf : buf);
  681.         sprintf(c, "%s/%s", cwd, s);
  682.         s = c;            /* absolutize it */
  683.     }
  684.     s = savedest = savestr(s);    /* doesn't move any more */
  685.                     /* make it handy for %b */
  686.     if (!there) {
  687.         if (mbox_always)
  688.         mailbox = TRUE;
  689.         else if (norm_always)
  690.         mailbox = FALSE;
  691.         else {
  692.         char *dflt = (instr(savename,"%a") ? "nyq" : "ynq");
  693.         
  694.         sprintf(cmd_buf,
  695.         "\nFile %s doesn't exist--\n    use mailbox format? [%s] ",
  696.           s,dflt);
  697.           reask_save:
  698.         in_char(cmd_buf);
  699.         putchar('\n') FLUSH;
  700.         setdef(cmd_buf,dflt);
  701. #ifdef VERIFY
  702.         printcmd();
  703. #endif
  704.         if (*buf == 'h') {
  705. #ifdef VERBOSE
  706.             IF(verbose)
  707.             printf("\n\
  708. Type y to create %s as a mailbox.\n\
  709. Type n to create it as a normal file.\n\
  710. Type q to abort the save.\n\
  711. ",s) FLUSH;
  712.             ELSE
  713. #endif
  714. #ifdef TERSE
  715.             fputs("\n\
  716. y to create mailbox.\n\
  717. n to create normal file.\n\
  718. q to abort.\n\
  719. ",stdout) FLUSH;
  720. #endif
  721.             goto reask_save;
  722.         }
  723.         else if (*buf == 'n') {
  724.             mailbox = FALSE;
  725.         }
  726.         else if (*buf == 'y') {
  727.             mailbox = TRUE;
  728.         }
  729.         else if (*buf == 'q') {
  730.             goto s_bomb;
  731.         }
  732.         else {
  733.             fputs(hforhelp,stdout) FLUSH;
  734.             settle_down();
  735.             goto reask_save;
  736.         }
  737.         }
  738.     }
  739.     else if (filestat.st_mode & S_IFCHR)
  740.         mailbox = FALSE;
  741.     else {
  742.         int tmpfd;
  743.         
  744.         tmpfd = open(s,0);
  745.         if (tmpfd == -1)
  746.         mailbox = FALSE;
  747.         else {
  748.         read(tmpfd,buf,LBUFLEN);
  749.         c = buf;
  750.         if (!isspace(MBOXCHAR))
  751.             while (isspace(*c))
  752.             c++;
  753.         mailbox = (*c == MBOXCHAR);
  754.         close(tmpfd);
  755.         }
  756.     }
  757.  
  758.     safecpy(cmd_buf, filexp(mailbox ?
  759.         getval("MBOXSAVER",MBOXSAVER) :
  760.         getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
  761.                 /* format the command */
  762.     resetty();        /* make terminal behave */
  763.     if (doshell(use_pref?Nullch:SH,cmd_buf))
  764.         fputs("Not saved",stdout);
  765.     else
  766.         printf("%s to %s %s",
  767.           there?"Appended":"Saved",
  768.           mailbox?"mailbox":"file",
  769.           s);
  770.     if (interactive)
  771.         putchar('\n') FLUSH;
  772.     noecho();        /* make terminal do what we want */
  773.     crmode();
  774.     }
  775. s_bomb:
  776.     if (chdir(spool) || chdir(ngdir)) {
  777.     printf(nocd,ngdir) FLUSH;
  778.     sig_catcher(0);
  779.     }
  780.     return SAVE_DONE;
  781. }
  782.  
  783. int
  784. cancel_article()
  785. {
  786.     char *artid_buf;
  787.     char *ngs_buf;
  788.     char *from_buf;
  789.     char *reply_buf;
  790.     int myuid = getuid();
  791.     int r = -1;
  792.  
  793.     if (artopen(art) == Nullfp) {
  794. #ifdef VERBOSE
  795.     IF(verbose)
  796.         fputs("\n\
  797. Cancelling null articles is your idea of fun?  :-)\n\
  798. ",stdout) FLUSH;
  799.     ELSE
  800. #endif
  801. #ifdef TERSE
  802.         fputs(nullart,stdout) FLUSH;
  803. #endif
  804.     return r;
  805.     }
  806.     reply_buf = fetchlines(art,REPLY_LINE);
  807.     from_buf = fetchlines(art,FROM_LINE);
  808.     artid_buf = fetchlines(art,ARTID_LINE);
  809.     ngs_buf = fetchlines(art,NGS_LINE);
  810.     if (!instr(from_buf,sitename) ||
  811.     (!instr(from_buf,logname) &&
  812.      !instr(reply_buf,logname) &&
  813. #ifdef NEWSADMIN
  814.      myuid != newsuid &&
  815. #endif
  816.      myuid != ROOTID ) )
  817. #ifdef VERBOSE
  818.         IF(verbose)
  819.         fputs("You can't cancel someone else's article\n",stdout)
  820.           FLUSH;
  821.         ELSE
  822. #endif
  823. #ifdef TERSE
  824.         fputs("Not your article\n",stdout) FLUSH;
  825. #endif
  826.     else {
  827.     tmpfp = fopen(headname,"w");    /* open header file */
  828.     if (tmpfp == Nullfp) {
  829.         printf(cantcreate,headname) FLUSH;
  830.         goto no_cancel;
  831.     }
  832.     interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
  833.     fputs(buf,tmpfp);
  834.     fclose(tmpfp);
  835.     r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
  836.     }
  837. no_cancel:
  838.     free(artid_buf);
  839.     free(ngs_buf);
  840.     free(from_buf);
  841.     free(reply_buf);
  842.     return r;
  843. }
  844.  
  845. void
  846. reply()
  847. {
  848.     bool incl_body = (*buf == 'R');
  849.     char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));
  850.  
  851.     if (artopen(art) == Nullfp) {
  852. #ifdef VERBOSE
  853.     IF(verbose)
  854.         fputs("\nBut null articles are so dull!  :-)\n",stdout) FLUSH;
  855.     ELSE
  856. #endif
  857. #ifdef TERSE
  858.         fputs(nullart,stdout) FLUSH;
  859. #endif
  860.     goto no_reply;
  861.     }
  862.     tmpfp = fopen(headname,"w");    /* open header file */
  863.     if (tmpfp == Nullfp) {
  864.     printf(cantcreate,headname) FLUSH;
  865.     goto no_reply;
  866.     }
  867.     interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
  868.     fputs(buf,tmpfp);
  869.     if (!instr(maildoer,"%h"))
  870. #ifdef VERBOSE
  871.     IF(verbose)
  872.         printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
  873.           FLUSH;
  874.     ELSE
  875. #endif
  876. #ifdef TERSE
  877.         printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
  878. #endif
  879.     if (incl_body) {
  880.     interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
  881.     fprintf(tmpfp,"%s\n",buf);
  882. #ifdef ASYNC_PARSE
  883.     parse_maybe(art);
  884. #endif
  885.     fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
  886.     while (fgets(buf,LBUFLEN,artfp) != Nullch) {
  887.         fprintf(tmpfp,"%s%s",indstr,buf);
  888.     }
  889.     fprintf(tmpfp,"\n");
  890.     }
  891.     fclose(tmpfp);
  892.     interp(cmd_buf, (sizeof cmd_buf), maildoer);
  893.     invoke(cmd_buf,origdir);
  894.     UNLINK(headname);        /* kill the header file */
  895. no_reply:
  896.     free(maildoer);
  897. }
  898.  
  899. void
  900. followup()
  901. {
  902.     bool incl_body = (*buf == 'F');
  903.  
  904.     if (artopen(art) == Nullfp) {
  905. #ifdef VERBOSE
  906.     IF(verbose)
  907.         fputs("\nNull articles give me indigestion!  :-)\n",stdout) FLUSH;
  908.     ELSE
  909. #endif
  910. #ifdef TERSE
  911.         fputs(nullart,stdout) FLUSH;
  912. #endif
  913.     return;
  914.     }
  915.     tmpfp = fopen(headname,"w");
  916.     if (tmpfp == Nullfp) {
  917.     printf(cantcreate,headname) FLUSH;
  918.     return;
  919.     }
  920.     interp(buf, (sizeof buf), getval("NEWSHEADER",NEWSHEADER));
  921.     fprintf(tmpfp,"%s",buf);
  922.     if (incl_body) {
  923. #ifdef VERBOSE
  924.     if (verbose)
  925.         fputs("\n\
  926. (Be sure to double-check the attribution against the signature, and\n\
  927. trim the quoted article down as much as possible.)\n\
  928. ",stdout) FLUSH;
  929. #endif
  930.     interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
  931.     fprintf(tmpfp,"%s\n",buf);
  932. #ifdef ASYNC_PARSE
  933.     parse_maybe(art);
  934. #endif
  935.     fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
  936.     while (fgets(buf,LBUFLEN,artfp) != Nullch) {
  937.         fprintf(tmpfp,"%s%s",indstr,buf);
  938.     }
  939.     fprintf(tmpfp,"\n");
  940.     }
  941.     fclose(tmpfp);
  942.     safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
  943.     invoke(cmd_buf,origdir);
  944.     UNLINK(headname);
  945. }
  946.  
  947. void
  948. invoke(cmd,dir)
  949. char *cmd,*dir;
  950. {
  951.     if (chdir(dir)) {
  952.     printf(nocd,dir) FLUSH;
  953.     return;
  954.     }
  955. #ifdef VERBOSE
  956.     IF(verbose)
  957.     printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
  958.         dir,cmd) FLUSH;
  959.     ELSE
  960. #endif
  961. #ifdef TERSE
  962.     printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
  963. #endif
  964.     resetty();            /* make terminal well-behaved */
  965.     doshell(sh,cmd);        /* do the command */
  966.     noecho();            /* set no echo */
  967.     crmode();            /* and cbreak mode */
  968. #ifdef VERBOSE
  969.     IF(verbose)
  970.     fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
  971.     ELSE
  972. #endif
  973. #ifdef TERSE
  974.     fputs("\n(+cbreak)\n",stdout) FLUSH;
  975. #endif
  976.     if (chdir(spool) || chdir(ngdir)) {
  977.     printf(nocd,ngdir) FLUSH;
  978.     sig_catcher(0);
  979.     }
  980. }
  981.  
  982. !STUFFY!FUNK!
  983. echo Extracting sw.c
  984. cat >sw.c <<'!STUFFY!FUNK!'
  985. /* $Header: sw.c,v 4.3 85/05/01 11:50:54 lwall Exp $
  986.  *
  987.  * $Log:    sw.c,v $
  988.  * Revision 4.3  85/05/01  11:50:54  lwall
  989.  * Baseline for release with 4.3bsd.
  990.  * 
  991.  */
  992.  
  993. #include "EXTERN.h"
  994. #include "common.h"
  995. #include "util.h"
  996. #include "head.h"
  997. #include "only.h"
  998. #include "term.h"
  999. #include "ng.h"
  1000. #include "intrp.h"
  1001. #include "INTERN.h"
  1002. #include "sw.h"
  1003.  
  1004. void
  1005. sw_init(argc,argv,tcbufptr)
  1006. int argc;
  1007. char *argv[];
  1008. char **tcbufptr;
  1009. {
  1010.     register int i;
  1011.  
  1012.     interp(*tcbufptr,1024,GLOBINIT);
  1013.     sw_file(tcbufptr,FALSE);
  1014.     safecpy(*tcbufptr,getenv("RNINIT"),1024);
  1015.     if (**tcbufptr) {
  1016.     if (**tcbufptr == '/') {
  1017.         sw_file(tcbufptr,TRUE);
  1018.     }
  1019.     else
  1020.         sw_list(*tcbufptr);
  1021.     }
  1022.  
  1023.     for (i = 1; i < argc; i++)
  1024.     decode_switch(argv[i]);
  1025. }
  1026.  
  1027. void
  1028. sw_file(tcbufptr,bleat)
  1029. char **tcbufptr;
  1030. bool bleat;
  1031. {
  1032.     int initfd = open(*tcbufptr,0);
  1033.     
  1034.     if (initfd >= 0) {
  1035.     fstat(initfd,&filestat);
  1036.     if (filestat.st_size > 1024)
  1037.         *tcbufptr = saferealloc(*tcbufptr,(MEM_SIZE)filestat.st_size);
  1038.     if (filestat.st_size) {
  1039.         read(initfd,*tcbufptr,(int)filestat.st_size);
  1040.         (*tcbufptr)[filestat.st_size-1] = '\0';
  1041.                 /* wipe out last newline */
  1042.         sw_list(*tcbufptr);
  1043.     }
  1044.     else
  1045.         **tcbufptr = '\0';
  1046.     close(initfd);
  1047.     }
  1048.     else {
  1049.     if (bleat)
  1050.         printf(cantopen,*tcbufptr) FLUSH;
  1051.     **tcbufptr = '\0';
  1052.     }
  1053. }
  1054.  
  1055. /* decode a list of space separated switches */
  1056.  
  1057. void
  1058. sw_list(swlist)
  1059. char *swlist;
  1060. {
  1061.     char *tmplist = safemalloc((MEM_SIZE) strlen(swlist) + 2);
  1062.                     /* semi-automatic string */
  1063.     register char *p, inquote = 0;
  1064.  
  1065.     strcpy(tmplist,swlist);
  1066.     for (p=tmplist; isspace(*p); p++) ;    /* skip any initial spaces */
  1067.     while (*p) {            /* "String, or nothing" */
  1068.     if (!inquote && isspace(*p)) {    /* word delimiter? */
  1069.         *p++ = '\0';        /* chop here */
  1070.         while (isspace(*p))        /* these will be ignored later */
  1071.         p++;
  1072.     }
  1073.     else if (inquote == *p) {
  1074.         strcpy(p,p+1);        /* delete trailing quote */
  1075.         inquote = 0;        /* no longer quoting */
  1076.     }
  1077.     else if (!inquote && *p == '"' || *p == '\'') {
  1078.                     /* OK, I know when I am not wanted */
  1079.         inquote = *p;        /* remember single or double */
  1080.         strcpy(p,p+1);        /* delete the quote */
  1081.     }                /* (crude, but effective) */
  1082.     else if (*p == '\\') {        /* quoted something? */
  1083.         if (p[1] == '\n')        /* newline? */
  1084.         strcpy(p,p+2);        /* "I didn't see anything" */
  1085.         else {
  1086.         strcpy(p,p+1);        /* delete the backwhack */
  1087.         p++;            /* leave the whatever alone */
  1088.         }
  1089.     }
  1090.     else
  1091.         p++;            /* normal char, leave it alone */
  1092.     }
  1093.     *++p = '\0';            /* put an extra null on the end */
  1094.     if (inquote)
  1095.     printf("Unmatched %c in switch\n",inquote) FLUSH;
  1096.     for (p = tmplist; *p; /* p += strlen(p)+1 */ ) {
  1097.     decode_switch(p);
  1098.     while (*p++) ;            /* point at null + 1 */
  1099.     }
  1100.     free(tmplist);            /* this oughta be in Ada */
  1101. }
  1102.  
  1103. /* decode a single switch */
  1104.  
  1105. void
  1106. decode_switch(s)
  1107. register char *s;
  1108. {
  1109.     while (isspace(*s))            /* ignore leading spaces */
  1110.     s++;
  1111. #ifdef DEBUGGING
  1112.     if (debug)
  1113.     printf("Switch: %s\n",s) FLUSH;
  1114. #endif
  1115.     if (*s != '-' && *s != '+') {    /* newsgroup pattern */
  1116.     setngtodo(s);
  1117.     }
  1118.     else {                /* normal switch */
  1119.     bool upordown = *s == '-' ? TRUE : FALSE;
  1120.     char tmpbuf[LBUFLEN];
  1121.  
  1122.     s++;
  1123.     switch (*s) {
  1124. #ifdef TERMMOD
  1125.     case '=': {
  1126.         char *beg = s+1;
  1127.  
  1128.         while (*s && *s != '-' && *s != '+') s++;
  1129.         cpytill(tmpbuf,beg,*s);
  1130.         if (upordown ? strEQ(getenv("TERM"),tmpbuf)
  1131.                  : strNE(getenv("TERM"),tmpbuf) ) {
  1132.         decode_switch(s);
  1133.         }
  1134.         break;
  1135.     }
  1136. #endif
  1137. #ifdef BAUDMOD
  1138.     case '0': case '1': case '2': case '3': case '4':
  1139.     case '5': case '6': case '7': case '8': case '9':
  1140.         if (upordown ? (just_a_sec*10 <= atoi(s))
  1141.                  : (just_a_sec*10 >= atoi(s)) ) {
  1142.         while (isdigit(*s)) s++;
  1143.         decode_switch(s);
  1144.         }
  1145.         break;
  1146. #endif
  1147.     case '/':
  1148. #ifdef SETENV
  1149.         setenv("SAVEDIR",  upordown ? "%p/%c" : "%p" );
  1150.         setenv("SAVENAME", upordown ? "%a"    : "%^C");
  1151. #else
  1152.         notincl("-/");
  1153. #endif
  1154.         break;
  1155.     case 'c':
  1156.         checkflag = upordown;
  1157.         break;
  1158.     case 'C':
  1159.         s++;
  1160.         if (*s == '=') s++;
  1161.         docheckwhen = atoi(s);
  1162.         break;
  1163.     case 'd': {
  1164.         s++;
  1165.         if (*s == '=') s++;
  1166.         if (cwd) {
  1167.         chdir(cwd);
  1168.         free(cwd);
  1169.         }
  1170.         cwd = savestr(s);
  1171.         break;
  1172.     }
  1173. #ifdef DEBUGGING
  1174.     case 'D':
  1175.         s++;
  1176.         if (*s == '=') s++;
  1177.         if (*s)
  1178.         if (upordown)
  1179.             debug |= atoi(s);
  1180.         else
  1181.             debug &= ~atoi(s);
  1182.         else
  1183.         if (upordown)
  1184.             debug |= 1;
  1185.         else
  1186.             debug = 0;
  1187.         break;
  1188. #endif
  1189.     case 'e':
  1190.         erase_screen = upordown;
  1191.         break;
  1192.     case 'E':
  1193. #ifdef SETENV
  1194.         s++;
  1195.         if (*s == '=')
  1196.         s++;
  1197.         strcpy(tmpbuf,s);
  1198.         s = index(tmpbuf,'=');
  1199.         if (s) {
  1200.         *s++ = '\0';
  1201.         setenv(tmpbuf,s);
  1202.         }
  1203.         else
  1204.         setenv(tmpbuf,nullstr);
  1205. #else
  1206.         notincl("-E");
  1207. #endif
  1208.         break;
  1209.     case 'F':
  1210.         s++;
  1211.         indstr = savestr(s);
  1212.         break;
  1213. #ifdef INNERSEARCH
  1214.     case 'g':
  1215.         gline = atoi(s+1)-1;
  1216.         break;
  1217. #endif
  1218.     case 'H':
  1219.     case 'h': {
  1220.         register int len, i;
  1221.         char *t;
  1222.         int flag = (*s == 'h' ? HT_HIDE : HT_MAGIC);
  1223.         
  1224.         s++;
  1225.         len = strlen(s);
  1226.         for (t=s; *t; t++)
  1227.         if (isupper(*t))
  1228.            *t = tolower(*t);
  1229.         for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  1230.         if (!len || strnEQ(s,htype[i].ht_name,len))
  1231.             if (upordown)
  1232.             htype[i].ht_flags |= flag;
  1233.             else
  1234.             htype[i].ht_flags &= ~flag;
  1235.         break;
  1236.     }
  1237.     case 'i':
  1238.         s++;
  1239.         if (*s == '=') s++;
  1240.         initlines = atoi(s);
  1241.         break;
  1242.     case 'l':
  1243.         muck_up_clear = upordown;
  1244.         break;
  1245.     case 'L':
  1246. #ifdef CLEAREOL
  1247.         can_home_clear = upordown;
  1248. #else
  1249.         notincl("-L");
  1250. #endif
  1251.         break;
  1252.     case 'M':
  1253.         mbox_always = upordown;
  1254.         break;
  1255.     case 'm':
  1256.         s++;
  1257.         if (*s == '=') s++;
  1258.         if (!upordown)
  1259.         marking = NOMARKING;
  1260.         else if (*s == 'u')
  1261.         marking = UNDERLINE;
  1262.         else {
  1263.         marking = STANDOUT;
  1264.         }
  1265.         break;
  1266.     case 'N':
  1267.         norm_always = upordown;
  1268.         break;
  1269. #ifdef VERBOSE
  1270.     case 'n':
  1271.         fputs("This isn't readnews.  Don't use -n.\n\n",stdout) FLUSH;
  1272.         break;
  1273. #endif
  1274.     case 'r':
  1275.         findlast = upordown;
  1276.         break;
  1277.     case 's':
  1278.         s++;
  1279.         if (*s == '=') s++;
  1280.         if (*s) {
  1281.         countdown = atoi(s);
  1282.         suppress_cn = FALSE;
  1283.         }
  1284.         else {
  1285.         if (!upordown)
  1286.             countdown = 5;
  1287.         suppress_cn = upordown;
  1288.         }
  1289.         break;
  1290.     case 'S':
  1291. #ifdef ARTSEARCH
  1292.         s++;
  1293.         if (*s == '=') s++;
  1294.         if (*s)
  1295.         scanon = atoi(s);
  1296.         else
  1297.         scanon = upordown*3;
  1298. #else
  1299.         notincl("-S");
  1300. #endif
  1301.         break;
  1302.     case 't':
  1303. #ifdef VERBOSE
  1304. #ifdef TERSE
  1305.         verbose = !upordown;
  1306. #else
  1307.         notincl("+t");
  1308. #endif
  1309. #else
  1310.         notincl("+t");
  1311. #endif
  1312.         break;
  1313.     case 'T':
  1314.         typeahead = upordown;
  1315.         break;
  1316.     case 'v':
  1317. #ifdef VERIFY
  1318.         verify = upordown;
  1319. #else
  1320.         notincl("-v");
  1321. #endif
  1322.         break;
  1323.     default:
  1324. #ifdef VERBOSE
  1325.         IF(verbose)
  1326.         printf("\nIgnoring unrecognized switch: -%c\n", *s) FLUSH;
  1327.         ELSE
  1328. #endif
  1329. #ifdef TERSE
  1330.         printf("\nIgnoring -%c\n", *s) FLUSH;
  1331. #endif
  1332.         break;
  1333.     }
  1334.     }
  1335. }
  1336.  
  1337. /* print current switch values */
  1338.  
  1339. void
  1340. pr_switches()
  1341. {
  1342.     static char mp[2] = {'+','-'};
  1343.     register int i;
  1344.     
  1345.     fputs("\nCurrent switch settings:\n",stdout);
  1346.     printf("%c/ ", mp[strEQ(getval("SAVEDIR",SAVEDIR),"%p/%c")]);
  1347.     printf("%cc ", mp[checkflag]);
  1348.     printf("-C%d ", docheckwhen);
  1349.     printf("-d%s ", cwd);
  1350. #ifdef DEBUGGING
  1351.     if (debug)
  1352.     printf("-D%d ", debug);
  1353. #endif
  1354.     printf("%ce ", mp[erase_screen]);
  1355.     printf("-F\"%s\" ", indstr);
  1356. #ifdef INNERSEARCH
  1357.     printf("-g%d", gline);
  1358. #endif
  1359.     putchar('\n');
  1360. #ifdef VERBOSE
  1361.     if (verbose) {
  1362.     for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  1363.         printf("%ch%s%c",
  1364.         mp[htype[i].ht_flags & HT_HIDE], htype[i].ht_name,
  1365.         (! (i % 5) ? '\n' : ' ') );
  1366.     }
  1367. #endif
  1368.     printf("-i%d ", initlines);
  1369.     printf("%cl ", mp[muck_up_clear]);
  1370. #ifdef CLEAREOL
  1371.     printf("%cL ", mp[can_home_clear]);
  1372. #endif CLEAREOL
  1373.     if (marking)
  1374.     printf("-m%c ",marking==UNDERLINE?'u':'s');
  1375.     else
  1376.     printf("+m ");
  1377.     printf("%cM ", mp[mbox_always]);
  1378.     printf("%cN ", mp[norm_always]);
  1379.     printf("%cr ", mp[findlast]);
  1380.     if (countdown)
  1381.     printf("-s%d ", countdown);
  1382.     else
  1383.     printf("%cs ", mp[suppress_cn]);
  1384. #ifdef ARTSEARCH
  1385.     if (scanon)
  1386.     printf("-S%d ",scanon);
  1387.     else
  1388.     printf("+S ");
  1389. #ifdef VERBOSE
  1390. #ifdef TERSE
  1391.     printf("%ct ", mp[!verbose]);
  1392. #endif
  1393. #endif
  1394.     printf("%cT ", mp[typeahead]);
  1395. #ifdef VERIFY
  1396.     printf("%cv ", mp[verify]);
  1397. #endif
  1398. #endif
  1399.     fputs("\n\n",stdout) FLUSH;
  1400. #ifdef ONLY
  1401.     if (maxngtodo) {
  1402. #ifdef VERBOSE
  1403.     IF(verbose)
  1404.         fputs("Current restriction:",stdout);
  1405.     ELSE
  1406. #endif
  1407. #ifdef TERSE
  1408.         fputs("Only:",stdout);
  1409. #endif
  1410.     for (i=0; i<maxngtodo; i++)
  1411.         printf(" %s",ngtodo[i]);
  1412.     fputs("\n\n",stdout) FLUSH;
  1413.     }
  1414. #ifdef VERBOSE
  1415.     else if (verbose)
  1416.     fputs("No restriction.\n\n",stdout) FLUSH;
  1417. #endif
  1418. #endif
  1419. }
  1420.  
  1421. void
  1422. cwd_check()
  1423. {
  1424.     char tmpbuf[LBUFLEN];
  1425.  
  1426.     if (!cwd)
  1427.     cwd = savestr(filexp("~/News"));
  1428.     strcpy(tmpbuf,cwd);
  1429.     if (chdir(cwd)) {
  1430.     safecpy(tmpbuf,filexp(cwd),sizeof tmpbuf);
  1431.     if (makedir(tmpbuf,MD_DIR) < 0 || chdir(tmpbuf) < 0) {
  1432.         interp(cmd_buf, (sizeof cmd_buf), "%~/News");
  1433.         if (makedir(cmd_buf,MD_DIR) < 0)
  1434.         strcpy(tmpbuf,homedir);
  1435.         else
  1436.         strcpy(tmpbuf,cmd_buf);
  1437.         chdir(tmpbuf);
  1438. #ifdef VERBOSE
  1439.         IF(verbose)
  1440.         printf("\
  1441. Cannot make directory %s--\n\
  1442.     articles will be saved to %s\n\
  1443. \n\
  1444. ",cwd,tmpbuf) FLUSH;
  1445.         ELSE
  1446. #endif
  1447. #ifdef TERSE
  1448.         printf("\
  1449. Can't make %s--\n\
  1450.     using %s\n\
  1451. \n\
  1452. ",cwd,tmpbuf) FLUSH;
  1453. #endif
  1454.     }
  1455.     }
  1456.     free(cwd);
  1457.     getwd(tmpbuf);
  1458.     if (eaccess(tmpbuf,2)) {
  1459. #ifdef VERBOSE
  1460.     IF(verbose)
  1461.         printf("\
  1462. Current directory %s is not writeable--\n\
  1463.     articles will be saved to home directory\n\n\
  1464. ",tmpbuf) FLUSH;
  1465.     ELSE
  1466. #endif
  1467. #ifdef TERSE
  1468.         printf("%s not writeable--using ~\n\n",tmpbuf) FLUSH;
  1469. #endif
  1470.     strcpy(tmpbuf,homedir);
  1471.     }
  1472.     cwd = savestr(tmpbuf);
  1473. }
  1474. !STUFFY!FUNK!
  1475. echo Extracting inews.c.2.pat
  1476. cat >inews.c.2.pat <<'!STUFFY!FUNK!'
  1477. *** inews.old.c    Tue Apr 30 14:34:19 1985
  1478. --- inews.c    Tue Apr 30 14:34:33 1985
  1479. ***************
  1480. *** 416,421
  1481.   /*
  1482.    *    Link ARTICLE into dir for ngname and update active file.
  1483.    */
  1484.   localize(ngname)
  1485.   char    *ngname;
  1486.   {
  1487.  
  1488. --- 416,424 -----
  1489.   /*
  1490.    *    Link ARTICLE into dir for ngname and update active file.
  1491.    */
  1492. + #ifdef DOXREFS
  1493. + long
  1494. + #endif
  1495.   localize(ngname)
  1496.   char    *ngname;
  1497.   {
  1498. ***************
  1499. *** 453,458
  1500.               mknewsg(cp, ngname);
  1501.   
  1502.           sprintf(bfr, "%s/%ld", cp, ngsize+1);
  1503.   #ifdef VMS
  1504.           if ((f2 = creat(bfr, 0666)) >=0 ) {
  1505.               f1 = open(article, 0);
  1506.  
  1507. --- 456,466 -----
  1508.               mknewsg(cp, ngname);
  1509.   
  1510.           sprintf(bfr, "%s/%ld", cp, ngsize+1);
  1511. + #ifdef LINKART
  1512. +         if (mylink(ARTICLE, bfr) == 0) break;
  1513. +                 /* on first file inits ARTICLE, on subsequent */
  1514. +                 /* files "links" to first article */
  1515. + #else !LINKART
  1516.   #ifdef VMS
  1517.           if ((f2 = creat(bfr, 0666)) >=0 ) {
  1518.               f1 = open(article, 0);
  1519. ***************
  1520. *** 468,473
  1521.           if (link(ARTICLE, bfr) == 0)
  1522.               break;
  1523.   #endif !VMS
  1524.           e = errno;    /* keep log from clobbering it */
  1525.           logerr("Cannot install article as %s", bfr);
  1526.           if (e != EEXIST) {
  1527.  
  1528. --- 476,482 -----
  1529.           if (link(ARTICLE, bfr) == 0)
  1530.               break;
  1531.   #endif !VMS
  1532. + #endif !LINKART
  1533.           e = errno;    /* keep log from clobbering it */
  1534.           logerr("Cannot install article as %s", bfr);
  1535.           if (e != EEXIST) {
  1536. ***************
  1537. *** 494,499
  1538.           strcpy(firstbufname, bfr);
  1539.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  1540.       addhist(bfr);
  1541.       return TRUE;
  1542.   }
  1543.   
  1544.  
  1545. --- 503,509 -----
  1546.           strcpy(firstbufname, bfr);
  1547.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  1548.       addhist(bfr);
  1549. + #ifndef DOXREFS
  1550.       return TRUE;
  1551.   #else DOXREFS
  1552.       return ngsize+1;
  1553. ***************
  1554. *** 495,500
  1555.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  1556.       addhist(bfr);
  1557.       return TRUE;
  1558.   }
  1559.   
  1560.   /*
  1561.  
  1562. --- 505,513 -----
  1563.       addhist(bfr);
  1564.   #ifndef DOXREFS
  1565.       return TRUE;
  1566. + #else DOXREFS
  1567. +     return ngsize+1;
  1568. + #endif DOXREFS
  1569.   }
  1570.   
  1571.   /*
  1572. ***************
  1573. *** 507,512
  1574.       char c;
  1575.       struct srec srec;    /* struct for sys file lookup    */
  1576.       int is_invalid = FALSE;
  1577.   
  1578.       /* Fill up the rest of header. */
  1579.       if (mode != PROC) {
  1580.  
  1581. --- 520,529 -----
  1582.       char c;
  1583.       struct srec srec;    /* struct for sys file lookup    */
  1584.       int is_invalid = FALSE;
  1585. + #ifdef DOXREFS
  1586. +     register char *nextxref = header.xref; 
  1587. +     int numxrefs = 0;
  1588. + #endif DOXREFS
  1589.   
  1590.       /* Fill up the rest of header. */
  1591.       if (mode != PROC) {
  1592. ***************
  1593. *** 527,532
  1594.       if (!is_ctl && mode != CREATENG)
  1595.           is_invalid = ngfcheck(mode == PROC);
  1596.   
  1597.       /* Write article to temp file. */
  1598.       tfp = xfopen(mktemp(ARTICLE), "w");
  1599.       if ( (c=getc(infp)) == ' ' || c == '\t' ) {
  1600.  
  1601. --- 544,556 -----
  1602.       if (!is_ctl && mode != CREATENG)
  1603.           is_invalid = ngfcheck(mode == PROC);
  1604.   
  1605. + #ifdef LINKART
  1606. +     *ARTICLE = '\0';    /* tell mylink() to snarf the name */
  1607. + #else !LINKART
  1608. + #ifdef DOXREFS
  1609. +     /* Open temp file for article, but link before writing */
  1610. +     tfp = xfopen(mktemp(ARTICLE), "w");
  1611. + #else DOXREFS
  1612.       /* Write article to temp file. */
  1613.       tfp = xfopen(mktemp(ARTICLE), "w");
  1614.       if ( (c=getc(infp)) == ' ' || c == '\t' ) {
  1615. ***************
  1616. *** 545,550
  1617.           putc('\n',tfp);
  1618.       fclose(tfp);
  1619.       fclose(infp);
  1620.   
  1621.       if (is_invalid) {
  1622.           logerr("No valid newsgroups found, moved to junk");
  1623.  
  1624. --- 569,576 -----
  1625.           putc('\n',tfp);
  1626.       fclose(tfp);
  1627.       fclose(infp);
  1628. + #endif DOXREFS
  1629. + #endif LINKART
  1630.   
  1631.       if (is_invalid) {
  1632.           logerr("No valid newsgroups found, moved to junk");
  1633. ***************
  1634. *** 550,555
  1635.           logerr("No valid newsgroups found, moved to junk");
  1636.           if (localize("junk"))
  1637.               savehist(histline);
  1638.           xxit(1);
  1639.       }
  1640.   
  1641.  
  1642. --- 576,582 -----
  1643.           logerr("No valid newsgroups found, moved to junk");
  1644.           if (localize("junk"))
  1645.               savehist(histline);
  1646. + #ifndef DOXREFS
  1647.           xxit(1);
  1648.   #endif
  1649.       }
  1650. ***************
  1651. *** 551,556
  1652.           if (localize("junk"))
  1653.               savehist(histline);
  1654.           xxit(1);
  1655.       }
  1656.   
  1657.       if (time((time_t)0) > (cgtdate(header.subdate) + DFLTEXP) ){
  1658.  
  1659. --- 578,584 -----
  1660.               savehist(histline);
  1661.   #ifndef DOXREFS
  1662.           xxit(1);
  1663. + #endif
  1664.       }
  1665.   #ifdef DOXREFS
  1666.       else
  1667. ***************
  1668. *** 552,558
  1669.               savehist(histline);
  1670.           xxit(1);
  1671.       }
  1672.       if (time((time_t)0) > (cgtdate(header.subdate) + DFLTEXP) ){
  1673.           logerr("Article too old, moved to junk");
  1674.           if (localize("junk"))
  1675.  
  1676. --- 580,588 -----
  1677.           xxit(1);
  1678.   #endif
  1679.       }
  1680. ! #ifdef DOXREFS
  1681. !     else
  1682. ! #endif
  1683.       if (time((time_t)0) > (cgtdate(header.subdate) + DFLTEXP) ){
  1684.           logerr("Article too old, moved to junk");
  1685.           if (localize("junk"))
  1686. ***************
  1687. *** 557,562
  1688.           logerr("Article too old, moved to junk");
  1689.           if (localize("junk"))
  1690.               savehist(histline);
  1691.           xxit(1);
  1692.       }
  1693.   
  1694.  
  1695. --- 587,593 -----
  1696.           logerr("Article too old, moved to junk");
  1697.           if (localize("junk"))
  1698.               savehist(histline);
  1699. + #ifndef DOXREFS
  1700.           xxit(1);
  1701.   #endif
  1702.       }
  1703. ***************
  1704. *** 558,563
  1705.           if (localize("junk"))
  1706.               savehist(histline);
  1707.           xxit(1);
  1708.       }
  1709.   
  1710.       if (is_ctl) {
  1711.  
  1712. --- 589,595 -----
  1713.               savehist(histline);
  1714.   #ifndef DOXREFS
  1715.           xxit(1);
  1716. + #endif
  1717.       }
  1718.   #ifdef DOXREFS
  1719.       else
  1720. ***************
  1721. *** 559,565
  1722.               savehist(histline);
  1723.           xxit(1);
  1724.       }
  1725.       if (is_ctl) {
  1726.           control(&header);
  1727.           localize("control");
  1728.  
  1729. --- 591,599 -----
  1730.           xxit(1);
  1731.   #endif
  1732.       }
  1733. ! #ifdef DOXREFS
  1734. !     else
  1735. ! #endif
  1736.       if (is_ctl) {
  1737.   #ifndef DOXREFS
  1738.           control(&header);
  1739. ***************
  1740. *** 561,566
  1741.       }
  1742.   
  1743.       if (is_ctl) {
  1744.           control(&header);
  1745.           localize("control");
  1746.       } else {
  1747.  
  1748. --- 595,601 -----
  1749.       else
  1750.   #endif
  1751.       if (is_ctl) {
  1752. + #ifndef DOXREFS
  1753.           control(&header);
  1754.   #endif
  1755.           localize("control");
  1756. ***************
  1757. *** 562,567
  1758.   
  1759.       if (is_ctl) {
  1760.           control(&header);
  1761.           localize("control");
  1762.       } else {
  1763.           if (s_find(&srec, FULLSYSNAME) == FALSE)
  1764.  
  1765. --- 597,603 -----
  1766.       if (is_ctl) {
  1767.   #ifndef DOXREFS
  1768.           control(&header);
  1769. + #endif
  1770.           localize("control");
  1771.       } else {
  1772.           if (s_find(&srec, FULLSYSNAME) == FALSE)
  1773. ***************
  1774. *** 566,571
  1775.       } else {
  1776.           if (s_find(&srec, FULLSYSNAME) == FALSE)
  1777.               xerror("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
  1778.           for (ptr = nbuf; *ptr;) {
  1779.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1780.                   localize(ptr);
  1781.  
  1782. --- 602,611 -----
  1783.       } else {
  1784.           if (s_find(&srec, FULLSYSNAME) == FALSE)
  1785.               xerror("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
  1786. + #ifdef DOXREFS
  1787. +         sprintf(nextxref,"%s ",FULLSYSNAME);
  1788. +         nextxref += strlen(nextxref);
  1789. + #endif
  1790.           for (ptr = nbuf; *ptr;) {
  1791.   #ifndef DOXREFS
  1792.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1793. ***************
  1794. *** 567,572
  1795.           if (s_find(&srec, FULLSYSNAME) == FALSE)
  1796.               xerror("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE);
  1797.           for (ptr = nbuf; *ptr;) {
  1798.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1799.                   localize(ptr);
  1800.               while (*ptr++)
  1801.  
  1802. --- 607,613 -----
  1803.           nextxref += strlen(nextxref);
  1804.   #endif
  1805.           for (ptr = nbuf; *ptr;) {
  1806. + #ifndef DOXREFS
  1807.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1808.                   localize(ptr);
  1809.   #else DOXREFS
  1810. ***************
  1811. *** 569,574
  1812.           for (ptr = nbuf; *ptr;) {
  1813.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1814.                   localize(ptr);
  1815.               while (*ptr++)
  1816.                   ;
  1817.           }
  1818.  
  1819. --- 610,624 -----
  1820.   #ifndef DOXREFS
  1821.               if (ngmatch(ptr, srec.s_nbuf) || index(ptr,'.') == NULL)
  1822.                   localize(ptr);
  1823. + #else DOXREFS
  1824. +             if (ngmatch(ptr, srec.s_nbuf) ||
  1825. +                 index(ptr,'.') == NULL) {
  1826. +                 sprintf(nextxref,"%s:%ld ",ptr,localize(ptr));
  1827. +                 numxrefs++;
  1828. +                 while (*nextxref)
  1829. +                        nextxref++;
  1830. +             }
  1831. + #endif DOXREFS
  1832.               while (*ptr++)
  1833.                   ;
  1834.           }
  1835. ***************
  1836. *** 577,582
  1837.               localize("junk");
  1838.           }
  1839.       }
  1840.   
  1841.       broadcast();
  1842.       savehist(histline);
  1843.  
  1844. --- 627,638 -----
  1845.               localize("junk");
  1846.           }
  1847.       }
  1848. + #ifdef DOXREFS
  1849. +     if (numxrefs >= 2)
  1850. +         *(nextxref-1) = '\0';       /* wipe out the last space */
  1851. +     else
  1852. +         header.xref[0] = '\0';      /* wipe out the whole thing */
  1853. + #endif
  1854.   
  1855.   #ifdef LINKART
  1856.       tfp = xfopen(ARTICLE,"w");    /* open 1st article localized */
  1857. ***************
  1858. *** 578,583
  1859.           }
  1860.       }
  1861.   
  1862.       broadcast();
  1863.       savehist(histline);
  1864.       xxit(0);
  1865.  
  1866. --- 634,669 -----
  1867.           header.xref[0] = '\0';      /* wipe out the whole thing */
  1868.   #endif
  1869.   
  1870. + #ifdef LINKART
  1871. +     tfp = xfopen(ARTICLE,"w");    /* open 1st article localized */
  1872. + #endif
  1873. + #if defined(LINKART) || defined(DOXREFS)
  1874. +     /* Now that xref is constructed, write article to temp file. */
  1875. +     /* (We ought to detect no room at this point and clean up.) */ 
  1876. +     if ( (c=getc(infp)) == ' ' || c == '\t' ) {
  1877. +         header.intnumlines++;
  1878. +         sprintf(header.numlines,"%d",header.intnumlines);
  1879. +     }
  1880. +     lhwrite(&header, tfp);
  1881. +     /* Kludge to get around article truncation problem */
  1882. +     if (c == ' ' || c == '\t' )
  1883. +         putc('\n', tfp);
  1884. +     putc(c,tfp);
  1885. +     while (fgets(bfr, BUFLEN, infp) != NULL)
  1886. +         fputs(bfr, tfp);
  1887. +     if (bfr[strlen(bfr)-1] != '\n')
  1888. +         putc('\n',tfp);
  1889. +     fclose(tfp);
  1890. +     fclose(infp);
  1891. + #endif LINKART || DOXREFS
  1892. + #ifdef DOXREFS
  1893. +     if (is_ctl)    /* moved here cuz checkgroups uses ARTICLE! */
  1894. +         control(&header);
  1895. + #endif
  1896.       broadcast();
  1897.       savehist(histline);
  1898.       xxit(0);
  1899. ***************
  1900. *** 853,855
  1901.       }
  1902.       return(NULL);
  1903.   }
  1904.  
  1905. --- 939,963 -----
  1906.       }
  1907.       return(NULL);
  1908.   }
  1909. + #ifdef LINKART
  1910. + mylink(tmpart,linkfrom)
  1911. + char *tmpart, *linkfrom;
  1912. + {
  1913. +     struct stat statbuf;
  1914. +     if (stat(linkfrom,&statbuf)==0)
  1915. +     return -1;
  1916. +     if (!*tmpart)                       /* first article? */
  1917. +     strcpy(tmpart,linkfrom);        /* just remember name */
  1918. +     else {
  1919. +     FILE *linkfp = fopen(linkfrom,"w");
  1920. +     if (!linkfp)
  1921. +         return -1;
  1922. +     fprintf(linkfp,"%s\n",tmpart);  /* do "symbolic link" */
  1923. +     fclose(linkfp);
  1924. +     }
  1925. +     return 0;
  1926. + }
  1927. + #endif LINKART
  1928. !STUFFY!FUNK!
  1929. echo Extracting help.c
  1930. cat >help.c <<'!STUFFY!FUNK!'
  1931. /* $Header: help.c,v 4.3 85/05/01 11:38:59 lwall Exp $
  1932.  *
  1933.  * $Log:    help.c,v $
  1934.  * Revision 4.3  85/05/01  11:38:59  lwall
  1935.  * Baseline for release with 4.3bsd.
  1936.  * 
  1937.  */
  1938.  
  1939. #include "EXTERN.h"
  1940. #include "common.h"
  1941. #include "rn.h"
  1942. #include "term.h"
  1943. #include "INTERN.h"
  1944. #include "help.h"
  1945.  
  1946. void
  1947. help_init()
  1948. {
  1949.     ;
  1950. }
  1951.  
  1952. int
  1953. help_page()
  1954. {
  1955.     int cmd;
  1956.  
  1957. #ifdef PAGERHELP
  1958.     doshell(sh,filexp(PAGERHELP));
  1959. #else
  1960.     page_init();
  1961.     if ((cmd = print_lines("\
  1962. Paging commands:\n\
  1963. ",STANDOUT)) ||
  1964.     (cmd = print_lines("\n\
  1965. SP    Display the next page.\n\
  1966. x    Display the next page decrypted (rot13).\n\
  1967. d    Display half a page more.\n\
  1968. CR    Display one more line.\n\
  1969. ^R,v,^X    Restart the current article (v=verbose header, ^X=rot13).\n\
  1970. ",NOMARKING)) ||
  1971.     (cmd = print_lines("\
  1972. ^B    Back up one page.\n\
  1973. ^L,X    Refresh the screen (X=rot13).\n\
  1974. g pat    Go to (search forward within article for) pattern.\n\
  1975. G    Search again for current pattern within article.\n\
  1976. ^G    Search for next line beginning with \"Subject:\".\n\
  1977. TAB    Search for next line beginning with a different character.\n\
  1978. q    Quit the pager, go to end of article.  Leave article read or unread.\n\
  1979. j    Junk this article (mark it read).  Goes to end of article.\n\
  1980. \n\
  1981. ",NOMARKING)) ||
  1982.     (cmd = print_lines("\
  1983. The following commands skip the rest of the current article, then behave\n\
  1984. just as if typed to the 'What next?' prompt at the end of the article:\n\
  1985. ",STANDOUT)) ||
  1986.     (cmd = print_lines("\n\
  1987. n    Scan forward for next unread article.\n\
  1988. N    Go to next article.\n\
  1989. ^N    Scan forward for next unread article with same title.\n\
  1990. p,P,^P    Same as n,N,^N, only going backwards.\n\
  1991. -    Go to previously displayed article.\n\
  1992. \n\
  1993. ",NOMARKING)) ||
  1994.     (cmd = print_lines("\
  1995. The following commands also take you to the end of the article.\n\
  1996. Type h at end of article for a description of these commands:\n\
  1997. ",STANDOUT)) ||
  1998.     (cmd = print_lines("\
  1999.     # $ & / = ? c C f F k K ^K m M number r R ^R s S u v w W Y ^ |\n\
  2000. \n\
  2001. (To return to the middle of the article after one of these commands, type ^L.)\n\
  2002. ",NOMARKING)) )
  2003.     return cmd;
  2004. #endif
  2005.     return 0;
  2006. }
  2007.  
  2008. int
  2009. help_art()
  2010. {
  2011.     int cmd;
  2012. #ifdef ARTHELP
  2013.     doshell(sh,filexp(ARTHELP));
  2014. #else
  2015.     page_init();
  2016.     if ((cmd = print_lines("\
  2017. Article Selection commands:\n\
  2018. ",STANDOUT)) ||
  2019.     (cmd = print_lines("\n\
  2020. n,SP    Scan forward for next unread article.\n\
  2021. N    Go to next article.\n\
  2022. ^N    Scan forward for next unread article with same subject.\n\
  2023. p,P,^P    Same as n,N,^N, only going backwards.\n\
  2024. -    Go to previously displayed article.\n\
  2025. ",NOMARKING)) ||
  2026.     (cmd = print_lines("\
  2027. number    Go to specified article.\n\
  2028. range{,range} command{:command}\n\
  2029.     Apply one or more commands to one or more ranges of articles.\n\
  2030.     Ranges are of the form: number | number-number.  You may use . for\n\
  2031.     the current article, and $ for the last article.\n\
  2032.      Valid commands are: j, m, M, s, S, and !.\n\
  2033. ",NOMARKING)) ||
  2034.     (cmd = print_lines("\
  2035. /pattern/modifiers\n\
  2036.     Scan forward for article containing pattern in the subject line.\n\
  2037.     (Use ?pat? to scan backwards; append h to scan headers, a to scan\n\
  2038.     entire articles, r to scan read articles, c to make case sensitive.\n\
  2039. /pattern/modifiers:command{:command}\n\
  2040.     Apply one or more commands to the set of articles matching pattern.\n\
  2041.     Use a K modifier to save entire command to the KILL file for this\n\
  2042.     newsgroup.  Commands m and M, if first, imply an r modifier.\n\
  2043.      Valid commands are: j, m, M, s, S, and !.\n\
  2044. ",NOMARKING)) ||
  2045.     (cmd = print_lines("\
  2046. f,F    Submit a followup article (F = include this article).\n\
  2047. r,R    Reply through net mail (R = include this article).\n\
  2048. s ...    Save to file or pipe via sh.\n\
  2049. S ...    Save via preferred shell.\n\
  2050. w,W    Like s and S but save without the header.\n\
  2051. | ...    Same as s|...\n\
  2052. C    Cancel this article, if yours.\n\
  2053. ",NOMARKING)) ||
  2054.     (cmd = print_lines("\
  2055. ^R,v    Restart article (v=verbose).\n\
  2056. ^X    Restart article, rot13 mode.\n\
  2057. c    Catch up (mark all articles as read).\n\
  2058. ^B    Back up one page.\n\
  2059. ^L    Refresh the screen.  You can get back to the pager with this.\n\
  2060. X    Refresh screen in rot13 mode.\n\
  2061. ",NOMARKING)) ||
  2062.     (cmd = print_lines("\
  2063. ^    Go to first unread article.  Disables subject search mode.\n\
  2064. $    Go to end of newsgroup.  Disables subject search mode.\n\
  2065. ",NOMARKING)) ||
  2066.     (cmd = print_lines("#       Print last article number.\n\
  2067. &    Print current values of command-line switches.\n\
  2068. &switch {switch}\n\
  2069.     Set or unset more switches.\n\
  2070. &&    Print current macro definitions.\n\
  2071. &&def    Define a new macro.\n\
  2072. j    Junk this article (mark it read).  Stays at end of article.\n\
  2073. m    Mark article as still unread.\n\
  2074. M    Mark article as still unread upon exiting newsgroup or Y command.\n\
  2075. ",NOMARKING)) ||
  2076.     (cmd = print_lines("\
  2077. Y    Yank back articles marked temporarily read via M.\n\
  2078. k    Mark current SUBJECT as read.\n\
  2079. K    Mark current SUBJECT as read, and save command in KILL file.\n\
  2080. =    List subjects of unread articles.\n\
  2081. u    Unsubscribe to this newsgroup.\n\
  2082. ^K    Edit local KILL file (the one for this newsgroup).\n\
  2083. q    Quit this newsgroup for now.\n\
  2084. Q    Quit newsgroup, staying at current newsgroup.\n\
  2085. ",NOMARKING)) )
  2086.     return cmd;
  2087. #endif
  2088.     return 0;
  2089. }
  2090.  
  2091. int
  2092. help_ng()
  2093. {
  2094.     int cmd;
  2095. #ifdef NGHELP
  2096.     doshell(sh,filexp(NGHELP));
  2097. #else
  2098.     page_init();
  2099.     if (cmd = print_lines("\
  2100. Newsgroup Selection commands:\n\
  2101. ",STANDOUT) )
  2102.     return cmd;
  2103.     if (ng != nextrcline) {
  2104.     if (cmd = print_lines("\
  2105. \n\
  2106. y,SP    Do this newsgroup now.\n\
  2107. .cmd    Do this newsgroup, executing cmd as first command.\n\
  2108. =    Equivalent to .=<carriage return>.\n\
  2109. u    Unsubscribe from this newsgroup.\n\
  2110. c    Catch up (mark this newsgroup all read).\n\
  2111. ",NOMARKING) )
  2112.         return cmd;
  2113.     }
  2114.     if ((cmd = print_lines("\
  2115. \n\
  2116. n    Go to the next newsgroup with unread news.\n\
  2117. N    Go to the next newsgroup.\n\
  2118. p    Go to the previous newsgroup with unread news.\n\
  2119. P    Go to the previous newsgroup.\n\
  2120. ",NOMARKING)) ||
  2121.     (cmd = print_lines("\
  2122. -    Go to the previously displayed newsgroup.\n\
  2123. 1    Go to the first newsgroup.\n\
  2124. ^    Go to the first newsgroup with unread news.\n\
  2125. $    Go to the last newsgroup.\n\
  2126. ",NOMARKING)) ||
  2127.     (cmd = print_lines("\
  2128. g name    Go to the named newsgroup.  Subscribe to new newsgroups this way too.\n\
  2129. /pat    Search forward for newsgroup matching pattern.\n\
  2130. ?pat    Search backward for newsgroup matching pattern.\n\
  2131.     (Use * and ? style patterns.  Append r to include read newsgroups.)\n\
  2132. ",NOMARKING)) ||
  2133.     (cmd = print_lines("\
  2134. l pat    List unsubscribed newsgroups containing pattern.\n\
  2135. m name    Move named newsgroup elsewhere (no name moves current newsgroup).\n\
  2136. o pat    Only display newsgroups matching pattern.  Omit pat to unrestrict.\n\
  2137. a pat    Like o, but also scans for unsubscribed newsgroups matching pattern.\n\
  2138. L    List current .newsrc.\n\
  2139. ",NOMARKING)) ||
  2140.     (cmd = print_lines("\
  2141. &    Print current command-line switch settings.\n\
  2142. &switch {switch}\n\
  2143.     Set (or unset) more command-line switches.\n\
  2144. &&    Print current macro definitions.\n\
  2145. &&def    Define a new macro.\n\
  2146. !cmd    Shell escape.\n\
  2147. ",NOMARKING)) ||
  2148.     (cmd = print_lines("\
  2149. q    Quit rn.\n\
  2150. ^K    Edit the global KILL file.  Use commands like /pattern/j to suppress\n\
  2151.     pattern in every newsgroup.\n\
  2152. v    Print version.\n\
  2153. ",NOMARKING)) )
  2154.     return cmd;
  2155. #endif
  2156. #ifdef PUSHBACK
  2157.     if (cmd = get_anything())
  2158.     return cmd;
  2159.     show_macros();
  2160. #endif
  2161.     return 0;
  2162. }
  2163.  
  2164. #ifdef ESCSUBS
  2165. int
  2166. help_subs()
  2167. {
  2168.     int cmd;
  2169. #ifdef SUBSHELP
  2170.     doshell(sh,filexp(SUBSHELP));
  2171. #else
  2172.     page_init();
  2173.     if ((cmd = print_lines("\
  2174. Valid substitutions are:\n\
  2175. ",STANDOUT)) ||
  2176.     (cmd = print_lines("\
  2177. \n\
  2178. a    Current article number\n\
  2179. A    Full name of current article (%P/%c/%a)\n\
  2180. b    Destination of last save command, often a mailbox\n\
  2181. B    Bytes to ignore at beginning of last saved article\n\
  2182. ",NOMARKING)) ||
  2183.     (cmd = print_lines("\
  2184. c    Current newsgroup, directory form\n\
  2185. C    Current newsgroup, dot form\n\
  2186. d    Full name of newsgroup directory (%P/%c)\n\
  2187. D    Distribution line from current article\
  2188. ",NOMARKING)) ||
  2189.     (cmd = print_lines("\
  2190. f    Who the current article is from\n\
  2191. F    Newsgroups to followup to (from Newsgroups and Followup-To)\n\
  2192. h    (This help message)\n\
  2193. H    Host name (yours)\n\
  2194. i    Message-I.D. line from current article, with <>\n\
  2195. I    Reference indicator mark (see -F switch)\n\
  2196. ",NOMARKING)) ||
  2197.     (cmd = print_lines("\
  2198. l    News administrator's login name, if any\n\
  2199. L    Login name (yours)\n\
  2200. m    Current mode, first letter of (init,newsgroup,article,pager,misc)\n\
  2201. M    Number of article marked with M\n\
  2202. n    Newsgroups from current article\n\
  2203. N    Full name (yours)\n\
  2204. ",NOMARKING)) ||
  2205.     (cmd = print_lines("\
  2206. o    Organization (yours)\n\
  2207. O    Original working directory (where you ran rn from)\n\
  2208. p    Your private news directory (from -d)\n\
  2209. P    Public news spool directory\n\
  2210. ",NOMARKING)) ||
  2211.     (cmd = print_lines("\
  2212. r    Last reference (parent article id)\n\
  2213. R    References list for followup article\n\
  2214. s    Subject, with all Re's and (nf)'s stripped off\n\
  2215. S    Subject, with one Re stripped off\
  2216. ",NOMARKING)) ||
  2217.     (cmd = print_lines("\
  2218. t    New To line derived from From and Reply-To (Internet format)\n\
  2219. T    New To line derived from Path\n\
  2220. u    Number of unread articles\n\
  2221. U    Number of unread articles not counting current article\n\
  2222. x    News library directory\n\
  2223. X    Rn library directory\n\
  2224. z    Length of current article in bytes\n\
  2225. ",NOMARKING)) ||
  2226.     (cmd = print_lines("\
  2227. ~    Your home directory\n\
  2228. .    Directory containing . files\n\
  2229. $    Current process number\n\
  2230. /    Last search string\n\
  2231. ESC    Run preceding command through % interpretation\n\
  2232. ",NOMARKING)) )
  2233.     return cmd;
  2234. #endif
  2235.     return 0;
  2236. }
  2237. #endif
  2238.  
  2239. !STUFFY!FUNK!
  2240. echo Extracting artsrch.c
  2241. cat >artsrch.c <<'!STUFFY!FUNK!'
  2242. /* $Header: artsrch.c,v 4.3 85/05/01 11:35:47 lwall Exp $
  2243.  *
  2244.  * $Log:    artsrch.c,v $
  2245.  * Revision 4.3  85/05/01  11:35:47  lwall
  2246.  * Baseline for release with 4.3bsd.
  2247.  * 
  2248.  */
  2249.  
  2250. #include "EXTERN.h"
  2251. #include "common.h"
  2252. #include "search.h"
  2253. #include "term.h"
  2254. #include "util.h"
  2255. #include "intrp.h"
  2256. #include "bits.h"
  2257. #include "kfile.h"
  2258. #include "head.h"
  2259. #include "final.h"
  2260. #include "cheat.h"
  2261. #include "ng.h"
  2262. #include "artio.h"
  2263. #include "INTERN.h"
  2264. #include "artsrch.h"
  2265.  
  2266. void
  2267. artsrch_init()
  2268. {
  2269. #ifdef ARTSEARCH
  2270. #ifdef ZEROGLOB
  2271.     init_compex(&sub_compex);
  2272.     init_compex(&art_compex);
  2273. #endif
  2274. #endif
  2275. }
  2276.  
  2277. /* search for an article containing some pattern */
  2278.  
  2279. #ifdef ARTSEARCH
  2280. int
  2281. art_search(patbuf,patbufsiz,get_cmd)
  2282. char *patbuf;                /* if patbuf != buf, get_cmd must */
  2283. int patbufsiz;
  2284. int get_cmd;                /*   be set to FALSE!!! */
  2285. {
  2286.     char *pattern;            /* unparsed pattern */
  2287.     register char cmdchr = *patbuf;    /* what kind of search? */
  2288.     register char *s;
  2289.     bool backward = cmdchr == '?' || cmdchr == Ctl('p');
  2290.                     /* direction of search */
  2291.     COMPEX *compex;            /* which compiled expression */
  2292.     char *cmdlst = Nullch;        /* list of commands to do */
  2293.     int normal_return = SRCH_NOTFOUND;    /* assume no commands */
  2294.     bool saltaway = FALSE;        /* store in KILL file? */
  2295.     char howmuch;            /* search just the subjects */
  2296.     bool doread;            /* search read articles? */
  2297.     bool foldcase = TRUE;        /* fold upper and lower case? */
  2298.  
  2299.     int_count = 0;
  2300.     if (cmdchr == '/' || cmdchr == '?') {    /* normal search? */
  2301.     if (get_cmd && buf == patbuf)
  2302.         if (!finish_command(FALSE))    /* get rest of command */
  2303.         return SRCH_ABORT;
  2304.     compex = &art_compex;
  2305.     if (patbuf[1]) {
  2306.         howmuch = 0;
  2307.         doread = FALSE;
  2308.     }
  2309.     else {
  2310.         howmuch = art_howmuch;
  2311.         doread = art_doread;
  2312.     }
  2313.     s = cpytill(buf,patbuf+1,cmdchr);/* ok to cpy buf+1 to buf */
  2314.     pattern = buf;
  2315.     if (*pattern) {
  2316.         if (*lastpat)
  2317.         free(lastpat);
  2318.         lastpat = savestr(pattern);
  2319.     }
  2320.     if (*s) {            /* modifiers or commands? */
  2321.         for (s++; *s && index("Kharc",*s); s++) {
  2322.         if (*s == 'h')        /* scan header */
  2323.             howmuch = 1;
  2324.         else if (*s == 'a')    /* scan article */
  2325.             howmuch = 2;
  2326.         else if (*s == 'r')    /* scan read articles */
  2327.             doread = TRUE;
  2328.         else if (*s == 'K')    /* put into KILL file */
  2329.             saltaway = TRUE;
  2330.         else if (*s == 'c')    /* make search case sensitive */
  2331.             foldcase = FALSE;
  2332.         }
  2333.     }
  2334.     while (isspace(*s) || *s == ':')
  2335.         s++;
  2336.     if (*s) {
  2337.         if (*s == 'm' || *s == 'M')
  2338.         doread = TRUE;
  2339.         if (*s == 'k')        /* grandfather clause */
  2340.         *s = 'j';
  2341.         cmdlst = savestr(s);
  2342.         normal_return = SRCH_DONE;
  2343.     }
  2344.     art_howmuch = howmuch;
  2345.     art_doread = doread;
  2346.     if (srchahead)
  2347.         srchahead = -1;
  2348.     }
  2349.     else {
  2350.     register char *h;
  2351.  
  2352.     howmuch = 0;            /* just search subjects */
  2353.     doread = (cmdchr == Ctl('p'));
  2354.     if (cmdchr == Ctl('n'))
  2355.         normal_return = SRCH_SUBJDONE;
  2356.     compex = &sub_compex;
  2357.     pattern = patbuf+1;
  2358.     strcpy(pattern,": *");
  2359.     h = pattern + strlen(pattern);
  2360.     interp(h,patbufsiz - (h-patbuf),"%s");    /* fetch current subject */
  2361.     if (cmdchr == 'K') {
  2362.         saltaway = TRUE;
  2363.         cmdchr = 'k';
  2364.     }
  2365.     if (cmdchr == 'k') {
  2366.         normal_return = SRCH_DONE;
  2367.         cmdlst = savestr("j");
  2368.         mark_as_read(art);        /* this article has this subject */
  2369.         if (!*h) {
  2370. #ifdef VERBOSE
  2371.         IF(verbose)
  2372.             fputs("\nCannot delete null subject.\n",stdout) FLUSH;
  2373.         ELSE
  2374. #endif
  2375. #ifdef TERSE
  2376.             fputs("\nNull subject.\n",stdout) FLUSH;
  2377. #endif
  2378.         return SRCH_ABORT;
  2379.         }
  2380. #ifdef VERBOSE
  2381.         else if (verbose)
  2382.         printf("\nMarking subject \"%s\" as read.\n",h) FLUSH;
  2383. #endif
  2384.     }
  2385.     else if (!srchahead)
  2386.         srchahead = -1;
  2387.     h[24] = '\0';        /* compensate for notesfiles */
  2388.     while (*h) {
  2389.         if (index("/\\[.^*$'\"",*h) != Nullch)
  2390.         *h++ = '.';
  2391.         else
  2392.         h++;
  2393.     }
  2394. #ifdef DEBUGGING
  2395.     if (debug) {
  2396.         printf("\npattern = %s\n",pattern) FLUSH;
  2397.     }
  2398. #endif
  2399.     }
  2400.     if ((s = compile(compex,pattern,TRUE,foldcase)) != Nullch) {
  2401.                     /* compile regular expression */
  2402.     printf("\n%s\n",s) FLUSH;
  2403.     return SRCH_ABORT;
  2404.     }
  2405. #ifdef KILLFILES
  2406.     if (saltaway) {
  2407.     char saltbuf[LBUFLEN];
  2408.  
  2409.     s = saltbuf;
  2410.     sprintf(s,"/%s/",pattern);
  2411.     s += strlen(s);
  2412.     if (doread)
  2413.         *s++ = 'r';
  2414.     if (howmuch==1)
  2415.         *s++ = 'h';
  2416.     else if (howmuch==2)
  2417.         *s++ = 'a';
  2418.     *s++ = ':';
  2419.     if (!cmdlst)
  2420.         cmdlst = savestr("j");
  2421.     safecpy(s,cmdlst,LBUFLEN-(s-saltbuf));
  2422.     kf_append(saltbuf);
  2423.     }
  2424. #endif
  2425.     if (cmdlst && index(cmdlst,'='))
  2426.     normal_return = SRCH_ERROR;    /* listing subjects is an error? */
  2427.     if (get_cmd) {
  2428.     fputs("\nSearching...\n",stdout) FLUSH;
  2429.                     /* give them something to read */
  2430.     }
  2431.     if (backward) {
  2432.     if (cmdlst && art < lastart)
  2433.         art++;            /* include current article */
  2434.     if (doread)
  2435.         check_first(absfirst);
  2436.     }
  2437.     else {
  2438.     if (art > lastart)
  2439.         art = (doread ? absfirst : firstart) - 1;
  2440.     else if (cmdlst && art > absfirst)
  2441.         art--;            /* include current article */
  2442.     check_first(art);
  2443.     }
  2444.     if (srchahead > 0) {
  2445.     if (!backward)
  2446.         art = srchahead - 1;
  2447.     srchahead = -1;
  2448.     }
  2449.     assert(!cmdlst || *cmdlst);
  2450.     for (;;) {
  2451.     if (int_count) {
  2452.         int_count = 0;
  2453.         if (cmdlst)
  2454.         free(cmdlst);
  2455.         return SRCH_INTR;
  2456.     }
  2457.     if (backward ?
  2458.         (--art < absfirst || (!doread && art < firstart)) :
  2459.         (++art > lastart)
  2460.       ) {            /* out of articles? */
  2461.         if (cmdlst)
  2462.         free(cmdlst);
  2463.         return normal_return;
  2464.     }
  2465.     /*NOSTRICT*/
  2466.     if (doread || !was_read(art)) {
  2467.         if (wanted(compex,art,howmuch)) {
  2468.                     /* does the shoe fit? */
  2469.         if (cmdlst) {
  2470.             if (perform(cmdlst,TRUE)) {
  2471.             if (cmdlst)
  2472.                 free(cmdlst);
  2473.             return SRCH_INTR;
  2474.             }
  2475.         }
  2476.         else {
  2477.             if (cmdlst)
  2478.             free(cmdlst);
  2479.             return SRCH_FOUND;
  2480.         }
  2481.         }
  2482.         else if (!cmdlst && ! (art%50)) {
  2483.         printf("...%ld",(long)art);
  2484.         fflush(stdout);
  2485.         }
  2486.     }
  2487.     }
  2488. }
  2489.  
  2490. /* determine if article fits pattern */
  2491. /* returns TRUE if it exists and fits pattern, FALSE otherwise */
  2492.  
  2493. bool
  2494. wanted(compex, artnum, scope)
  2495. COMPEX *compex;
  2496. ART_NUM artnum;
  2497. char scope;
  2498. {
  2499.     if (!scope) {
  2500.     char subj_buf[266];
  2501.     
  2502.     strcpy(subj_buf, "Subject: ");
  2503.     strncpy(subj_buf+9,fetchsubj(artnum,FALSE,FALSE),256);
  2504. #ifdef DEBUGGING
  2505.     if (debug & DEB_SEARCH_AHEAD)
  2506.         printf("%s\n",subj_buf) FLUSH;
  2507. #endif
  2508.     return execute(compex,subj_buf) != Nullch;
  2509.     }
  2510. #ifdef CACHESUBJ
  2511.     else
  2512.     fetchsubj(artnum,FALSE,FALSE);/* might as well get subject handy */
  2513. #endif
  2514.     
  2515.     if (artopen(artnum) == Nullfp)    /* ensure that article is open */
  2516.     return FALSE;            /* if not, return NO MATCH */
  2517.     scope--;
  2518.     while (fgets(buf,LBUFLEN,artfp) != Nullch) {
  2519.                     /* for each line of article */
  2520.     if (!scope && index(buf,':') == Nullch && *buf != ' ' && *buf != '\t')
  2521.                     /* if headers only and out of header */
  2522.         return FALSE;        /* say no go */
  2523.     if (execute(compex,buf) != Nullch) {
  2524.                     /* does pattern matcher match? */
  2525.         return TRUE;        /* say Eureka */
  2526.     }
  2527.     }
  2528.     return FALSE;            /* out of article, so no match */
  2529. }
  2530. #endif
  2531.  
  2532. !STUFFY!FUNK!
  2533. echo Extracting inews.c.1.pat
  2534. cat >inews.c.1.pat <<'!STUFFY!FUNK!'
  2535. *** inews.c.1.std    Tue Oct  2 16:09:59 1984
  2536. --- inews.c.1    Fri Sep 21 14:50:49 1984
  2537. ***************
  2538. *** 483,488
  2539.   /*
  2540.    *    Link ARTICLE into dir for ngname and update active file.
  2541.    */
  2542.   localize(ngname)
  2543.   char    *ngname;
  2544.   {
  2545.  
  2546. --- 483,491 -----
  2547.   /*
  2548.    *    Link ARTICLE into dir for ngname and update active file.
  2549.    */
  2550. + #ifdef DOXREFS
  2551. + long
  2552. + #endif
  2553.   localize(ngname)
  2554.   char    *ngname;
  2555.   {
  2556. ***************
  2557. *** 515,520
  2558.       }
  2559.       for (;;) {
  2560.           sprintf(bfr, "%s/%ld", dirname(ngname), ngsize+1);
  2561.           if (link(ARTICLE, bfr) == 0) break;
  2562.           e = errno;    /* keep log from clobbering it */
  2563.           fprintf(stderr, "Cannot install article as %s\n", bfr);
  2564.  
  2565. --- 518,528 -----
  2566.       }
  2567.       for (;;) {
  2568.           sprintf(bfr, "%s/%ld", dirname(ngname), ngsize+1);
  2569. + #ifdef LINKART
  2570. +         if (mylink(ARTICLE, bfr) == 0) break;
  2571. +                 /* on first file inits ARTICLE, on subsequent */
  2572. +                 /* files "links" to first article */
  2573. + #else
  2574.           if (link(ARTICLE, bfr) == 0) break;
  2575.   #endif
  2576.           e = errno;    /* keep log from clobbering it */
  2577. ***************
  2578. *** 516,521
  2579.       for (;;) {
  2580.           sprintf(bfr, "%s/%ld", dirname(ngname), ngsize+1);
  2581.           if (link(ARTICLE, bfr) == 0) break;
  2582.           e = errno;    /* keep log from clobbering it */
  2583.           fprintf(stderr, "Cannot install article as %s\n", bfr);
  2584.           log("Cannot install article as %s", bfr);
  2585.  
  2586. --- 524,530 -----
  2587.                   /* files "links" to first article */
  2588.   #else
  2589.           if (link(ARTICLE, bfr) == 0) break;
  2590. + #endif
  2591.           e = errno;    /* keep log from clobbering it */
  2592.           fprintf(stderr, "Cannot install article as %s\n", bfr);
  2593.           log("Cannot install article as %s", bfr);
  2594. ***************
  2595. *** 542,547
  2596.           strcpy(firstbufname, bfr);
  2597.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  2598.       addhist(bfr);
  2599.       return TRUE;
  2600.   }
  2601.   
  2602.  
  2603. --- 551,557 -----
  2604.           strcpy(firstbufname, bfr);
  2605.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  2606.       addhist(bfr);
  2607. + #ifndef DOXREFS
  2608.       return TRUE;
  2609.   #else DOXREFS
  2610.       return ngsize+1;
  2611. ***************
  2612. *** 543,548
  2613.       sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
  2614.       addhist(bfr);
  2615.       return TRUE;
  2616.   }
  2617.   
  2618.   /*
  2619.  
  2620. --- 553,561 -----
  2621.       addhist(bfr);
  2622.   #ifndef DOXREFS
  2623.       return TRUE;
  2624. + #else DOXREFS
  2625. +     return ngsize+1;
  2626. + #endif DOXREFS
  2627.   }
  2628.   
  2629.   /*
  2630. ***************
  2631. *** 553,558
  2632.       register char *ptr;
  2633.       register FILE *tfp;
  2634.       int badgroup = 0, goodgroup = 0;
  2635.   
  2636.       /* Fill up the rest of header. */
  2637.       if (mode != PROC) {
  2638.  
  2639. --- 566,574 -----
  2640.       register char *ptr;
  2641.       register FILE *tfp;
  2642.       int badgroup = 0, goodgroup = 0;
  2643. + #ifdef DOXREFS
  2644. +     register char *nextxref = header.xref; 
  2645. + #endif DOXREFS
  2646.   
  2647.       /* Fill up the rest of header. */
  2648.       if (mode != PROC) {
  2649. ***************
  2650. *** 565,570
  2651.       if (mode==PROC)
  2652.           log("from %s relay %s", header.from, header.relayversion);
  2653.   
  2654.       /* Write article to temp file. */
  2655.       tfp = xfopen(mktemp(ARTICLE), "w");
  2656.       lhwrite(&header, tfp);
  2657.  
  2658. --- 581,593 -----
  2659.       if (mode==PROC)
  2660.           log("from %s relay %s", header.from, header.relayversion);
  2661.   
  2662. + #ifdef LINKART
  2663. +     *ARTICLE = '\0';    /* tell mylink() to snarf the name */
  2664. + #else !LINKART
  2665. + #ifdef DOXREFS
  2666. +     /* Open temp file for article, but link before writing */
  2667. +     tfp = xfopen(mktemp(ARTICLE), "w");
  2668. + #else DOXREFS
  2669.       /* Write article to temp file. */
  2670.       tfp = xfopen(mktemp(ARTICLE), "w");
  2671.       lhwrite(&header, tfp);
  2672. ***************
  2673. *** 577,582
  2674.       }
  2675.       fclose(tfp);
  2676.       fclose(infp);
  2677.   
  2678.       if (is_ctl) {
  2679.           control(&header);
  2680.  
  2681. --- 600,607 -----
  2682.       }
  2683.       fclose(tfp);
  2684.       fclose(infp);
  2685. + #endif DOXREFS
  2686. + #endif LINKART
  2687.   
  2688.       if (is_ctl) {
  2689.           control(&header);
  2690. ***************
  2691. *** 593,598
  2692.               }
  2693.           }
  2694.       } else {
  2695.           for (ptr = nbuf; *ptr;) {
  2696.               if (*ptr == '-') {
  2697.                   while (*ptr++)
  2698.  
  2699. --- 618,627 -----
  2700.               }
  2701.           }
  2702.       } else {
  2703. + #ifdef DOXREFS
  2704. +         sprintf(nextxref,"%s ",SYSNAME);
  2705. +         nextxref += strlen(nextxref);
  2706. + #endif
  2707.           for (ptr = nbuf; *ptr;) {
  2708.               if (*ptr == '-') {
  2709.                   while (*ptr++)
  2710. ***************
  2711. *** 610,615
  2712.               }
  2713.               else
  2714.                   goodgroup++;
  2715.               if (*nbuf)
  2716.                   localize(ptr);
  2717.               while (*ptr++)
  2718.  
  2719. --- 639,645 -----
  2720.               }
  2721.               else
  2722.                   goodgroup++;
  2723. + #ifndef DOXREFS
  2724.               if (*nbuf)
  2725.                   localize(ptr);
  2726.   #else DOXREFS
  2727. ***************
  2728. *** 612,617
  2729.                   goodgroup++;
  2730.               if (*nbuf)
  2731.                   localize(ptr);
  2732.               while (*ptr++)
  2733.                   ;
  2734.           }
  2735.  
  2736. --- 642,653 -----
  2737.   #ifndef DOXREFS
  2738.               if (*nbuf)
  2739.                   localize(ptr);
  2740. + #else DOXREFS
  2741. +             if (*nbuf)
  2742. +                 sprintf(nextxref,"%s:%ld ",ptr,localize(ptr));
  2743. +             while (*nextxref)
  2744. +                 nextxref++;
  2745. + #endif DOXREFS
  2746.               while (*ptr++)
  2747.                   ;
  2748.           }
  2749. ***************
  2750. *** 616,621
  2751.                   ;
  2752.           }
  2753.       }
  2754.   
  2755.   #ifdef NOFORWARD
  2756.       if (*nbuf)
  2757.  
  2758. --- 652,663 -----
  2759.                   ;
  2760.           }
  2761.       }
  2762. + #ifdef DOXREFS
  2763. +     if (goodgroup < 2)
  2764. +         header.xref[0] = '\0';
  2765. +     else
  2766. +         *(nextxref-1) = '\0';
  2767. + #endif
  2768.   
  2769.   #ifdef LINKART
  2770.       tfp = xfopen(ARTICLE,"w");    /* open 1st article localized */
  2771. ***************
  2772. *** 617,622
  2773.           }
  2774.       }
  2775.   
  2776.   #ifdef NOFORWARD
  2777.       if (*nbuf)
  2778.   #endif
  2779.  
  2780. --- 659,683 -----
  2781.           *(nextxref-1) = '\0';
  2782.   #endif
  2783.   
  2784. + #ifdef LINKART
  2785. +     tfp = xfopen(ARTICLE,"w");    /* open 1st article localized */
  2786. + #endif
  2787. + #if defined(LINKART) || defined(DOXREFS)
  2788. +     /* Now that xref is constructed, write article to temp file. */
  2789. +     /* (We ought to detect no room at this point and clean up.) */ 
  2790. +     lhwrite(&header, tfp);
  2791. +     while (fgets(bfr, BUFLEN, infp) != NULL) {
  2792. +         /*
  2793. +         if (!strncmp(bfr, "From ", 5))
  2794. +             putc('>', tfp);
  2795. +         */
  2796. +         fputs(bfr, tfp);
  2797. +     }
  2798. +     fclose(tfp);
  2799. +     fclose(infp);
  2800. + #endif LINKART || DOXREFS
  2801.   #ifdef NOFORWARD
  2802.       if (*nbuf)
  2803.   #endif
  2804. ***************
  2805. *** 861,863
  2806.           mclose(fd);
  2807.       }
  2808.   }
  2809.  
  2810. --- 922,946 -----
  2811.           mclose(fd);
  2812.       }
  2813.   }
  2814. + #ifdef LINKART
  2815. + mylink(tmpart,linkfrom)
  2816. + char *tmpart, *linkfrom;
  2817. + {
  2818. +     struct stat statbuf;
  2819. +     if (stat(linkfrom,&statbuf)==0)
  2820. +     return -1;
  2821. +     if (!*tmpart)
  2822. +     strcpy(tmpart,linkfrom);
  2823. +     else {
  2824. +     FILE *linkfp = fopen(linkfrom,"w");
  2825. +     if (!linkfp)
  2826. +         return -1;
  2827. +     fprintf(linkfp,"%s\n",tmpart);
  2828. +     fclose(linkfp);
  2829. +     }
  2830. +     return 0;
  2831. + }
  2832. + #endif LINKART
  2833. !STUFFY!FUNK!
  2834. echo ""
  2835. echo "End of kit 6 (of 9)"
  2836. cat /dev/null >kit6isdone
  2837. config=true
  2838. for iskit in 1 2 3 4 5 6 7 8 9; do
  2839.     if test -f kit${iskit}isdone; then
  2840.     echo "You have run kit ${iskit}."
  2841.     else
  2842.     echo "You still need to run kit ${iskit}."
  2843.     config=false
  2844.     fi
  2845. done
  2846. case $config in
  2847.     true)
  2848.     echo "You have run all your kits.  Please read README and then type Configure."
  2849.     chmod 755 Configure
  2850.     ;;
  2851. esac
  2852. : I do not append .signature, but someone might mail this.
  2853. exit
  2854.  
  2855.