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