Commit | Line | Data |
---|---|---|
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 | ||
42 | char 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 | |
70 | static char *tildename = Nullch; | |
71 | static char *tildedir = Nullch; | |
72 | #endif | |
73 | ||
74 | char *realname INIT(Nullch); /* real name of sender from /etc/passwd */ | |
75 | ||
76 | char *dointerp(); | |
77 | char *getrealname(); | |
78 | #ifdef CONDSUB | |
79 | char *skipinterp(); | |
80 | #endif | |
81 | ||
82 | static void abort_interp(); | |
83 | ||
84 | void | |
85 | intrp_init(tcbuf) | |
86 | char *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 | ||
161 | char * | |
162 | filexp(s) | |
163 | register 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 | ||
306 | char * | |
307 | skipinterp(pattern,stoppers) | |
308 | register char *pattern; | |
309 | char *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 | } | |
370 | getout: | |
371 | return pattern; /* where we left off */ | |
372 | } | |
373 | #endif | |
374 | ||
375 | /* interpret interpolations */ | |
376 | ||
377 | char * | |
378 | dointerp(dest,destsize,pattern,stoppers) | |
379 | register char *dest; | |
380 | register int destsize; | |
381 | register char *pattern; | |
382 | char *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'; | |
904 | getout: | |
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 | ||
928 | void | |
929 | interp(dest,destsize,pattern) | |
930 | char *dest; | |
931 | int destsize; | |
932 | char *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 | ||
943 | void | |
944 | refscpy(dest,destsize,src) | |
945 | register char *dest, *src; | |
946 | register 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 | ||
1000 | char * | |
1001 | getrealname(uid) | |
1002 | int 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 | ||
1063 | static void | |
1064 | abort_interp() | |
1065 | { | |
1066 | fputs("\n% interp buffer overflow!\n",stdout) FLUSH; | |
1067 | sig_catcher(0); | |
1068 | } |