home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / trn-3.3 / part09 / intrp.c < prev    next >
C/C++ Source or Header  |  1993-11-27  |  28KB  |  1,259 lines

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