home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trn / part09 / intrp.c next >
Encoding:
C/C++ Source or Header  |  1991-12-02  |  26.4 KB  |  1,217 lines

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