home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / trn_12.zip / src / intrp.c < prev    next >
C/C++ Source or Header  |  1993-12-05  |  30KB  |  1,255 lines

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