home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / rn_4_3_blars.lzh / intrp.c < prev    next >
Text File  |  1990-08-26  |  24KB  |  1,090 lines

  1. /* $Header: intrp.c,v 4.3.2.4 90/04/23 00:31:20 sob Exp $
  2.  *
  3.  * $Log:    intrp.c,v $
  4.  * Revision 4.3.2.4  90/04/23  00:31:20  sob
  5.  * Removed unneeded atoi call.
  6.  * 
  7.  * Revision 4.3.2.3  90/03/22  23:04:35  sob
  8.  * Fixes provided by Wayne Davison <drivax!davison>
  9.  * 
  10.  * Revision 4.3.2.2  90/03/17  17:03:12  sob
  11.  * Fixed determination of the news superuser's id. Fix provided by Chip
  12.  * Rosenthal <chip@chinacat.lonestar.org>.
  13.  * 
  14.  * Revision 4.3.2.1  89/12/17  02:54:55  sob
  15.  * Removed redundant include directive.
  16.  * 
  17.  * Revision 4.3.1.5  85/05/23  17:21:24  lwall
  18.  * Now allows 'r' and 'f' on null articles.
  19.  * 
  20.  * Revision 4.3.1.4  85/05/21  13:35:21  lwall
  21.  * Sped up "rn -c" by not doing unnecessary initialization.
  22.  * 
  23.  * Revision 4.3.1.3  85/05/17  10:37:11  lwall
  24.  * Fixed & substitution to capitalize last name too.
  25.  * 
  26.  * Revision 4.3.1.2  85/05/15  14:39:45  lwall
  27.  * Spelled gecos right.
  28.  * 
  29.  * Revision 4.3.1.1  85/05/10  11:33:51  lwall
  30.  * Branch for patches.
  31.  * 
  32.  * Revision 4.3  85/05/01  11:40:54  lwall
  33.  * Baseline for release with 4.3bsd.
  34.  * 
  35.  */
  36.  
  37. #include "EXTERN.h"
  38. #include "common.h"
  39. #include "util.h"
  40. #include "search.h"
  41. #include "head.h"
  42. #include "rn.h"
  43. #include "artsrch.h"
  44. #include "ng.h"
  45. #include "respond.h"
  46. #include "rcstuff.h"
  47. #include "bits.h"
  48. #include "artio.h"
  49. #include "term.h"
  50. #include "final.h"
  51. #include "INTERN.h"
  52. #include "intrp.h"
  53.  
  54. char orgname[] = ORGNAME;
  55.  
  56. /* name of this site */
  57. #ifdef GETHOSTNAME
  58.     char *hostname;
  59. #   undef SITENAME
  60. #   define SITENAME hostname
  61. #else !GETHOSTNAME
  62. #   ifdef DOUNAME
  63. #    include <sys/utsname.h>
  64.     struct utsname uts;
  65. #    undef SITENAME
  66. #    define SITENAME uts.nodename
  67. #   else !DOUNAME
  68. #    ifdef PHOSTNAME
  69.         char *hostname;
  70. #        undef SITENAME
  71. #        define SITENAME hostname
  72. #    else !PHOSTNAME
  73. #        ifdef WHOAMI
  74. #        undef SITENAME
  75. #        define SITENAME sysname
  76. #        endif WHOAMI
  77. #    endif PHOSTNAME
  78. #   endif DOUNAME
  79. #endif GETHOSTNAME
  80.  
  81. #ifdef TILDENAME
  82. static char *tildename = Nullch;
  83. static char *tildedir = Nullch;
  84. #endif
  85.  
  86. char *realname INIT(Nullch);    /* real name of sender from /etc/passwd */
  87.  
  88. char *dointerp();
  89. char *getrealname();
  90. #ifdef CONDSUB
  91. char *skipinterp();
  92. #endif
  93.  
  94. static void abort_interp();
  95.  
  96. void
  97. intrp_init(tcbuf)
  98. char *tcbuf;
  99. {
  100.     char *getlogin();
  101.  
  102.     spool = savestr(filexp(SPOOL));    /* usually /usr/spool/news */
  103.     
  104.     /* get environmental stuff */
  105.  
  106.     /* get home directory */
  107.  
  108.     homedir = getenv("HOME");
  109.     if (homedir == Nullch)
  110.     homedir = getenv("LOGDIR");
  111.  
  112.     dotdir = getval("DOTDIR",homedir);
  113.  
  114.     /* get login name */
  115.  
  116.     logname = getenv("USER");
  117.     if (logname == Nullch)
  118.     logname = getenv("LOGNAME");
  119. #ifdef GETLOGIN
  120.     if (logname == Nullch)
  121.     logname = savestr(getlogin());
  122. #endif
  123.     
  124.     if (checkflag)            /* that getwd below takes ~1/3 sec. */
  125.     return;                /* and we do not need it for -c */
  126.     getwd(tcbuf);            /* find working directory name */
  127.     origdir = savestr(tcbuf);        /* and remember it */
  128.  
  129.     /* get the real name of the person (%N) */
  130.     /* Must be done after logname is read in because BERKNAMES uses that */
  131.  
  132.     strcpy(tcbuf,getrealname(getuid()));
  133.     realname = savestr(tcbuf);
  134.  
  135.     /* name of header file (%h) */
  136.  
  137.     headname = savestr(filexp(HEADNAME));
  138.  
  139.     /* name of this site (%H) */
  140.  
  141. #ifdef GETHOSTNAME
  142.     gethostname(buf,sizeof buf);
  143.     hostname = savestr(buf);
  144. #else
  145. #ifdef DOUNAME
  146.     /* get sysname */
  147.     uname(&uts);
  148. #else
  149. #ifdef PHOSTNAME
  150.     {
  151.     FILE *popen();
  152.     FILE *pipefp = popen(PHOSTNAME,"r");
  153.     
  154.     if (pipefp == Nullfp) {
  155.         printf("Can't find hostname\n");
  156.         sig_catcher(0);
  157.     }
  158.     fgets(buf,sizeof buf,pipefp);
  159.     buf[strlen(buf)-1] = '\0';    /* wipe out newline */
  160.     hostname = savestr(buf);
  161.     pclose(pipefp);
  162.     }
  163. #endif
  164. #endif
  165. #endif
  166.     sitename = savestr(SITENAME);
  167. }
  168.  
  169. /* expand filename via %, ~, and $ interpretation */
  170. /* returns pointer to static area */
  171. /* Note that there is a 1-deep cache of ~name interpretation */
  172.  
  173. char *
  174. filexp(s)
  175. register char *s;
  176. {
  177.     static char filename[CBUFLEN];
  178.     char scrbuf[CBUFLEN];
  179.     register char *d;
  180.  
  181. #ifdef DEBUGGING
  182.     if (debug & DEB_FILEXP)
  183.     printf("< %s\n",s) FLUSH;
  184. #endif
  185.     interp(filename, (sizeof filename), s);            /* interpret any % escapes */
  186. #ifdef DEBUGGING
  187.     if (debug & DEB_FILEXP)
  188.     printf("%% %s\n",filename) FLUSH;
  189. #endif
  190.     s = filename;
  191.     if (*s == '~') {    /* does destination start with ~? */
  192.     if (!*(++s) || *s == '/') {
  193.         sprintf(scrbuf,"%s%s",homedir,s);
  194.                 /* swap $HOME for it */
  195. #ifdef DEBUGGING
  196.     if (debug & DEB_FILEXP)
  197.     printf("~ %s\n",scrbuf) FLUSH;
  198. #endif
  199.         strcpy(filename,scrbuf);
  200.     }
  201.     else {
  202. #ifdef TILDENAME
  203.         for (d=scrbuf; isalnum(*s); s++,d++)
  204.         *d = *s;
  205.         *d = '\0';
  206.         if (tildedir && strEQ(tildename,scrbuf)) {
  207.         strcpy(scrbuf,tildedir);
  208.         strcat(scrbuf, s);
  209.         strcpy(filename, scrbuf);
  210. #ifdef DEBUGGING
  211.         if (debug & DEB_FILEXP)
  212.             printf("r %s %s\n",tildename,tildedir) FLUSH;
  213. #endif
  214.         }
  215.         else {
  216.         if (tildename) {
  217.             free(tildename);
  218.             free(tildedir);
  219.         }
  220.         tildedir = Nullch;
  221.         tildename = savestr(scrbuf);
  222. #ifdef GETPWENT        /* getpwnam() is not the paragon of efficiency */
  223.         {
  224.             struct passwd *getpwnam();
  225.             struct passwd *pwd = getpwnam(tildename);
  226.  
  227.             sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
  228.             tildedir = savestr(pwd->pw_dir);
  229. #ifdef NEWSADMIN
  230.             if ((pwd != NULL) && strEQ(newsadmin,tildename))
  231.             newsuid = pwd->pw_uid;
  232. #endif
  233.             strcpy(filename,scrbuf);
  234. #ifdef GETPWENT
  235.             endpwent();
  236. #endif
  237.         }
  238. #else            /* this will run faster, and is less D space */
  239.         {    /* just be sure LOGDIRFIELD is correct */
  240.             FILE *pfp = fopen("/etc/passwd","r");
  241.             char tmpbuf[512];
  242.             int i;
  243.             
  244.             if (pfp == Nullfp) {
  245.             printf(cantopen,"passwd") FLUSH;
  246.             sig_catcher(0);
  247.             }
  248.             while (fgets(tmpbuf,512,pfp) != Nullch) {
  249.             d = cpytill(scrbuf,tmpbuf,':');
  250. #ifdef DEBUGGING
  251.             if (debug & DEB_FILEXP)
  252.                 printf("p %s\n",tmpbuf) FLUSH;
  253. #endif
  254.             if (strEQ(scrbuf,tildename)) {
  255. #ifdef NEWSADMIN
  256.                 if (strEQ(newsadmin,tildename))
  257.                 newsuid = atoi(index(d+1,':')+1);
  258. #endif
  259.                 for (i=LOGDIRFIELD-2; i; i--) {
  260.                 if (d)
  261.                     d = index(d+1,':');
  262.                 }
  263.                 if (d) {
  264.                 cpytill(scrbuf,d+1,':');
  265.                 tildedir = savestr(scrbuf);
  266.                 strcat(scrbuf,s);
  267.                 strcpy(filename,scrbuf);
  268.                 }
  269.                 break;
  270.             }
  271.             }
  272.             fclose(pfp);
  273.         }
  274. #endif
  275.         }
  276. #else !TILDENAME
  277. #ifdef VERBOSE
  278.         IF(verbose)
  279.         fputs("~loginname not implemented.\n",stdout) FLUSH;
  280.         ELSE
  281. #endif
  282. #ifdef TERSE
  283.         fputs("~login not impl.\n",stdout) FLUSH;
  284. #endif
  285. #endif
  286.     }
  287.     }
  288.     else if (*s == '$') {    /* starts with some env variable? */
  289.     d = scrbuf;
  290.     *d++ = '%';
  291.     if (s[1] == '{')
  292.         strcpy(d,s+2);
  293.     else {
  294.         *d++ = '{';
  295.         for (s++; isalnum(*s); s++) *d++ = *s;
  296.                 /* skip over token */
  297.         *d++ = '}';
  298.         strcpy(d,s);
  299.     }
  300. #ifdef DEBUGGING
  301.     if (debug & DEB_FILEXP)
  302.         printf("$ %s\n",scrbuf) FLUSH;
  303. #endif
  304.     interp(filename, (sizeof filename), scrbuf);
  305.                     /* this might do some extra '%'s but */
  306.                     /* that is how the Mercedes Benz */
  307.     }
  308. #ifdef DEBUGGING
  309.     if (debug & DEB_FILEXP)
  310.     printf("> %s\n",filename) FLUSH;
  311. #endif
  312.     return filename;
  313. }
  314.  
  315. #ifdef CONDSUB
  316. /* skip interpolations */
  317.  
  318. char *
  319. skipinterp(pattern,stoppers)
  320. register char *pattern;
  321. char *stoppers;
  322. {
  323.  
  324.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  325. #ifdef DEBUGGING
  326.     if (debug & DEB_INTRP)
  327.         printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
  328. #endif
  329.     if (*pattern == '%' && pattern[1]) {
  330.         switch (*++pattern) {
  331.         case '{':
  332.         for (pattern++; *pattern && *pattern != '}'; pattern++)
  333.             if (*pattern == '\\')
  334.             pattern++;
  335.         break;
  336.         case '[':
  337.         for (pattern++; *pattern && *pattern != ']'; pattern++)
  338.             if (*pattern == '\\')
  339.             pattern++;
  340.         break;
  341. #ifdef CONDSUB
  342.         case '(': {
  343.         pattern = skipinterp(pattern+1,"!=");
  344.         if (!*pattern)
  345.             goto getout;
  346.         for (pattern++; *pattern && *pattern != '?'; pattern++)
  347.             if (*pattern == '\\')
  348.             pattern++;
  349.         if (!*pattern)
  350.             goto getout;
  351.         pattern = skipinterp(pattern+1,":)");
  352.         if (*pattern == ':')
  353.             pattern = skipinterp(pattern+1,")");
  354.         break;
  355.         }
  356. #endif
  357. #ifdef BACKTICK
  358.         case '`': {
  359.         pattern = skipinterp(pattern+1,"`");
  360.         break;
  361.         }
  362. #endif
  363. #ifdef PROMPTTTY
  364.         case '"':
  365.         pattern = skipinterp(pattern+1,"\"");
  366.         break;
  367. #endif
  368.         default:
  369.         break;
  370.         }
  371.         pattern++;
  372.     }
  373.     else {
  374.         if (*pattern == '^' && pattern[1])
  375.         pattern += 2;
  376.         else if (*pattern == '\\' && pattern[1])
  377.         pattern += 2;
  378.         else
  379.         pattern++;
  380.     }
  381.     }
  382. getout:
  383.     return pattern;            /* where we left off */
  384. }
  385. #endif
  386.  
  387. /* interpret interpolations */
  388.  
  389. char *
  390. dointerp(dest,destsize,pattern,stoppers)
  391. register char *dest;
  392. register int destsize;
  393. register char *pattern;
  394. char *stoppers;
  395. {
  396.     char *subj_buf = Nullch;
  397.     char *ngs_buf = Nullch;
  398.     char *refs_buf = Nullch;
  399.     char *artid_buf = Nullch;
  400.     char *reply_buf = Nullch;
  401.     char *from_buf = Nullch;
  402.     char *path_buf = Nullch;
  403.     char *follow_buf = Nullch;
  404.     char *dist_buf = Nullch;
  405.     char *line_buf = Nullch;
  406.     register char *s, *h;
  407.     register int i;
  408.     char scrbuf[512];
  409.     bool upper = FALSE;
  410.     bool lastcomp = FALSE;
  411.     int metabit = 0;
  412.  
  413.     while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
  414. #ifdef DEBUGGING
  415.     if (debug & DEB_INTRP)
  416.         printf("dointerp till %s at %s\n",stoppers?stoppers:"",pattern);
  417. #endif
  418.     if (*pattern == '%' && pattern[1]) {
  419.         upper = FALSE;
  420.         lastcomp = FALSE;
  421.         for (s=Nullch; !s; ) {
  422.         switch (*++pattern) {
  423.         case '^':
  424.             upper = TRUE;
  425.             break;
  426.         case '_':
  427.             lastcomp = TRUE;
  428.             break;
  429.         case '/':
  430. #ifdef ARTSRCH
  431.             s = scrbuf;
  432.             if (!index("/?g",pattern[-2]))
  433.             *s++ = '/';
  434.             strcpy(s,lastpat);
  435.             s += strlen(s);
  436.             if (pattern[-2] != 'g') {
  437.             if (index("/?",pattern[-2]))
  438.                 *s++ = pattern[-2];
  439.             else
  440.                 *s++ = '/';
  441.             if (art_howmuch == 1)
  442.                 *s++ = 'h';
  443.             else if (art_howmuch == 2)
  444.                 *s++ = 'a';
  445.             if (art_doread)
  446.                 *s++ = 'r';
  447.             }
  448.             *s = '\0';
  449.             s = scrbuf;
  450. #else
  451.             s = nullstr;
  452. #endif
  453.             break;
  454.         case '{':
  455.             pattern = cpytill(scrbuf,pattern+1,'}');
  456.             if (s = index(scrbuf,'-'))
  457.             *s++ = '\0';
  458.             else
  459.             s = nullstr;
  460.             s = getval(scrbuf,s);
  461.             break;
  462.         case '[':
  463.             pattern = cpytill(scrbuf,pattern+1,']');
  464.             i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
  465.             if (line_buf)
  466.             free(line_buf);
  467.             s = line_buf = fetchlines(art,i);
  468.             break;
  469. #ifdef CONDSUB
  470.         case '(': {
  471.             COMPEX *oldbra_compex = bra_compex;
  472.             COMPEX cond_compex;
  473.             char rch;
  474.             bool matched;
  475.             
  476.             init_compex(&cond_compex);
  477.             pattern = dointerp(dest,destsize,pattern+1,"!=");
  478.             rch = *pattern;
  479.             if (rch == '!')
  480.             pattern++;
  481.             if (*pattern != '=')
  482.             goto getout;
  483.             pattern = cpytill(scrbuf,pattern+1,'?');
  484.             if (!*pattern)
  485.             goto getout;
  486.             if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
  487.             printf("%s: %s\n",scrbuf,s) FLUSH;
  488.             pattern += strlen(pattern);
  489.             goto getout;
  490.             }
  491.             matched = (execute(&cond_compex,dest) != Nullch);
  492.             if (cond_compex.nbra)    /* were there brackets? */
  493.             bra_compex = &cond_compex;
  494.             if (matched==(rch == '=')) {
  495.             pattern = dointerp(dest,destsize,pattern+1,":)");
  496.             if (*pattern == ':')
  497.                 pattern = skipinterp(pattern+1,")");
  498.             }
  499.             else {
  500.             pattern = skipinterp(pattern+1,":)");
  501.             if (*pattern == ':')
  502.                 pattern++;
  503.             pattern = dointerp(dest,destsize,pattern,")");
  504.             }
  505.             s = dest;
  506.             bra_compex = oldbra_compex;
  507.             free_compex(&cond_compex);
  508.             break;
  509.         }
  510. #endif
  511. #ifdef BACKTICK
  512.         case '`': {
  513.             FILE *pipefp, *popen();
  514.  
  515.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
  516.             pipefp = popen(scrbuf,"r");
  517.             if (pipefp != Nullfp) {
  518.             int len;
  519.  
  520.             len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
  521.                 pipefp);
  522.             scrbuf[len] = '\0';
  523.             pclose(pipefp);
  524.             }
  525.             else {
  526.             printf("\nCan't run %s\n",scrbuf);
  527.             *scrbuf = '\0';
  528.             }
  529.             for (s=scrbuf; *s; s++) {
  530.             if (*s == '\n') {
  531.                 if (s[1])
  532.                 *s = ' ';
  533.                 else
  534.                 *s = '\0';
  535.             }
  536.             }
  537.             s = scrbuf;
  538.             break;
  539.         }
  540. #endif
  541. #ifdef PROMPTTTY
  542.         case '"':
  543.             pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
  544.             fputs(scrbuf,stdout) FLUSH;
  545.             resetty();
  546.             gets(scrbuf);
  547.             noecho();
  548.             crmode();
  549.             s = scrbuf;
  550.             break;
  551. #endif
  552.         case '~':
  553.             s = homedir;
  554.             break;
  555.         case '.':
  556.             s = dotdir;
  557.             break;
  558.         case '$':
  559.             s = scrbuf;
  560.             sprintf(s,"%d",getpid());
  561.             break;
  562.         case '0': case '1': case '2': case '3': case '4':
  563.         case '5': case '6': case '7': case '8': case '9':
  564. #ifdef CONDSUB
  565.             s = getbracket(bra_compex,*pattern - '0');
  566. #else
  567.             s = nullstr;
  568. #endif
  569.             break;
  570.         case 'a':
  571.             s = scrbuf;
  572.             sprintf(s,"%ld",(long)art);
  573.             break;
  574.         case 'A':
  575. #ifdef LINKART
  576.             s = linkartname;    /* so Eunice people get right file */
  577. #else
  578.             s = scrbuf;
  579.             sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
  580. #endif
  581.             break;
  582.         case 'b':
  583.             s = savedest;
  584.             break;
  585.         case 'B':
  586.             s = scrbuf;
  587.             sprintf(s,"%ld",(long)savefrom);
  588.             break;
  589.         case 'c':
  590.             s = ngdir;
  591.             break;
  592.         case 'C':
  593.             s = ngname;
  594.             break;
  595.         case 'd':
  596.             s = scrbuf;
  597.             sprintf(s,"%s/%s",spool,ngdir);
  598.             break;
  599.         case 'D':
  600.             s = dist_buf = fetchlines(art,DIST_LINE);
  601.             break;
  602.         case 'f':            /* from line */
  603. #ifdef ASYNC_PARSE
  604.             parse_maybe(art);
  605. #endif
  606.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  607.                         /* was there a reply line? */
  608.             if (!(s=reply_buf))
  609.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  610.             }
  611.             else if (!(s = from_buf))
  612.             s = from_buf = fetchlines(art,FROM_LINE);
  613.             break;
  614.         case 'F':
  615. #ifdef ASYNC_PARSE
  616.             parse_maybe(art);
  617. #endif
  618.             if (htype[FOLLOW_LINE].ht_minpos >= 0)
  619.                     /* is there a Followup-To line? */
  620.             s = follow_buf = fetchlines(art,FOLLOW_LINE);
  621.             else {
  622.             int off;
  623.         
  624.             s = ngs_buf = fetchlines(art,NGS_LINE);
  625.             if (h = instr(s,"net.general")) {
  626.                 off = h-s;
  627.                 strncpy(scrbuf,s,off+4);
  628.                 strcpy(scrbuf+off+4,"followup");
  629.                 safecpy(scrbuf+off+12,h+11,sizeof(scrbuf));
  630.                 s = scrbuf;
  631.             }
  632.             }
  633.             break;
  634.         case 'h':            /* header file name */
  635.             s = headname;
  636.             break;
  637.         case 'H':            /* host name */
  638.             s = sitename;
  639.             break;
  640.         case 'i':
  641.             if (!(s=artid_buf))
  642.             s = artid_buf = fetchlines(art,MESSID_LINE);
  643.             if (*s && *s != '<') {
  644.             sprintf(scrbuf,"<%s>",artid_buf);
  645.             s = scrbuf;
  646.             }
  647.             break;
  648.         case 'I':            /* ref article indicator */
  649.             s = scrbuf;
  650.             sprintf(scrbuf,"'%s'",indstr);
  651.             break;
  652.         case 'l':            /* rn library */
  653. #ifdef NEWSADMIN
  654.             s = newsadmin;
  655. #else
  656.             s = "???";
  657. #endif
  658.             break;
  659.         case 'L':            /* login id */
  660.             s = logname;
  661.             break;
  662.         case 'm':        /* current mode */
  663.             s = scrbuf;
  664.             *s = mode;
  665.             s[1] = '\0';
  666.             break;
  667.         case 'M':
  668. #ifdef DELAYMARK
  669.             sprintf(scrbuf,"%ld",(long)dmcount);
  670.             s = scrbuf;
  671. #else
  672.             s = nullstr;
  673. #endif
  674.             break;
  675.         case 'n':            /* newsgroups */
  676.             s = ngs_buf = fetchlines(art,NGS_LINE);
  677.             break;
  678.         case 'N':            /* full name */
  679.             s = getval("NAME",realname);
  680.             break;
  681.         case 'o':            /* organization */
  682.             s = getval("ORGANIZATION",orgname);
  683. #ifdef ORGFILE
  684.             if (*s == '/') {
  685.             FILE *ofp = fopen(s,"r");
  686.  
  687.             if (ofp) {
  688.                 fgets(scrbuf,sizeof scrbuf,ofp);
  689.                 fclose(ofp);
  690.                 s = scrbuf;
  691.                 s[strlen(s)-1] = '\0';
  692.             }
  693.             }
  694. #endif
  695.             break;
  696.         case 'O':
  697.             s = origdir;
  698.             break;
  699.         case 'p':
  700.             s = cwd;
  701.             break;
  702.         case 'P':
  703.             s = spool;
  704.             break;
  705.         case 'r':
  706. #ifdef ASYNC_PARSE
  707.             parse_maybe(art);
  708. #endif
  709.             if (htype[REFS_LINE].ht_minpos >= 0) {
  710.             refs_buf = fetchlines(art,REFS_LINE);
  711.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  712.             }
  713.             else
  714.             *scrbuf = '\0';
  715.             s = rindex(scrbuf,'<');
  716.             break;
  717.         case 'R':
  718. #ifdef ASYNC_PARSE
  719.             parse_maybe(art);
  720. #endif
  721.             if (htype[REFS_LINE].ht_minpos >= 0) {
  722.             refs_buf = fetchlines(art,REFS_LINE);
  723.             refscpy(scrbuf,(sizeof scrbuf),refs_buf);
  724.             /* no more than 3 prior references allowed,
  725.             ** including the one concatenated below */
  726.             if ((s = rindex(scrbuf,'<')) > scrbuf) {
  727.                 *s = '\0';
  728.                 h = rindex(scrbuf,'<');
  729.                 *s = '<';
  730.                 if (h > scrbuf)
  731.                 strcpy(scrbuf,h);
  732.             }
  733.             }
  734.             else
  735.             *scrbuf = '\0';
  736.             if (!artid_buf)
  737.             artid_buf = fetchlines(art,MESSID_LINE);
  738.             if (artid_buf[0] == '<')
  739.             safecat(scrbuf,artid_buf,sizeof(scrbuf));
  740.             else if (artid_buf[0]) {
  741.             char tmpbuf[64];
  742.     
  743.             sprintf(tmpbuf,"<%s>",artid_buf);
  744.             safecat(scrbuf,tmpbuf,sizeof(scrbuf));
  745.             }
  746.             s = scrbuf;
  747.             break;
  748.         case 's':
  749.             if (!(s=subj_buf))
  750.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  751.                         /* get subject handy */
  752.             while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  753.                         /* skip extra Re: */
  754.             s += 3;
  755.             if (*s == ' ')
  756.                 s++;
  757.             }
  758.             if (h = instr(s,"- (nf"))
  759.             *h = '\0';
  760.             break;
  761.         case 'S':
  762.             if (!(s=subj_buf))
  763.             s = subj_buf = fetchsubj(art,TRUE,TRUE);
  764.                         /* get subject handy */
  765.             if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
  766.                         /* skip extra Re: */
  767.             s += 3;
  768.             if (*s == ' ')
  769.                 s++;
  770.             }
  771.             break;
  772.         case 't':
  773.         case 'T':
  774. #ifdef ASYNC_PARSE
  775.             parse_maybe(art);
  776. #endif
  777.             if (htype[REPLY_LINE].ht_minpos >= 0) {
  778.                     /* was there a reply line? */
  779.             if (!(s=reply_buf))
  780.                 s = reply_buf = fetchlines(art,REPLY_LINE);
  781.             }
  782.             else if (!(s = from_buf))
  783.             s = from_buf = fetchlines(art,FROM_LINE);
  784.             if (*pattern == 'T') {
  785.             if (htype[PATH_LINE].ht_minpos >= 0) {
  786.                     /* should we substitute path? */
  787.                 s = path_buf = fetchlines(art,PATH_LINE);
  788.             }
  789.             i = strlen(sitename);
  790.             if (strnEQ(sitename,s,i) && s[i] == '!')
  791.                 s += i + 1;
  792.             }
  793.             if ((h=index(s,'(')) != Nullch)
  794.                         /* strip garbage from end */
  795.             *(h-1) = '\0';
  796.             else if ((h=index(s,'<')) != Nullch) {
  797.                         /* or perhaps from beginning */
  798.             s = h+1;
  799.             if ((h=index(s,'>')) != Nullch)
  800.                 *h = '\0';
  801.             }
  802.             break;
  803.         case 'u':
  804.             sprintf(scrbuf,"%ld",(long)toread[ng]);
  805.             s = scrbuf;
  806.             break;
  807.         case 'U':
  808.             sprintf(scrbuf,"%ld",
  809.             (long)(((ART_NUM)toread[ng]) - 1 + was_read(art)));
  810.             s = scrbuf;
  811.             break;
  812.         case 'x':            /* news library */
  813.             s = lib;
  814.             break;
  815.         case 'X':            /* rn library */
  816.             s = rnlib;
  817.             break;
  818.         case 'z':
  819. #ifdef LINKART
  820.             s = linkartname;    /* so Eunice people get right file */
  821. #else
  822.             s = scrbuf;
  823.             sprintf(s,"%ld",(long)art);
  824. #endif
  825.             if (stat(s,&filestat) < 0)
  826.             filestat.st_size = 0L;
  827.             sprintf(scrbuf,"%5ld",(long)filestat.st_size);
  828.             s = scrbuf;
  829.             break;
  830.         default:
  831.             if (--destsize <= 0)
  832.             abort_interp();
  833.             *dest++ = *pattern | metabit;
  834.             s = nullstr;
  835.             break;
  836.         }
  837.         }
  838.         if (!s)
  839.         s = nullstr;
  840.         pattern++;
  841.         if (upper || lastcomp) {
  842.         char *t;
  843.  
  844.         if (s != scrbuf) {
  845.             safecpy(scrbuf,s,(sizeof scrbuf));
  846.             s = scrbuf;
  847.         }
  848.         if (upper || !(t=rindex(s,'/')))
  849.             t = s;
  850.         while (*t && !isalpha(*t))
  851.             t++;
  852.         if (islower(*t))
  853.             *t = toupper(*t);
  854.         }
  855.         i = metabit;        /* maybe get into register */
  856.         if (s == dest) {
  857.         while (*dest) {
  858.             if (--destsize <= 0)
  859.             abort_interp();
  860.             *dest++ |= i;
  861.         }
  862.         }
  863.         else {
  864.         while (*s) {
  865.             if (--destsize <= 0)
  866.             abort_interp();
  867.             *dest++ = *s++ | i;
  868.         }
  869.         }
  870.     }
  871.     else {
  872.         if (--destsize <= 0)
  873.         abort_interp();
  874.         if (*pattern == '^' && pattern[1]) {
  875.         ++pattern;            /* skip uparrow */
  876.         i = *pattern;        /* get char into a register */
  877.         if (i == '?')
  878.             *dest++ = '\177' | metabit;
  879.         else if (i == '(') {
  880.             metabit = 0200;
  881.             destsize++;
  882.         }
  883.         else if (i == ')') {
  884.             metabit = 0;
  885.             destsize++;
  886.         }
  887.         else
  888.             *dest++ = i & 037 | metabit;
  889.         pattern++;
  890.         }
  891.         else if (*pattern == '\\' && pattern[1]) {
  892.         ++pattern;            /* skip backslash */
  893.         i = *pattern;        /* get char into a register */
  894.     
  895.         /* this used to be a switch but the if may save space */
  896.         
  897.         if (i >= '0' && i <= '7') {
  898.             i = 1;
  899.             while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
  900.             i <<= 3;
  901.             i += *pattern++ - '0';
  902.             }
  903.             *dest++ = i & 0377 | metabit;
  904.             --pattern;
  905.         }
  906.         else if (i == 'b')
  907.             *dest++ = '\b' | metabit;
  908.         else if (i == 'f')
  909.             *dest++ = '\f' | metabit;
  910.         else if (i == 'n')
  911.             *dest++ = '\n' | metabit;
  912.         else if (i == 'r')
  913.             *dest++ = '\r' | metabit;
  914.         else if (i == 't')
  915.             *dest++ = '\t' | metabit;
  916.         else
  917.             *dest++ = i | metabit;
  918.         pattern++;
  919.         }
  920.         else
  921.         *dest++ = *pattern++ | metabit;
  922.     }
  923.     }
  924.     *dest = '\0';
  925. getout:
  926.     if (subj_buf != Nullch)    /* return any checked out storage */
  927.     free(subj_buf);
  928.     if (ngs_buf != Nullch)
  929.     free(ngs_buf);
  930.     if (refs_buf != Nullch)
  931.     free(refs_buf);
  932.     if (artid_buf != Nullch)
  933.     free(artid_buf);
  934.     if (reply_buf != Nullch)
  935.     free(reply_buf);
  936.     if (from_buf != Nullch)
  937.     free(from_buf);
  938.     if (path_buf != Nullch)
  939.     free(path_buf);
  940.     if (follow_buf != Nullch)
  941.     free(follow_buf);
  942.     if (dist_buf != Nullch)
  943.     free(dist_buf);
  944.     if (line_buf != Nullch)
  945.     free(line_buf);
  946.     return pattern;            /* where we left off */
  947. }
  948.  
  949. void
  950. interp(dest,destsize,pattern)
  951. char *dest;
  952. int destsize;
  953. char *pattern;
  954. {
  955.     dointerp(dest,destsize,pattern,Nullch);
  956. #ifdef DEBUGGING
  957.     if (debug & DEB_FILEXP)
  958.     fputs(dest,stdout);
  959. #endif
  960. }
  961.  
  962. /* copy a references line, normalizing as we go */
  963.  
  964. void
  965. refscpy(dest,destsize,src)
  966. register char *dest, *src;
  967. register int destsize;
  968. {
  969.     register char *dot, *at, *beg;
  970.     char tmpbuf[64];
  971.     
  972.     while (*src) {
  973.     if (*src != '<') {
  974.         if (--destsize <= 0)
  975.         break;
  976.         *dest++ = '<';
  977.         at = dot = Nullch;
  978.         beg = src;
  979.         while (*src && *src != ' ' && *src != ',') {
  980.         if (*src == '.')
  981.             dot = src;
  982.         else if (*src == '@')
  983.             at = src;
  984.         if (--destsize <= 0)
  985.             break;
  986.         *dest++ = *src++;
  987.         }
  988.         if (destsize <= 0)
  989.         break;
  990.         if (dot && !at) {
  991.         int len;
  992.  
  993.         *dest = *dot++ = '\0';
  994.         sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
  995.         len = strlen(tmpbuf);
  996.         if (destsize > len) {
  997.             strcpy(dest,tmpbuf);
  998.             dest = dest + len;
  999.             destsize -= len;
  1000.         }
  1001.         }
  1002.         if (--destsize <= 0)
  1003.         break;
  1004.         *dest++ = '>';
  1005.     }
  1006.     else {
  1007.         while (*src && --destsize > 0 && (*dest++ = *src++) != '>') ;
  1008.         if (destsize <= 0)
  1009.         break;
  1010.     }
  1011.     while (*src == ' ' || *src == ',') src++;
  1012.     if (*src && --destsize > 0)
  1013.         *dest++ = ' ';
  1014.     }
  1015.     *dest = '\0';
  1016.  
  1017. /* get the person's real name from /etc/passwd */
  1018. /* (string is overwritten, so it must be copied) */
  1019.  
  1020. char *
  1021. getrealname(uid)
  1022. int uid;
  1023. {
  1024.     char *s, *c;
  1025.  
  1026. #ifdef PASSNAMES
  1027. #ifdef GETPWENT
  1028.     struct passwd *pwd = getpwuid(uid);
  1029.     
  1030.     s = pwd->pw_gecos;
  1031. #else
  1032.     char tmpbuf[512];
  1033.     int i;
  1034.  
  1035.     getpw(uid, tmpbuf);
  1036.     for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
  1037.     if (s)
  1038.         s = index(s,':')+1;
  1039.     }
  1040.     if (!s)
  1041.     return nullstr;
  1042.     cpytill(tmpbuf,s,':');
  1043.     s = tmpbuf;
  1044. #endif
  1045. #ifdef BERKNAMES
  1046. #ifdef BERKJUNK
  1047.     while (*s && !isalnum(*s) && *s != '&') s++;
  1048. #endif
  1049.     if ((c = index(s, ',')) != Nullch)
  1050.     *c = '\0';
  1051.     if ((c = index(s, ';')) != Nullch)
  1052.     *c = '\0';
  1053.     s = cpytill(buf,s,'&');
  1054.     if (*s == '&') {            /* whoever thought this one up was */
  1055.     c = buf + strlen(buf);        /* in the middle of the night */
  1056.     strcat(c,logname);        /* before the morning after */
  1057.     strcat(c,s+1);
  1058.     if (islower(*c))
  1059.         *c = toupper(*c);        /* gack and double gack */
  1060.     }
  1061. #else
  1062.     if ((c = index(s, '(')) != Nullch)
  1063.     *c = '\0';
  1064.     if ((c = index(s, '-')) != Nullch)
  1065.     s = c;
  1066.     strcpy(buf,tmpbuf);
  1067. #endif
  1068. #ifdef GETPWENT
  1069.     endpwent();
  1070. #endif
  1071.     return buf;                /* return something static */
  1072. #else
  1073.     if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
  1074.     fgets(buf,sizeof buf,tmpfp);
  1075.     fclose(tmpfp);
  1076.     buf[strlen(buf)-1] = '\0';
  1077.     return buf;
  1078.     }
  1079.     return "PUT YOUR NAME HERE";
  1080. #endif
  1081. }
  1082.  
  1083. static void
  1084. abort_interp()
  1085. {
  1086.     fputs("\n% interp buffer overflow!\n",stdout) FLUSH;
  1087.     sig_catcher(0);
  1088. }
  1089.