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