|
|
1.1 root 1: /*
2: * funcs - functions used by both inews and readnews.
3: */
4:
5: static char *SccsId = "@(#)funcs.c 2.10 6/24/83";
6:
7: #include "params.h"
8:
9: /*
10: * Append NGDELIM to string.
11: */
12: ngcat(s)
13: register char *s;
14: {
15: if (*s) {
16: while (*s++);
17: s -= 2;
18: if (*s++ == NGDELIM)
19: return;
20: }
21: *s++ = NGDELIM;
22: *s = '\0';
23: }
24:
25: /*
26: * News group matching.
27: *
28: * nglist is a list of newsgroups.
29: * sublist is a list of subscriptions.
30: * sublist may have "meta newsgroups" in it.
31: * All fields are NGDELIM separated,
32: * and there is an NGDELIM at the end of each argument.
33: *
34: * Currently implemented glitches:
35: * sublist uses 'all' like shell uses '*', and '.' like shell '/'.
36: * If subscription X matches Y, it also matches Y.anything.
37: */
38: ngmatch(nglist, sublist)
39: register char *nglist, *sublist;
40: {
41: register char *n, *s;
42: register int rc;
43:
44: rc = FALSE;
45: for (n = nglist; *n != '\0' && rc == FALSE;) {
46: for (s = sublist; *s != '\0';) {
47: if (*s != NEGCHAR)
48: rc |= ptrncmp(s, n);
49: else
50: rc &= ~ptrncmp(s+1, n);
51: while (*s++ != NGDELIM);
52: }
53: while (*n++ != NGDELIM);
54: }
55: return(rc);
56: }
57:
58: /*
59: * Compare two newsgroups for equality.
60: * The first one may be a "meta" newsgroup.
61: */
62: ptrncmp(ng1, ng2)
63: register char *ng1, *ng2;
64: {
65: while (*ng1 != NGDELIM) {
66: if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') {
67: ng1 += 3;
68: while (*ng2 != NGDELIM && *ng2 != '.')
69: if (ptrncmp(ng1, ng2++))
70: return(TRUE);
71: return (ptrncmp(ng1, ng2));
72: } else if (*ng1++ != *ng2++)
73: return(FALSE);
74: }
75: return (*ng2 == '.' || *ng2 == NGDELIM);
76: }
77:
78: /*
79: * Remove newsgroups in 'a' not subscribed to by 'b'.
80: */
81: ngsquash(ap, bp)
82: register char *ap, *bp;
83: {
84: register char *tp;
85: char tbuf[BUFLEN];
86:
87: /* replace NGDELIM by '\0' in a */
88: for (tp = ap; *tp != '\0'; tp++)
89: if (*tp == NGDELIM)
90: *tp = '\0';
91: /* ap = building, tp = checking. */
92: tp = ap;
93: while (*tp != '\0') {
94: ngcat(strcpy(tbuf, tp));
95: if (ngmatch(tbuf, bp)) {
96: while ((*ap++ = *tp++) != '\0')
97: ;
98: ap[-1] = NGDELIM;
99: } else
100: while (*tp++ != '\0');
101: }
102: *ap = '\0';
103: }
104:
105: /*
106: * Exec the shell.
107: * This version resets uid, gid, and umask.
108: * Called with fsubr(ushell, s, NULL)
109: */
110: /* ARGSUSED */
111: ushell(s, dummy)
112: char *s, *dummy;
113: {
114: umask(savmask);
115: setgid(gid);
116: setuid(uid);
117: xshell(s);
118: }
119:
120: /*
121: * Exec the shell.
122: * This version restricts PATH to bin and /usr/bin.
123: * Called with fsubr(pshell, s, NULL)
124: */
125: extern char **environ;
126:
127: /* ARGSUSED */
128: pshell(s, dummy)
129: char *s, *dummy;
130: {
131: static char *penv[] = { SYSPATH, NULL };
132: register char **ep, *p;
133: register int found;
134:
135: found = FALSE;
136: for (ep = environ; p = *ep; ep++) {
137: if (strncmp(p, "PATH=", 5) == 0) {
138: *ep = penv[0];
139: found = TRUE;
140: }
141: }
142: if (!found)
143: environ = &penv[0];
144: xshell(s);
145: }
146:
147: /*
148: * Exec the shell.
149: */
150: xshell(s)
151: char *s;
152: {
153: execl(SHELL, SHELL, "-c", s, 0);
154: xerror("No shell!");
155: }
156:
157: /*
158: * Fork and call a subroutine with two args.
159: * Return pid without waiting.
160: */
161: fsubr(f, s1, s2)
162: int (*f)();
163: char *s1, *s2;
164: {
165: register int pid;
166:
167: while ((pid = fork()) == -1)
168: sleep(1);
169: if (pid == 0) {
170: (*f)(s1, s2);
171: exit(0);
172: }
173: return(pid);
174: }
175:
176: /*
177: * Wait on a child process.
178: */
179: fwait(pid)
180: register int pid;
181: {
182: register int w;
183: int status;
184: void (*onhup)(), (*onint)();
185:
186: onint = (void (*)()) signal(SIGINT, SIG_IGN);
187: onhup = (void (*)()) signal(SIGHUP, SIG_IGN);
188: while ((w = wait(&status)) != pid && w != -1)
189: ;
190: if (w == -1)
191: status = -1;
192: signal(SIGINT, onint);
193: signal(SIGHUP, onhup);
194: return(status);
195: }
196:
197: /*
198: * Get user name and home directory.
199: */
200: getuser()
201: {
202: static int flag = TRUE;
203: register struct passwd *p;
204:
205: if (flag) {
206: if ((p = getpwuid(uid)) == NULL)
207: xerror("Cannot get user's name");
208: if (username[0] == 0)
209: strcpy(username, p->pw_name);
210: strcpy(userhome, p->pw_dir);
211: flag = FALSE;
212: }
213: strcpy(header.path, username);
214: }
215:
216: /*
217: * Strip trailing newlines, blanks, and tabs from 's'.
218: * Return TRUE if newline was found, else FALSE.
219: */
220: nstrip(s)
221: register char *s;
222: {
223: register char *p;
224: register int rc;
225:
226: rc = FALSE;
227: p = s;
228: while (*p)
229: if (*p++ == '\n')
230: rc = TRUE;
231: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
232: *++p = '\0';
233: return(rc);
234: }
235:
236: /*
237: * Delete trailing NGDELIM.
238: */
239: ngdel(s)
240: register char *s;
241: {
242: if (*s++) {
243: while (*s++);
244: s -= 2;
245: if (*s == NGDELIM)
246: *s = '\0';
247: }
248: }
249:
250: /*
251: * Return the ptr in sp at which the character c appears;
252: * NULL if not found
253: *
254: * These are the v7 index and rindex routines, stolen for portability.
255: * (Some Unix systems call them strchr and strrchr, notably PWB 2.0
256: * and its derivitives such as Unix/TS 2.0, Unix 3.0, etc.) Others,
257: * like v6, don't have them at all.
258: */
259:
260: char *
261: index(sp, c)
262: register char *sp, c;
263: {
264: do {
265: if (*sp == c)
266: return(sp);
267: } while (*sp++);
268: return(NULL);
269: }
270:
271: /*
272: * Return the ptr in sp at which the character c last
273: * appears; NULL if not found
274: */
275:
276: char *
277: rindex(sp, c)
278: register char *sp, c;
279: {
280: register char *r;
281:
282: r = NULL;
283: do {
284: if (*sp == c)
285: r = sp;
286: } while (*sp++);
287: return(r);
288: }
289: static FILE *sysfile;
290:
291: char *fldget();
292:
293: /*
294: * Open SUBFILE.
295: */
296: s_openr()
297: {
298: sysfile = xfopen(SUBFILE, "r");
299: }
300:
301: /*
302: * Read SUBFILE.
303: */
304: s_read(sp)
305: register struct srec *sp;
306: {
307: register char *p;
308: again:
309: p = bfr;
310: if (fgets(p, LBUFLEN, sysfile) == NULL)
311: return(FALSE);
312: if (!nstrip(p))
313: xerror("SUBFILE line too long.");
314: if (*p == '#')
315: goto again;
316: sp->s_xmit[0] = '\0';
317: sp->s_flags[0] = '\0';
318:
319: p = fldget(sp->s_name, p);
320: if (*p++ == '\0')
321: xerror("Bad SUBFILE line.");
322: /*
323: * A sys file line reading "ME" means the name of the local system.
324: */
325: if (strcmp(sp->s_name, "ME") == 0)
326: strcpy(sp->s_name, FULLSYSNAME);
327: p = fldget(sp->s_nbuf, p);
328: lcase(sp->s_nbuf);
329: ngcat(sp->s_nbuf);
330: if (*p++ == '\0')
331: return(TRUE);
332:
333: p = fldget(sp->s_flags, p);
334: if (*p++ == '\0')
335: return(TRUE);
336:
337: fldget(sp->s_xmit, p);
338: return(TRUE);
339: }
340:
341: char *
342: fldget(q, p)
343: register char *q, *p;
344: {
345: while (*p && *p != ':') {
346: if (*p == '\\' && p[1]==':')
347: p++;
348: *q++ = *p++;
349: }
350: *q = '\0';
351: return(p);
352: }
353:
354: /*
355: * Find the SUBFILE record for a system.
356: */
357: s_find(sp, system)
358: register struct srec *sp;
359: char *system;
360: {
361: s_openr();
362: while (s_read(sp))
363: if (strncmp(system, sp->s_name, SNLN) == 0) {
364: s_close();
365: return(TRUE);
366: }
367: s_close();
368: return(FALSE);
369: }
370:
371: /*
372: * Close sysfile.
373: */
374: s_close()
375: {
376: fclose(sysfile);
377: }
378:
379: /*
380: * Local open routine.
381: */
382: FILE *
383: xfopen(name, mode)
384: register char *name, *mode;
385: {
386: register FILE *fp;
387: char *fname;
388:
389: if ((fp = fopen(name, mode)) == NULL) {
390: fname = rindex(name, '/');
391: /*
392: * IHCC users only see the "filename" that was in trouble, not the
393: * whole path. (for security!)
394: */
395: #ifdef IHCC
396: sprintf(bfr, "Cannot open %s (%s)", ++fname, mode);
397: #else
398: sprintf(bfr, "Cannot open %s (%s)", name, mode);
399: #endif
400: xerror(bfr);
401: }
402: /* kludge for setuid not being honored for root */
403: if ((uid == 0) && (duid != 0) && ((mode == "a") || (mode == "w")))
404: chown(name, duid, dgid);
405: return(fp);
406: }
407:
408: time_t
409: cgtdate(datestr)
410: char *datestr;
411: {
412: time_t i;
413: char junk[40],month[40],day[30],time[60],year[50];
414:
415: if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0)
416: return i;
417: sscanf(datestr, "%s %s %s %s %s", junk, month, day, time, year);
418: sprintf(bfr, "%s %s, %s %s", month, day, year, time);
419: return getdate(bfr, (struct timeb *) NULL);
420: }
421:
422: lcase(s)
423: register char *s;
424: {
425: register char *ptr;
426:
427: for (ptr = s; *ptr; ptr++)
428: if (isupper(*ptr))
429: *ptr = tolower(*ptr);
430: }
431:
432: ohwrite(hp, fp)
433: register struct hbuf *hp;
434: register FILE *fp;
435: {
436: ngdel(strcpy(bfr, hp->nbuf));
437: fprintf(fp, "A%s\n%s\n%s!%s\n%s\n%s\n", hp->oident, bfr, FULLSYSNAME, hp->path, hp->subdate, hp->title);
438: }
439:
440: static int hascaught = 0;
441: static catchintr()
442: {
443: hascaught = 1;
444: printf("\n");
445: fflush(stdout);
446: }
447:
448: /*
449: * Print a recorded message warning the poor luser what he is doing
450: * and demand that he understands it before proceeding. Only do
451: * this for newsgroups listed in LIBDIR/recording.
452: */
453: recording(ngrps)
454: char *ngrps;
455: {
456: char recbuf[100];
457: FILE *fd;
458: char nglist[100], fname[100];
459: char lngrps[100];
460: char *oldsig;
461: int c, n, yes;
462:
463: sprintf(recbuf, "%s/%s", LIB, "recording");
464: fd = fopen(recbuf, "r");
465: if (fd == NULL)
466: return 0;
467: strcpy(lngrps, ngrps);
468: ngcat(lngrps);
469: while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
470: sscanf(recbuf, "%s %s", nglist, fname);
471: ngcat(nglist);
472: if (ngmatch(lngrps, nglist)) {
473: fclose(fd);
474: if (fname[0] == '/')
475: strcpy(recbuf, fname);
476: else
477: sprintf(recbuf, "%s/%s", LIB, fname);
478: fd = fopen(recbuf, "r");
479: if (fd == NULL)
480: return 0;
481: while ((c = getc(fd)) != EOF)
482: putc(c, stderr);
483: hascaught = 0;
484: oldsig = (char *) signal(SIGINT, catchintr);
485: fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: ");
486: n = read(2, recbuf, 100);
487: c = recbuf[0];
488: yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
489: signal(SIGINT, oldsig);
490: if (hascaught || n <= 0 || !yes)
491: return -1;
492: }
493: }
494: return 0;
495: }
496:
497: /*
498: * Return a compact representation of the person who posted the given
499: * message. A sender or internet name will be used, otherwise
500: * the last part of the path is used preceeded by an optional ".."
501: */
502: char *
503: tailpath(hp)
504: struct hbuf *hp;
505: {
506: char *p, *r;
507: static char resultbuf[BUFLEN];
508: char pathbuf[PATHLEN];
509: char *malloc();
510:
511: /*
512: * This only happens for articles posted by old news software
513: * in non-internet format.
514: */
515: resultbuf[0] = '\0';
516: strcpy(pathbuf, hp->path);
517: p = index(pathbuf, ' ');
518: if (p)
519: *p = '\0'; /* Chop off trailing " (name)" */
520: r = rindex(pathbuf, '!');
521: if (r == 0) {
522: r = pathbuf;
523: }
524: else {
525: while (r > pathbuf && *--r != '!')
526: ;
527: if (r > pathbuf) {
528: r++;
529: strcpy(resultbuf, "..!");
530: }
531: }
532: strcat(resultbuf, r);
533: return resultbuf;
534: }
535:
536: /*
537: * Generate the name of the person responsible for posting this article,
538: * in order to check that two articles were posted by the same person.
539: */
540: char *
541: senderof(hp)
542: struct hbuf *hp;
543: {
544: char *q, *tp;
545:
546: if (hp->sender[0])
547: tp = hp->sender;
548: else if (hp->from[0])
549: tp = hp->from;
550: else
551: tp = tailpath(hp);
552:
553: /* Remove full name */
554: q = index(tp, ' ');
555: if (q)
556: *q = '\0';
557:
558: q = malloc(strlen(tp) + 1);
559: strcpy(q, tp);
560: return q;
561: }
562:
563: /*
564: * Returns 1 iff addr looks like a valid internet address
565: * (as opposed to a routing path).
566: * The current check insists on *@*.* as a format.
567: */
568: goodinternet(addr)
569: register char *addr;
570: {
571: register char *at, *dot;
572:
573: at = index(addr, '@');
574: if (at == NULL)
575: return 0;
576: dot = index(at, '.');
577: if (dot == NULL)
578: return 0;
579: /*
580: * A more thorough check would insist on only alphanumerics
581: * and dots to the right of the @.
582: */
583: return 1;
584: }
585:
586: rwaccess(fname)
587: char *fname;
588: {
589: int fd;
590:
591: fd = open(fname, 2);
592: if (fd < 0)
593: return 0;
594: close(fd);
595: return 1;
596: }
597:
598: exists(fname)
599: char *fname;
600: {
601: int fd;
602:
603: fd = open(fname, 0);
604: if (fd < 0)
605: return 0;
606: close(fd);
607: return 1;
608: }
609:
610: prefix(full, pref)
611: register char *full, *pref;
612: {
613: while (*full++ == *pref++)
614: ;
615: if (*--pref == 0)
616: return 1;
617: else
618: return 0;
619: }
620:
621: char *
622: dirname(ngname)
623: char *ngname;
624: {
625: static char rbuf[100];
626: register char *p;
627:
628: sprintf(rbuf, "%s/%s", SPOOL, ngname);
629: #ifdef UPWARDCOMPAT
630: /* First check the old style name. */
631: if (exists(rbuf))
632: return rbuf;
633: #endif
634:
635: /* Use the new style name for all new stuff. */
636: for (p=rbuf+strlen(SPOOL); *p; p++)
637: if (*p == '.')
638: *p = '/';
639: return rbuf;
640: }
641:
642: #ifdef notdef
643: char *
644: dotname(ngname)
645: char *ngname;
646: {
647: static char rbuf[100];
648: register char *p;
649:
650: #ifdef UPWARDCOMPAT
651: /* First check the old style name. */
652: sprintf(rbuf, "%s/.%s", SPOOL, ngname);
653: if (exists(rbuf))
654: return rbuf;
655: #endif
656:
657: /* Use the new style name for all new stuff. */
658: sprintf(rbuf, "%s/%s", SPOOL, ngname);
659: for (p=rbuf+strlen(SPOOL); *p; p++)
660: if (*p == '.')
661: *p = '/';
662: strcat(rbuf, "/bounds");
663: return rbuf;
664: }
665: #endif
666:
667: /*
668: * Return TRUE iff ngname is a valid newsgroup name, active
669: * or inactive.
670: */
671: validng(ngname)
672: char *ngname;
673: {
674: return exists(dirname(ngname));
675: }
676:
677: /*
678: * arpadate is like ctime(3) except that the time is returned in
679: * an acceptable ARPANET time format instead of ctime format.
680: */
681: char *
682: arpadate(longtime)
683: time_t *longtime;
684: {
685: register char *p, *q, *ud;
686: char *cp;
687: register int i;
688: static char b[40];
689: struct timeb t;
690: extern struct tm *localtime();
691: extern char *ctime();
692: extern struct timeb *ftime();
693: #ifdef USG
694: struct tm *bp;
695: extern char *tzname[];
696: #else
697: extern char *timezone();
698: #endif
699:
700: /* Get current time. This will be used resolve the timezone. */
701: ud = ctime(longtime);
702: ftime(&t);
703:
704: /* Crack the UNIX date line in a singularly unoriginal way. */
705: q = b;
706:
707: p = &ud[0]; /* Mon */
708: *q++ = *p++;
709: *q++ = *p++;
710: *q++ = *p++;
711: *q++ = ','; *q++ = ' ';
712:
713: p = &ud[8]; /* 16 */
714: if (*p == ' ')
715: p++;
716: else
717: *q++ = *p++;
718: *q++ = *p++; *q++ = '-';
719:
720: p = &ud[4]; /* Sep */
721: *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = '-';
722:
723: p = &ud[22]; /* 1979 */
724: *q++ = *p++; *q++ = *p++; *q++ = ' ';
725:
726: p = &ud[11]; /* 01:03:52 */
727: for (i = 8; i > 0; i--)
728: *q++ = *p++;
729:
730: /* -PST or -PDT */
731: #ifdef USG
732: bp = localtime(&t.time);
733: p = tzname[bp->tm_isdst];
734: #else
735: p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
736: #endif
737: if (p[3] != '\0') {
738: /* hours from GMT */
739: p += 3;
740: *q++ = *p++;
741: if (p[1] == ':')
742: *q++ = '0';
743: else
744: *q++ = *p++;
745: *q++ = *p++; p++; *q++ = *p++; *q++ = *p++;
746: } else {
747: *q++ = ' '; *q++ = *p++; *q++ = *p++; *q++ = *p++;
748: }
749: *q = '\0';
750:
751: return (b);
752: }
753:
754: char *
755: replyname(hptr)
756: struct hbuf *hptr;
757: {
758: register char *ptr;
759: static char tbuf[PATHLEN];
760:
761: ptr = hptr->path;
762: if (prefix(ptr, FULLSYSNAME))
763: ptr = index(ptr, '!') + 1;
764: #ifdef INTERNET
765: if (hptr->from[0])
766: ptr = hptr->from;
767: if (hptr->replyto[0])
768: ptr = hptr->replyto;
769: #endif
770: strcpy(tbuf, ptr);
771: ptr = index(tbuf, '(');
772: if (ptr) {
773: while (ptr[-1] == ' ')
774: ptr--;
775: *ptr = 0;
776: }
777: #ifndef INTERNET
778: /*
779: * Play games stripping off multiple berknet
780: * addresses (a!b!c:d:e => a!b!d:e) here.
781: */
782: for (ptr=tbuf; *ptr; ptr++)
783: if (index(NETCHRS, *ptr) && *ptr == ':' && index(ptr+1, ':'))
784: strcpy(ptr, index(ptr+1, ':'));
785: #endif
786: return tbuf;
787: }
788:
789: /*
790: * Given an article ID, find the line in the history file that mentions it.
791: * Return the text of the line, or NULL if not found. A pointer to a
792: * static area is returned.
793: */
794: char *
795: findhist(artid)
796: char *artid;
797: {
798: static char lbuf[256];
799: char oidbuf[BUFSIZ];
800: FILE *hfp;
801: char *p;
802:
803: /* Try to understand old artid's as well. Assume .UUCP domain. */
804: if (artid[0] != '<') {
805: p = index(artid, '.');
806: if (p)
807: *p++ = '\0';
808: sprintf(oidbuf, "<%s@%s.UUCP>", p, artid);
809: if (p)
810: *--p = '.';
811: } else
812: strcpy(oidbuf, artid);
813: hfp = xfopen(ARTFILE, "r");
814: while (fgets(lbuf, BUFLEN, hfp) != NULL) {
815: p = index(lbuf, '\t');
816: if (p == NULL)
817: p = index(lbuf, '\n');
818: *p = 0;
819: if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) {
820: fclose(hfp);
821: *p = '\t';
822: *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */
823: return(lbuf);
824: }
825: }
826: fclose(hfp);
827: return(NULL);
828: }
829:
830: /*
831: * Hunt up the article "artid", and return the newsgroup/artnum
832: * where it can be found.
833: */
834: char *
835: findfname(artid)
836: char *artid;
837: {
838: char *line, *p, *q;
839: char *findhist();
840: FILE *rv;
841: static char fname[256];
842:
843: line = findhist(artid);
844: if (line) {
845: /* Look for it stored as an article, where it should be */
846: p = index(line, '\t');
847: p = index(p+1, '\t');
848: p++;
849: if (*p) {
850: q = index(p, ' ');
851: if (q)
852: *q = 0;
853: strcpy(fname, p);
854: return fname;
855: }
856: }
857:
858: return NULL;
859: }
860:
861: /*
862: * Hunt up the article "artid", fopen it for read, and return a
863: * file descriptor to it. We look everywhere we can think of.
864: */
865: FILE *
866: hfopen(artid)
867: char *artid;
868: {
869: char *p;
870: char *findhist();
871: FILE *rv = NULL;
872: char fname[256];
873:
874: p = findfname(artid);
875: if (p) {
876: strcpy(fname, dirname(p));
877: rv = fopen(fname, "r"); /* NOT xfopen! */
878: if (rv != NULL)
879: return rv;
880: }
881:
882: xerror("Cannot hfopen article %s", artid);
883: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.