+/* $Id: intrp.c,v 3.0 1992/02/01 03:09:32 davison Trn $
+ */
+/* This software is Copyright 1991 by Stan Barber.
+ *
+ * Permission is hereby granted to copy, reproduce, redistribute or otherwise
+ * use this software as long as: there is no monetary profit gained
+ * specifically from the use or reproduction of this software, it is not
+ * sold, rented, traded or otherwise marketed, and this copyright notice is
+ * included prominently in any copy made.
+ *
+ * The author make no claims as to the fitness or correctness of this software
+ * for any use whatsoever, and it is provided as is. Any use of this software
+ * is at the user's own risk.
+ */
+
+#include "EXTERN.h"
+#include "common.h"
+#include "util.h"
+#include "search.h"
+#include "cache.h"
+#include "bits.h"
+#include "head.h"
+#include "trn.h"
+#include "artsrch.h"
+#include "ng.h"
+#include "ngdata.h"
+#include "respond.h"
+#include "rcstuff.h"
+#include "artio.h"
+#include "init.h"
+#include "term.h"
+#include "final.h"
+#include "rthread.h"
+#include "rt-select.h"
+#include "nntp.h"
+#include "INTERN.h"
+#include "intrp.h"
+
+static char * regexp_specials = "^$.*[\\/?%";
+
+char orgname[] = ORGNAME;
+
+#ifdef HAS_UNAME
+#include <sys/utsname.h>
+struct utsname utsn;
+#endif
+
+#ifdef TILDENAME
+static char *tildename = Nullch;
+static char *tildedir = Nullch;
+#endif
+
+#ifdef CONDSUB
+char *skipinterp _((char *,char *));
+#endif
+
+static void abort_interp _((void));
+
+void
+intrp_init(tcbuf)
+char *tcbuf;
+{
+ char *getlogin();
+
+ /* get environmental stuff */
+
+#ifdef NEWS_ADMIN
+ {
+#ifdef HAS_GETPWENT
+ struct passwd *getpwnam();
+ struct passwd *pwd = getpwnam(NEWS_ADMIN);
+
+ if (pwd != NULL)
+ newsuid = pwd->pw_uid;
+#else
+#ifdef TILDENAME
+ char tildenews[2+sizeof NEWS_ADMIN];
+ strcpy(tildenews, "~");
+ strcat(tildenews, NEWS_ADMIN);
+ (void) filexp(tildenews);
+#else
+ ??? "Define either HAS_GETPWENT or TILDENAME to get NEWS_ADMIN"
+#endif /* TILDENAME */
+#endif /* HAS_GETPWENT */
+ }
+#endif /* NEWS_ADMIN */
+ /* get home directory */
+
+ homedir = getenv("HOME");
+ if (homedir == Nullch)
+ homedir = getenv("LOGDIR");
+
+ dotdir = getval("DOTDIR",homedir);
+
+ /* get login name */
+
+ logname = getenv("USER");
+ if (logname == Nullch)
+ logname = getenv("LOGNAME");
+#ifdef GETLOGIN
+ if (logname == Nullch)
+ logname = savestr(getlogin());
+#endif
+
+ spool = savestr(filexp(NEWSSPOOL)); /* usually /usr/spool/news */
+ threaddir = filexp(THREAD_DIR);
+ if (strEQ(threaddir,spool))
+ threaddir = spool;
+ else
+ threaddir = savestr(threaddir);
+ overviewdir = filexp(OVERVIEW_DIR);
+ if (strEQ(overviewdir,spool))
+ overviewdir = spool;
+ else
+ overviewdir = savestr(overviewdir);
+
+#ifdef NEWS_ADMIN
+ /* if this is the news admin than load his UID into newsuid */
+
+ if ( strEQ(logname,NEWS_ADMIN) )
+ newsuid = getuid();
+#endif
+
+ if (checkflag) /* that getwd below takes ~1/3 sec. */
+ return; /* and we do not need it for -c */
+ getwd(tcbuf); /* find working directory name */
+ origdir = savestr(tcbuf); /* and remember it */
+
+ /* get the real name of the person (%N) */
+ /* Must be done after logname is read in because BERKNAMES uses that */
+
+ strcpy(tcbuf,getrealname((long)getuid()));
+ realname = savestr(tcbuf);
+
+ /* name of header file (%h) */
+
+ headname = savestr(filexp(HEADNAME));
+
+ /* host name that goes in postings (%H) */
+
+ phostname = PHOSTNAME;
+ if (*phostname == '/') {
+ if ((tmpfp = fopen(phostname,"r")) == NULL) {
+ printf("Warning: Couldn't open %s to determine hostname!\n",
+ phostname);
+ sig_catcher(0);
+ }
+ fgets(buf, sizeof(buf), tmpfp);
+ if (buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = 0;
+ fclose(tmpfp);
+ }
+ else {
+#ifdef HAS_GETHOSTNAME
+ gethostname(buf,sizeof buf);
+#else
+# ifdef HAS_UNAME
+ /* get sysname */
+ uname(&utsn);
+ strcpy(buf,utsn.nodename);
+# else
+# ifdef PHOSTCMD
+ {
+ FILE *popen();
+ FILE *pipefp = popen(PHOSTCMD,"r");
+
+ if (pipefp == Nullfp) {
+ printf("Can't find hostname\n");
+ sig_catcher(0);
+ }
+ fgets(buf,sizeof buf,pipefp);
+ buf[strlen(buf)-1] = '\0'; /* wipe out newline */
+ pclose(pipefp);
+ }
+# else
+ *buf = '\0';
+# endif /* PHOSTCMD */
+# endif /* HAS_UNAME */
+#endif /* HAS_GETHOSTNAME */
+ if (*buf) {
+ char *cp = index(buf,'.');
+ if (cp)
+ *cp = '\0';
+ cp = index(phostname,'.');
+ if (cp)
+ strcat(buf,cp);
+ phostname = savestr(buf);
+ }
+ }
+}
+
+/* expand filename via %, ~, and $ interpretation */
+/* returns pointer to static area */
+/* Note that there is a 1-deep cache of ~name interpretation */
+
+char *
+filexp(s)
+register char *s;
+{
+ static char filename[CBUFLEN];
+ char scrbuf[CBUFLEN];
+ register char *d;
+
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("< %s\n",s) FLUSH;
+#endif
+ interp(filename, (sizeof filename), s);
+ /* interpret any % escapes */
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("%% %s\n",filename) FLUSH;
+#endif
+ s = filename;
+ if (*s == '~') { /* does destination start with ~? */
+ if (!*(++s) || *s == '/') {
+ sprintf(scrbuf,"%s%s",homedir,s);
+ /* swap $HOME for it */
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("~ %s\n",scrbuf) FLUSH;
+#endif
+ strcpy(filename,scrbuf);
+ }
+ else {
+#ifdef TILDENAME
+ for (d=scrbuf; isalnum(*s); s++,d++)
+ *d = *s;
+ *d = '\0';
+ if (tildedir && strEQ(tildename,scrbuf)) {
+ strcpy(scrbuf,tildedir);
+ strcat(scrbuf, s);
+ strcpy(filename, scrbuf);
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("r %s %s\n",tildename,tildedir) FLUSH;
+#endif
+ }
+ else {
+ if (tildename) {
+ free(tildename);
+ free(tildedir);
+ }
+ tildedir = Nullch;
+ tildename = savestr(scrbuf);
+#ifdef HAS_GETPWENT /* getpwnam() is not the paragon of efficiency */
+ {
+#ifdef notdef
+ struct passwd *getpwnam _((char*));
+#endif
+ struct passwd *pwd = getpwnam(tildename);
+ if ( pwd == NULL){
+ printf("%s is an unknown user. Using default.\n",tildename) FLUSH;
+ return(Nullch);
+ }
+ sprintf(scrbuf,"%s%s",pwd->pw_dir,s);
+ tildedir = savestr(pwd->pw_dir);
+ strcpy(filename,scrbuf);
+ endpwent();
+ }
+#else /* this will run faster, and is less D space */
+ { /* just be sure LOGDIRFIELD is correct */
+ FILE *pfp = fopen("/etc/passwd","r");
+ char tmpbuf[512];
+ int i;
+
+ if (pfp == Nullfp) {
+ printf(cantopen,"passwd") FLUSH;
+ sig_catcher(0);
+ }
+ while (fgets(tmpbuf,512,pfp) != Nullch) {
+ d = cpytill(scrbuf,tmpbuf,':');
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("p %s\n",tmpbuf) FLUSH;
+#endif
+ if (strEQ(scrbuf,tildename)) {
+ for (i=LOGDIRFIELD-2; i; i--) {
+ if (d)
+ d = index(d+1,':');
+ }
+ if (d) {
+ cpytill(scrbuf,d+1,':');
+ tildedir = savestr(scrbuf);
+ strcat(scrbuf,s);
+ strcpy(filename,scrbuf);
+ }
+ break;
+ }
+ }
+ fclose(pfp);
+ }
+#endif
+ }
+#else /* !TILDENAME */
+#ifdef VERBOSE
+ IF(verbose)
+ fputs("~loginname not implemented.\n",stdout) FLUSH;
+ ELSE
+#endif
+#ifdef TERSE
+ fputs("~login not impl.\n",stdout) FLUSH;
+#endif
+#endif
+ }
+ }
+ else if (*s == '$') { /* starts with some env variable? */
+ d = scrbuf;
+ *d++ = '%';
+ if (s[1] == '{')
+ strcpy(d,s+2);
+ else {
+ *d++ = '{';
+ for (s++; isalnum(*s); s++) *d++ = *s;
+ /* skip over token */
+ *d++ = '}';
+ strcpy(d,s);
+ }
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("$ %s\n",scrbuf) FLUSH;
+#endif
+ interp(filename, (sizeof filename), scrbuf);
+ /* this might do some extra '%'s but */
+ /* that is how the Mercedes Benz */
+ }
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ printf("> %s\n",filename) FLUSH;
+#endif
+ return filename;
+}
+
+#ifdef CONDSUB
+/* skip interpolations */
+
+char *
+skipinterp(pattern,stoppers)
+register char *pattern;
+char *stoppers;
+{
+
+ while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
+#ifdef DEBUG
+ if (debug & DEB_INTRP)
+ printf("skipinterp till %s at %s\n",stoppers?stoppers:"",pattern);
+#endif
+ if (*pattern == '%' && pattern[1]) {
+ switch (*++pattern) {
+ case '{':
+ for (pattern++; *pattern && *pattern != '}'; pattern++)
+ if (*pattern == '\\')
+ pattern++;
+ break;
+ case '[':
+ for (pattern++; *pattern && *pattern != ']'; pattern++)
+ if (*pattern == '\\')
+ pattern++;
+ break;
+#ifdef CONDSUB
+ case '(': {
+ pattern = skipinterp(pattern+1,"!=");
+ if (!*pattern)
+ goto getout;
+ for (pattern++; *pattern && *pattern != '?'; pattern++)
+ if (*pattern == '\\')
+ pattern++;
+ if (!*pattern)
+ goto getout;
+ pattern = skipinterp(pattern+1,":)");
+ if (*pattern == ':')
+ pattern = skipinterp(pattern+1,")");
+ break;
+ }
+#endif
+#ifdef BACKTICK
+ case '`': {
+ pattern = skipinterp(pattern+1,"`");
+ break;
+ }
+#endif
+#ifdef PROMPTTTY
+ case '"':
+ pattern = skipinterp(pattern+1,"\"");
+ break;
+#endif
+ default:
+ break;
+ }
+ pattern++;
+ }
+ else {
+ if (*pattern == '^' && pattern[1])
+ pattern += 2;
+ else if (*pattern == '\\' && pattern[1])
+ pattern += 2;
+ else
+ pattern++;
+ }
+ }
+getout:
+ return pattern; /* where we left off */
+}
+#endif
+
+/* interpret interpolations */
+
+char *
+dointerp(dest,destsize,pattern,stoppers)
+register char *dest;
+register int destsize;
+register char *pattern;
+char *stoppers;
+{
+ char *subj_buf = Nullch;
+ char *ngs_buf = Nullch;
+ char *refs_buf = Nullch;
+ char *artid_buf = Nullch;
+ char *reply_buf = Nullch;
+ char *from_buf = Nullch;
+ char *path_buf = Nullch;
+ char *follow_buf = Nullch;
+ char *dist_buf = Nullch;
+ char *line_buf = Nullch;
+ register char *s, *h;
+ register int i;
+ char scrbuf[512];
+ char spfbuf[512];
+ bool upper = FALSE;
+ bool lastcomp = FALSE;
+ bool re_quote = FALSE;
+ bool proc_sprintf = FALSE;
+ int metabit = 0;
+
+ while (*pattern && (!stoppers || !index(stoppers,*pattern))) {
+#ifdef DEBUG
+ if (debug & DEB_INTRP)
+ printf("dointerp till %s at %s\n",stoppers?stoppers:"",pattern);
+#endif
+ if (*pattern == '%' && pattern[1]) {
+ upper = FALSE;
+ lastcomp = FALSE;
+ re_quote = FALSE;
+ proc_sprintf = FALSE;
+ for (s=Nullch; !s; ) {
+ switch (*++pattern) {
+ case '^':
+ upper = TRUE;
+ break;
+ case '_':
+ lastcomp = TRUE;
+ break;
+ case '\\':
+ re_quote = TRUE;
+ break;
+ case ':':
+ proc_sprintf = TRUE;
+ h = spfbuf;
+ *h++ = '%';
+ pattern++; /* Skip over ':' */
+ while (*pattern
+ && (*pattern=='.' || *pattern=='-' || isdigit(*pattern))) {
+ *h++ = *pattern++;
+ }
+ *h++ = 's';
+ *h++ = '\0';
+ pattern--;
+ break;
+ case '/':
+#ifdef ARTSRCH
+ s = scrbuf;
+ if (!index("/?g",pattern[-2]))
+ *s++ = '/';
+ strcpy(s,lastpat);
+ s += strlen(s);
+ if (pattern[-2] != 'g') {
+ if (index("/?",pattern[-2]))
+ *s++ = pattern[-2];
+ else
+ *s++ = '/';
+ if (art_howmuch == 1)
+ *s++ = 'h';
+ else if (art_howmuch == 2)
+ *s++ = 'a';
+ if (art_doread)
+ *s++ = 'r';
+ }
+ *s = '\0';
+ s = scrbuf;
+#else
+ s = nullstr;
+#endif
+ break;
+ case '{':
+ pattern = cpytill(scrbuf,pattern+1,'}');
+ if (s = index(scrbuf,'-'))
+ *s++ = '\0';
+ else
+ s = nullstr;
+ s = getval(scrbuf,s);
+ break;
+ case '[':
+ pattern = cpytill(scrbuf,pattern+1,']');
+ i = set_line_type(scrbuf,scrbuf+strlen(scrbuf));
+ if (line_buf)
+ free(line_buf);
+ s = line_buf = fetchlines(art,i);
+ break;
+#ifdef CONDSUB
+ case '(': {
+ COMPEX *oldbra_compex = bra_compex;
+ COMPEX cond_compex;
+ char rch;
+ bool matched;
+
+ init_compex(&cond_compex);
+ pattern = dointerp(dest,destsize,pattern+1,"!=");
+ rch = *pattern;
+ if (rch == '!')
+ pattern++;
+ if (*pattern != '=')
+ goto getout;
+ pattern = cpytill(scrbuf,pattern+1,'?');
+ if (!*pattern)
+ goto getout;
+ if (s = compile(&cond_compex,scrbuf,TRUE,TRUE)) {
+ printf("%s: %s\n",scrbuf,s) FLUSH;
+ pattern += strlen(pattern);
+ goto getout;
+ }
+ matched = (execute(&cond_compex,dest) != Nullch);
+ if (cond_compex.nbra) /* were there brackets? */
+ bra_compex = &cond_compex;
+ if (matched==(rch == '=')) {
+ pattern = dointerp(dest,destsize,pattern+1,":)");
+ if (*pattern == ':')
+ pattern = skipinterp(pattern+1,")");
+ }
+ else {
+ pattern = skipinterp(pattern+1,":)");
+ if (*pattern == ':')
+ pattern++;
+ pattern = dointerp(dest,destsize,pattern,")");
+ }
+ s = dest;
+ bra_compex = oldbra_compex;
+ free_compex(&cond_compex);
+ break;
+ }
+#endif
+#ifdef BACKTICK
+ case '`': {
+ FILE *pipefp, *popen();
+
+ pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
+ pipefp = popen(scrbuf,"r");
+ if (pipefp != Nullfp) {
+ int len;
+
+ len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
+ pipefp);
+ scrbuf[len] = '\0';
+ pclose(pipefp);
+ }
+ else {
+ printf("\nCan't run %s\n",scrbuf);
+ *scrbuf = '\0';
+ }
+ for (s=scrbuf; *s; s++) {
+ if (*s == '\n') {
+ if (s[1])
+ *s = ' ';
+ else
+ *s = '\0';
+ }
+ }
+ s = scrbuf;
+ break;
+ }
+#endif
+#ifdef PROMPTTTY
+ case '"':
+ pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
+ fputs(scrbuf,stdout) FLUSH;
+ resetty();
+ gets(scrbuf);
+ noecho();
+ crmode();
+ s = scrbuf;
+ break;
+#endif
+ case '~':
+ s = homedir;
+ break;
+ case '.':
+ s = dotdir;
+ break;
+ case '$':
+ s = scrbuf;
+ sprintf(s,"%ld",our_pid);
+ break;
+ case '#':
+ s = scrbuf;
+ sprintf(s,"%d",perform_cnt);
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+#ifdef CONDSUB
+ s = getbracket(bra_compex,*pattern - '0');
+#else
+ s = nullstr;
+#endif
+ break;
+ case 'a':
+ s = scrbuf;
+ sprintf(s,"%ld",(long)art);
+ break;
+ case 'A':
+#ifdef LINKART
+ s = linkartname; /* so Eunice people get right file */
+#else
+ s = scrbuf;
+#ifdef USE_NNTP
+ sprintf(s,"%s/%s",spool,nntp_artname());
+#else
+ sprintf(s,"%s/%s/%ld",spool,ngdir,(long)art);
+#endif
+#endif
+ break;
+ case 'b':
+ s = savedest;
+ break;
+ case 'B':
+ s = scrbuf;
+ sprintf(s,"%ld",(long)savefrom);
+ break;
+ case 'c':
+ s = ngdir;
+ break;
+ case 'C':
+ s = ngname;
+ break;
+ case 'd':
+ s = scrbuf;
+ sprintf(s,"%s/%s",spool,ngdir);
+ break;
+ case 'D':
+ s = dist_buf = fetchlines(art,DIST_LINE);
+ break;
+ case 'e':
+ s = (extractprog ? extractprog : "-");
+ break;
+ case 'E':
+ s = extractdest;
+ break;
+ case 'f': /* from line */
+ parseheader(art);
+ if (htype[REPLY_LINE].ht_minpos >= 0) {
+ /* was there a reply line? */
+ if (!(s=reply_buf))
+ s = reply_buf = fetchlines(art,REPLY_LINE);
+ }
+ else if (!(s = from_buf))
+ s = from_buf = fetchlines(art,FROM_LINE);
+ break;
+ case 'F':
+ parseheader(art);
+ if (htype[FOLLOW_LINE].ht_minpos >= 0)
+ /* is there a Followup-To line? */
+ s = follow_buf = fetchlines(art,FOLLOW_LINE);
+ else
+ s = ngs_buf = fetchlines(art,NGS_LINE);
+ break;
+ case 'h': /* header file name */
+ s = headname;
+ break;
+ case 'H': /* host name in postings */
+ s = phostname;
+ break;
+ case 'i':
+ if (!(s=artid_buf))
+ s = artid_buf = fetchlines(art,MESSID_LINE);
+ if (*s && *s != '<') {
+ sprintf(scrbuf,"<%s>",artid_buf);
+ s = scrbuf;
+ }
+ break;
+ case 'I': /* ref article indicator */
+ s = scrbuf;
+ sprintf(scrbuf,"'%s'",indstr);
+ break;
+ case 'l': /* rn library */
+#ifdef NEWS_ADMIN
+ s = newsadmin;
+#else
+ s = "???";
+#endif
+ break;
+ case 'L': /* login id */
+ s = logname;
+ break;
+ case 'm': /* current mode */
+ s = scrbuf;
+ *s = mode;
+ s[1] = '\0';
+ break;
+ case 'M':
+ sprintf(scrbuf,"%ld",(long)dmcount);
+ s = scrbuf;
+ break;
+ case 'n': /* newsgroups */
+ s = ngs_buf = fetchlines(art,NGS_LINE);
+ break;
+ case 'N': /* full name */
+ s = getval("NAME",realname);
+ break;
+ case 'o': /* organization */
+#ifdef IGNOREORG
+ s = getval("NEWSORG",orgname);
+#else
+ s = getenv("NEWSORG");
+ if (s == Nullch)
+ s = getval("ORGANIZATION",orgname);
+#endif
+#ifdef ORGFILE
+ if (*s == '/') {
+ FILE *ofp = fopen(s,"r");
+
+ if (ofp) {
+ fgets(scrbuf,sizeof scrbuf,ofp);
+ fclose(ofp);
+ s = scrbuf+strlen(scrbuf)-1;
+ if (*s == '\n')
+ *s = '\0';
+ s = scrbuf;
+ }
+ }
+#endif
+ break;
+ case 'O':
+ s = origdir;
+ break;
+ case 'p':
+ s = cwd;
+ break;
+ case 'P':
+ s = spool;
+ break;
+ case 'r':
+ parseheader(art);
+ if (htype[REFS_LINE].ht_minpos >= 0) {
+ refs_buf = fetchlines(art,REFS_LINE);
+ refscpy(scrbuf,(sizeof scrbuf),refs_buf);
+ }
+ else
+ *scrbuf = '\0';
+ s = rindex(scrbuf,'<');
+ break;
+ case 'R':
+ parseheader(art);
+ if (htype[REFS_LINE].ht_minpos >= 0) {
+ refs_buf = fetchlines(art,REFS_LINE);
+ refscpy(scrbuf,(sizeof scrbuf),refs_buf);
+ /* no more than 3 prior references PLUS the
+ ** root article allowed, including the one
+ ** concatenated below */
+ if ((s = rindex(scrbuf,'<')) > scrbuf) {
+ *s = '\0';
+ h = rindex(scrbuf,'<');
+ *s = '<';
+ if (h > scrbuf) {
+ s = index(scrbuf+1,'<');
+ if (s < h)
+ strcpy(s,h);
+ }
+ }
+ }
+ else
+ *scrbuf = '\0';
+ if (!artid_buf)
+ artid_buf = fetchlines(art,MESSID_LINE);
+ if (artid_buf[0] == '<')
+ safecat(scrbuf,artid_buf,sizeof(scrbuf));
+ else if (artid_buf[0]) {
+ char tmpbuf[64];
+
+ sprintf(tmpbuf,"<%s>",artid_buf);
+ safecat(scrbuf,tmpbuf,sizeof(scrbuf));
+ }
+ s = scrbuf;
+ break;
+ case 's':
+ if (!(s=subj_buf))
+ s = subj_buf = fetchsubj(art,TRUE);
+ /* get subject handy */
+ while ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
+ /* skip extra Re: */
+ s += 3;
+ if (*s == ' ')
+ s++;
+ }
+ if (h = instr(s,"- (nf", TRUE))
+ *h = '\0';
+ break;
+ case 'S':
+ if (!(s=subj_buf))
+ s = subj_buf = fetchsubj(art,TRUE);
+ /* get subject handy */
+ if ((*s=='R'||*s=='r')&&(s[1]=='E'||s[1]=='e')&&s[2]==':') {
+ /* skip extra Re: */
+ s += 3;
+ if (*s == ' ')
+ s++;
+ }
+ break;
+ case 't':
+ case 'T':
+ parseheader(art);
+ if (htype[REPLY_LINE].ht_minpos >= 0) {
+ /* was there a reply line? */
+ if (!(s=reply_buf))
+ s = reply_buf = fetchlines(art,REPLY_LINE);
+ }
+ else if (!(s = from_buf))
+ s = from_buf = fetchlines(art,FROM_LINE);
+ else
+ s = "noname";
+ if (*pattern == 'T') {
+ if (htype[PATH_LINE].ht_minpos >= 0) {
+ /* should we substitute path? */
+ s = path_buf = fetchlines(art,PATH_LINE);
+ }
+ i = strlen(phostname);
+ if (strnEQ(phostname,s,i) && s[i] == '!')
+ s += i + 1;
+ }
+ if ((h=index(s,'(')) != Nullch)
+ /* strip garbage from end */
+ *(h-1) = '\0';
+ else if ((h=index(s,'<')) != Nullch) {
+ /* or perhaps from beginning */
+ s = h+1;
+ if ((h=index(s,'>')) != Nullch)
+ *h = '\0';
+ }
+ break;
+ case 'u':
+ sprintf(scrbuf,"%ld",(long)toread[ng]);
+ s = scrbuf;
+ break;
+ case 'U': {
+ int unseen;
+
+ unseen = (art <= lastart) && !was_read(art);
+ if (selected_only) {
+ int selected;
+
+ selected = (curr_artp->flags & AF_SEL);
+ sprintf(scrbuf,"%ld",
+ (long)selected_count - (selected && unseen));
+ }
+ else
+ sprintf(scrbuf,"%ld",(long)toread[ng] - unseen);
+ s = scrbuf;
+ break;
+ }
+ case 'v': {
+ int selected, unseen;
+
+ selected = (curr_artp->flags & AF_SEL);
+ unseen = (art <= lastart) && !was_read(art);
+ sprintf(scrbuf,"%ld",(long)toread[ng] - selected_count
+ - (!selected && unseen));
+ s = scrbuf;
+ break;
+ }
+ case 'W':
+ s = threaddir;
+ break;
+ case 'x': /* news library */
+ s = lib;
+ break;
+ case 'X': /* rn library */
+ s = rnlib;
+ break;
+ case 'z':
+#ifdef LINKART
+ s = linkartname; /* so Eunice people get right file */
+#else
+ s = scrbuf;
+ sprintf(s,"%ld",(long)art);
+#endif
+ if (stat(s,&filestat) < 0)
+ filestat.st_size = 0L;
+ sprintf(scrbuf,"%5ld",(long)filestat.st_size);
+ s = scrbuf;
+ break;
+ case 'Z':
+ sprintf(scrbuf,"%ld",(long)selected_count);
+ s = scrbuf;
+ break;
+ default:
+ if (--destsize <= 0)
+ abort_interp();
+ *dest++ = *pattern | metabit;
+ s = nullstr;
+ break;
+ }
+ }
+ if (!s)
+ s = nullstr;
+ if (proc_sprintf) {
+ sprintf(scrbuf,spfbuf,s);
+ s = scrbuf;
+ }
+ pattern++;
+ if (upper || lastcomp) {
+ char *t;
+
+ if (s != scrbuf) {
+ safecpy(scrbuf,s,(sizeof scrbuf));
+ s = scrbuf;
+ }
+ if (upper || !(t=rindex(s,'/')))
+ t = s;
+ while (*t && !isalpha(*t))
+ t++;
+ if (islower(*t))
+ *t = toupper(*t);
+ }
+ /* Do we have room left? */
+ i = strlen(s);
+ if (destsize <= i)
+ abort_interp();
+ destsize -= i; /* adjust the size now. */
+
+ /* A maze of twisty little conditions, all alike... */
+ if (metabit) {
+ /* set meta bit while copying. */
+ i = metabit; /* maybe get into register */
+ if (s == dest) {
+ while (*dest)
+ *dest++ |= i;
+ } else {
+ while (*s)
+ *dest++ = *s++ | i;
+ }
+ } else if (re_quote) {
+ /* put a backslash before regexp specials while copying. */
+ if (s == dest) {
+ /* copy out so we can copy in. */
+ safecpy(scrbuf, s, sizeof scrbuf);
+ s = scrbuf;
+ if (i > sizeof scrbuf) /* we truncated, ack! */
+ destsize += i - sizeof scrbuf;
+ }
+ while (*s) {
+ if (index(regexp_specials, *s)) {
+ if (--destsize <= 0)
+ abort_interp();
+ *dest++ = '\\';
+ }
+ *dest++ = *s++;
+ }
+ } else {
+ /* straight copy. */
+ if (s == dest) {
+ dest += i;
+ } else {
+ while (*s)
+ *dest++ = *s++;
+ }
+ }
+ }
+ else {
+ if (--destsize <= 0)
+ abort_interp();
+ if (*pattern == '^' && pattern[1]) {
+ ++pattern; /* skip uparrow */
+ i = *pattern; /* get char into a register */
+ if (i == '?')
+ *dest++ = '\177' | metabit;
+ else if (i == '(') {
+ metabit = 0200;
+ destsize++;
+ }
+ else if (i == ')') {
+ metabit = 0;
+ destsize++;
+ }
+ else
+ *dest++ = (i & 037) | metabit;
+ pattern++;
+ }
+ else if (*pattern == '\\' && pattern[1]) {
+ ++pattern; /* skip backslash */
+ i = *pattern; /* get char into a register */
+
+ /* this used to be a switch but the if may save space */
+
+ if (i >= '0' && i <= '7') {
+ i = 1;
+ while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
+ i <<= 3;
+ i += *pattern++ - '0';
+ }
+ *dest++ = (i & 0377) | metabit;
+ --pattern;
+ }
+ else if (i == 'b')
+ *dest++ = '\b' | metabit;
+ else if (i == 'f')
+ *dest++ = '\f' | metabit;
+ else if (i == 'n')
+ *dest++ = '\n' | metabit;
+ else if (i == 'r')
+ *dest++ = '\r' | metabit;
+ else if (i == 't')
+ *dest++ = '\t' | metabit;
+ else
+ *dest++ = i | metabit;
+ pattern++;
+ }
+ else
+ *dest++ = *pattern++ | metabit;
+ }
+ }
+ *dest = '\0';
+getout:
+ if (subj_buf != Nullch) /* return any checked out storage */
+ free(subj_buf);
+ if (ngs_buf != Nullch)
+ free(ngs_buf);
+ if (refs_buf != Nullch)
+ free(refs_buf);
+ if (artid_buf != Nullch)
+ free(artid_buf);
+ if (reply_buf != Nullch)
+ free(reply_buf);
+ if (from_buf != Nullch)
+ free(from_buf);
+ if (path_buf != Nullch)
+ free(path_buf);
+ if (follow_buf != Nullch)
+ free(follow_buf);
+ if (dist_buf != Nullch)
+ free(dist_buf);
+ if (line_buf != Nullch)
+ free(line_buf);
+ return pattern; /* where we left off */
+}
+
+void
+interp(dest,destsize,pattern)
+char *dest;
+int destsize;
+char *pattern;
+{
+ dointerp(dest,destsize,pattern,Nullch);
+#ifdef DEBUG
+ if (debug & DEB_FILEXP)
+ fputs(dest,stdout);
+#endif
+}
+
+/* copy a references line, normalizing as we go */
+
+void
+refscpy(dest,destsize,src)
+register char *dest, *src;
+register int destsize;
+{
+ register char *dot, *at, *beg;
+ char tmpbuf[64];
+
+ while (*src) {
+ if (*src != '<') {
+ if (--destsize <= 0)
+ break;
+ *dest++ = '<';
+ at = dot = Nullch;
+ beg = src;
+ while (*src && *src != ' ' && *src != ',') {
+ if (*src == '.')
+ dot = src;
+ else if (*src == '@')
+ at = src;
+ if (--destsize <= 0)
+ break;
+ *dest++ = *src++;
+ }
+ if (destsize <= 0)
+ break;
+ if (dot && !at) {
+ int len;
+
+ *dest = *dot++ = '\0';
+ sprintf(tmpbuf,"%s@%s.UUCP",dot,beg);
+ len = strlen(tmpbuf);
+ if (destsize > len) {
+ strcpy(dest,tmpbuf);
+ dest = dest + len;
+ destsize -= len;
+ }
+ }
+ if (--destsize <= 0)
+ break;
+ *dest++ = '>';
+ }
+ else {
+ while (*src && --destsize > 0 && (*dest++ = *src++) != '>') ;
+ if (destsize <= 0)
+ break;
+ }
+ while (*src == ' ' || *src == '\t' || *src == '\n' || *src == ',')
+ src++;
+ if (*src && --destsize > 0)
+ *dest++ = ' ';
+ }
+ *dest = '\0';
+}
+
+/* get the person's real name from /etc/passwd */
+/* (string is overwritten, so it must be copied) */
+
+char *
+getrealname(uid)
+long uid;
+{
+ char *s, *c;
+
+#ifdef PASSNAMES
+#ifdef HAS_GETPWENT
+#ifdef notdef
+ struct passwd *getpwuid _((uid_t));
+#endif
+ struct passwd *pwd = getpwuid(uid);
+
+ if (!pwd)
+ return nullstr;
+
+ s = pwd->pw_gecos;
+#else
+ char tmpbuf[512];
+ int i;
+
+ getpw(uid, tmpbuf);
+ for (s=tmpbuf, i=GCOSFIELD-1; i; i--) {
+ if (s)
+ s = index(s,':')+1;
+ }
+ if (!s)
+ return nullstr;
+ cpytill(tmpbuf,s,':');
+ s = tmpbuf;
+#endif
+#ifdef BERKNAMES
+#ifdef BERKJUNK
+ while (*s && !isalnum(*s) && *s != '&') s++;
+#endif
+ if ((c = index(s, ',')) != Nullch)
+ *c = '\0';
+ if ((c = index(s, ';')) != Nullch)
+ *c = '\0';
+ s = cpytill(buf,s,'&');
+ if (*s == '&') { /* whoever thought this one up was */
+ c = buf + strlen(buf); /* in the middle of the night */
+ strcat(c,logname); /* before the morning after */
+ strcat(c,s+1);
+ if (islower(*c))
+ *c = toupper(*c); /* gack and double gack */
+ }
+#else
+ if ((c = index(s, '(')) != Nullch)
+ *c = '\0';
+ if ((c = index(s, '-')) != Nullch)
+ s = c;
+ strcpy(buf,s);
+#endif
+#ifdef HAS_GETPWENT
+ endpwent();
+#endif
+ return buf; /* return something static */
+#else
+ if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != Nullfp) {
+ fgets(buf,sizeof buf,tmpfp);
+ fclose(tmpfp);
+ buf[strlen(buf)-1] = '\0';
+ return buf;
+ }
+ return "PUT YOUR NAME HERE";
+#endif
+}
+
+static void
+abort_interp()
+{
+ fputs("\n% interp buffer overflow!\n",stdout) FLUSH;
+ sig_catcher(0);
+}
+
+