|
|
1.1 root 1: /*
2: * This software is Copyright (c) 1985 by Rick Adams.
3: *
4: * Permission is hereby granted to copy, reproduce, redistribute or
5: * otherwise use this software as long as: there is no monetary
6: * profit gained specifically from the use or reproduction or this
7: * software, it is not sold, rented, traded or otherwise marketed, and
8: * this copyright notice is included prominently in any copy
9: * made.
10: *
11: * The author make no claims as to the fitness or correctness of
12: * this software for any use whatsoever, and it is provided as is.
13: * Any use of this software is at the user's own risk.
14: *
15: *
16: * funcs2 - functions used by both inews and readnews.
17: */
18:
19: #ifdef SCCSID
20: static char *SccsId = "@(#)funcs2.c 1.13 1/17/86";
21: #endif /* SCCSID */
22:
23: #include "params.h"
24:
25: #ifdef SunIII
26: #ifndef INTERNET
27: #define INTERNET
28: #endif /* !INTERNET */
29: #endif /* SunIII */
30:
31: /*LINTLIBRARY*/
32:
33: /*
34: * Get user name and home directory.
35: */
36: getuser()
37: {
38: static int flag = TRUE;
39: register struct passwd *p;
40:
41: if (flag) {
42: if ((p = getpwuid(uid)) == NULL)
43: xerror("Cannot get user's name");
44: if ( username == NULL || username[0] == 0)
45: username = AllocCpy(p->pw_name);
46: userhome = AllocCpy(p->pw_dir);
47: flag = FALSE;
48: }
49: (void) strcpy(header.path, username);
50: }
51:
52: static FILE *sysfile;
53:
54: char *fldget();
55:
56: static int sfline;
57:
58: /*
59: * Open SUBFILE.
60: */
61: s_openr()
62: {
63: sysfile = xfopen(SUBFILE, "r");
64: sfline = 0;
65: }
66:
67: /*
68: * Read SUBFILE.
69: */
70: s_read(sp)
71: register struct srec *sp;
72: {
73: register char *p;
74: register int c;
75: char *e;
76: int chop_spaces = 0;
77: again:
78: p = bfr;
79: /*
80: * Read the SUBFILE (/usr/lib/news/sys) from the current
81: * position to the first unescaped newline. If a newline is
82: * escaped with a backslash (\) continue reading but throw away
83: * the backslash and newline; read the next line skipping spaces
84: * and tabs until the first non-space/tab character, then start
85: * looking for a newline again. Skipping the leading
86: * spaces/tabs after a escaped newline keeps the news groups
87: * together. If a line begins with a newline, just skip it.
88: */
89: for (e=p+LBUFLEN; p < e && (c=getc(sysfile)) != EOF; p++) {
90: *p = c;
91: if (c == '\n') {
92: sfline++;
93: if (p == bfr || p[-1] != '\\') {
94: p[1] = '\0';
95: break;
96: } else {
97: chop_spaces++;
98: p -= 2;
99: }
100: } else if (chop_spaces) {
101: if (c == '\t' || c == ' ')
102: p--;
103: else
104: chop_spaces = 0;
105: }
106: }
107: if (c == EOF) {
108: return FALSE;
109: }
110: p = bfr;
111: if (*p == '\n')
112: goto again; /* skip newlines */
113: if (!nstrip(p))
114: xerror("SUBFILE (%s) line %d too long.", SUBFILE, sfline);
115: if (*p == '#')
116: goto again;
117: sp->s_xmit[0] = '\0';
118: sp->s_flags[0] = '\0';
119: sp->s_nosend = (char *)0;
120:
121: p = fldget(sp->s_name, p);
122: if (*p++ == '\0')
123: xerror("Bad SUBFILE (%s) line %d.", SUBFILE, sfline);
124: /*
125: * A sys file line reading "ME" means the name of the local system.
126: */
127: if (strcmp(sp->s_name, "ME") == 0)
128: (void) strcpy(sp->s_name, FULLSYSNAME);
129: e = index(sp->s_name, '/');
130: if (e) {
131: *e++ = '\0';
132: sp->s_nosend = e;
133: }
134: p = fldget(sp->s_nbuf, p);
135: lcase(sp->s_nbuf);
136: if (*p++ == '\0')
137: return TRUE;
138:
139: p = fldget(sp->s_flags, p);
140: if (*p++ == '\0')
141: return TRUE;
142:
143: (void) fldget(sp->s_xmit, p);
144: return TRUE;
145: }
146:
147: char *
148: fldget(q, p)
149: register char *q, *p;
150: {
151: while (*p && *p != ':') {
152: if (*p == '\\' && p[1]==':')
153: p++;
154: *q++ = *p++;
155: }
156: *q = '\0';
157: return p;
158: }
159:
160: /*
161: * Find the SUBFILE record for a system.
162: */
163: s_find(sp, system)
164: register struct srec *sp;
165: char *system;
166: {
167: s_openr();
168: while (s_read(sp))
169: if (strncmp(system, sp->s_name, SNLN) == 0) {
170: s_close();
171: return TRUE;
172: }
173: s_close();
174: return FALSE;
175: }
176:
177: /*
178: * Close sysfile.
179: */
180: s_close()
181: {
182: (void) fclose(sysfile);
183: }
184:
185: time_t
186: cgtdate(datestr)
187: char *datestr;
188: {
189: char junk[40],month[40],day[30],tod[60],year[50];
190: static time_t lasttime;
191: static char lastdatestr[BUFLEN] = "";
192:
193: if ( lastdatestr[0] && strcmp(datestr, lastdatestr) == 0)
194: return lasttime;
195: lasttime = getdate(datestr, (struct timeb *)NULL);
196: if (lasttime < 0 &&
197: sscanf(datestr, "%s %s %s %s %s", junk, month, day, tod, year) == 5) {
198: (void) sprintf(bfr, "%s %s, %s %s", month, day, year, tod);
199: lasttime = getdate(bfr, (struct timeb *)NULL);
200: }
201: strncpy(lastdatestr, datestr, BUFLEN);
202: return lasttime;
203: }
204:
205: lcase(s)
206: register char *s;
207: {
208: register char *ptr;
209:
210: for (ptr = s; *ptr; ptr++)
211: if (isupper(*ptr))
212: *ptr = tolower(*ptr);
213: }
214:
215: /*
216: * Return a compact representation of the person who posted the given
217: * message. A sender or internet name will be used, otherwise
218: * the last part of the path is used preceded by an optional ".."
219: */
220: char *
221: tailpath(hp)
222: struct hbuf *hp;
223: {
224: char *p, *r;
225: static char resultbuf[BUFLEN];
226: char pathbuf[PATHLEN];
227: char *malloc();
228:
229: /*
230: * This only happens for articles posted by old news software
231: * in non-internet format.
232: */
233: resultbuf[0] = '\0';
234: (void) strncpy(pathbuf, hp->path, PATHLEN);
235: p = index(pathbuf, ' ');
236: if (p)
237: *p = '\0'; /* Chop off trailing " (name)" */
238: r = rindex(pathbuf, '!');
239: if (r == 0) {
240: r = pathbuf;
241: } else {
242: while (r > pathbuf && *--r != '!')
243: ;
244: if (r > pathbuf) {
245: r++;
246: (void) strcpy(resultbuf, "..!");
247: }
248: }
249: (void) strcat(resultbuf, r);
250: return resultbuf;
251: }
252:
253: /*
254: * arpadate is like ctime(3) except that the time is returned in
255: * an acceptable ARPANET time format instead of ctime format.
256: */
257: char *
258: arpadate(longtime)
259: time_t *longtime;
260: {
261: register char *p, *q, *ud;
262: register int i;
263: static char b[40];
264: extern struct tm *gmtime();
265: extern char *asctime();
266:
267: /* Get current time. This will be used resolve the timezone. */
268: ud = asctime(gmtime(longtime));
269:
270: /* Crack the UNIX date line in a singularly unoriginal way. */
271: q = b;
272:
273: #ifdef notdef
274: /* until every site installs the fix to getdate.y, the day
275: of the week can cause time warps */
276: p = &ud[0]; /* Mon */
277: *q++ = *p++;
278: *q++ = *p++;
279: *q++ = *p++;
280: *q++ = ','; *q++ = ' ';
281: #endif
282:
283: p = &ud[8]; /* 16 */
284: if (*p == ' ')
285: p++;
286: else
287: *q++ = *p++;
288: *q++ = *p++; *q++ = ' ';
289:
290: p = &ud[4]; /* Sep */
291: *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = ' ';
292:
293: p = &ud[22]; /* 1979 */
294: *q++ = *p++; *q++ = *p++; *q++ = ' ';
295:
296: p = &ud[11]; /* 01:03:52 */
297: for (i = 8; i > 0; i--)
298: *q++ = *p++;
299:
300: *q++ = ' ';
301: *q++ = 'G'; /* GMT */
302: *q++ = 'M';
303: *q++ = 'T';
304: *q = '\0';
305:
306: return b;
307: }
308:
309: char *
310: replyname(hptr)
311: struct hbuf *hptr;
312: {
313: register char *ptr;
314: static char tbuf[PATHLEN];
315:
316: ptr = hptr->path;
317: if (prefix(ptr, FULLSYSNAME) &&
318: index(NETCHRS, ptr[strlen(FULLSYSNAME)]))
319: ptr = index(ptr, '!') + 1;
320: #ifdef INTERNET
321: if (hptr->from[0])
322: ptr = hptr->from;
323: if (hptr->replyto[0])
324: ptr = hptr->replyto;
325: #endif
326: (void) strcpy(tbuf, ptr);
327: ptr = index(tbuf, '(');
328: if (ptr) {
329: while (ptr[-1] == ' ')
330: ptr--;
331: *ptr = 0;
332: }
333: #ifdef SunIII
334: if (ptr = rindex(tbuf, '.')) {
335: if (prefix(++ptr, "OZ")) {
336: /* some people only allow it in lower case ... */
337: strcpy(ptr, "oz");
338: return tbuf;
339: }
340: if (prefix(ptr, "UUCP") || prefix(ptr, "ARPA") ||
341: prefix(ptr, "DEC") || prefix(ptr, "CSNET")) {
342: strcat(tbuf, "@munnari.oz"); /* via sun to munnari */
343: return tbuf;
344: }
345: }
346: /*
347: * must(?) have come from a uucp site, lets look see if path passes
348: * through munnari, and if so delete the fake uucp path after that.
349: */
350: for (ptr = tbuf ;; ptr++) {
351: if (prefix(ptr, "munnari!")) {
352: strcpy(tbuf, ptr+8);
353: break;
354: }
355: ptr = index(ptr, '!');
356: if (ptr == (char *)0)
357: break;
358: }
359: /*
360: * now, just send the address we have left to munnari, and
361: * hope that something sensible will be done with it there.
362: * (This works in more cases than you'd think ...)
363: */
364: strcat(tbuf, "@munnari.oz");
365: #else /* !SunIII */
366: #ifndef INTERNET
367: /*
368: * Play games stripping off multiple berknet
369: * addresses (a!b!c:d:e => a!b!d:e) here.
370: */
371: for (ptr=tbuf; *ptr; ptr++) {
372: register char *ptr2;
373:
374: if (index(NETCHRS, *ptr) && *ptr == ':' &&
375: (ptr2=index(ptr+1, ':')))
376: (void) strcpy(ptr, ptr2);
377: }
378: #endif /* !INTERNET */
379: #endif /* SunIII */
380: return tbuf;
381: }
382:
383: #ifdef DBM
384: typedef struct {
385: char *dptr;
386: int dsize;
387: } datum;
388: #endif /* DBM */
389:
390: /*
391: * Given an article ID, find the line in the history file that mentions it.
392: * Return the text of the line, or NULL if not found. A pointer to a
393: * static area is returned.
394: */
395: char *
396: findhist(artid)
397: char *artid;
398: {
399: static char lbuf[256];
400: char oidbuf[BUFSIZ];
401: FILE *hfp;
402: register char *p;
403: #ifdef DBM
404: datum lhs, rhs;
405: datum fetch();
406: long fpos; /* We have to use an explicit variable to insure alignment */
407: #else /* !DBM */
408: char *histfile();
409: #endif /* !DBM */
410:
411: /* Try to understand old artid's as well. Assume .UUCP domain. */
412: if (artid[0] != '<') {
413: p = index(artid, '.');
414: if (p)
415: *p++ = '\0';
416: (void) sprintf(oidbuf, "<%s@%s.UUCP>", p, artid);
417: if (p)
418: *--p = '.';
419: } else
420: (void) strcpy(oidbuf, artid);
421: lcase(oidbuf);
422: #ifdef DBM
423: initdbm(ARTFILE);
424: lhs.dptr = oidbuf;
425: lhs.dsize = strlen(lhs.dptr) + 1;
426: rhs = fetch(lhs);
427: if (rhs.dptr == NULL)
428: return NULL;
429: hfp = xfopen(ARTFILE, "r");
430: /* The bcopy is NECESSARY to insure alignment on some machines */
431: bcopy(rhs.dptr, (char *)&fpos, sizeof (long));
432: fseek(hfp, fpos, 0);
433: #else /* !DBM */
434: hfp = xfopen(histfile(oidbuf), "r");
435: #endif /* !DBM */
436: while (fgets(lbuf, BUFLEN, hfp) != NULL) {
437: p = index(lbuf, '\t');
438: if (p == NULL)
439: p = index(lbuf, '\n');
440: *p = 0;
441: if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) {
442: (void) fclose(hfp);
443: *p = '\t';
444: *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */
445: return lbuf;
446: }
447: #ifdef DBM
448: break;
449: #endif /* DBM */
450: }
451: (void) fclose(hfp);
452: return NULL;
453: }
454:
455: /*
456: * Hunt up the article "artid", and return the newsgroup/artnum
457: * where it can be found.
458: */
459: char *
460: findfname(artid)
461: char *artid;
462: {
463: char *line, *p, *q;
464: char *findhist();
465: static char fname[BUFLEN];
466:
467: line = findhist(artid);
468: if (line) {
469: /* Look for it stored as an article, where it should be */
470: p = index(line, '\t');
471: p = index(p+1, '\t');
472: p++;
473: if (*p) {
474: q = index(p, ' ');
475: if (q)
476: *q = 0;
477: (void) strcpy(fname, p);
478: return fname;
479: }
480: }
481: return NULL;
482: }
483:
484: /*
485: * Hunt up the article "artid", fopen it for read, and return a
486: * file descriptor to it. We look everywhere we can think of.
487: */
488: FILE *
489: hfopen(artid)
490: char *artid;
491: {
492: char *p;
493: char *findhist();
494: FILE *rv = NULL;
495: char fname[BUFLEN];
496:
497: p = findfname(artid);
498: if (p) {
499: (void) strcpy(fname, dirname(p));
500: rv = fopen(fname, "r"); /* NOT xfopen! */
501: if (rv == NULL)
502: xerror("Cannot hfopen article %s", artid);
503: }
504: return rv;
505: }
506:
507: #ifdef DBM
508: /*
509: ** Avoid problems of multiple dbminit calls.
510: */
511: initdbm(name)
512: char *name;
513: {
514: static int called = 0;
515:
516: if (called != 0)
517: return;
518: called = 1;
519: (void) dbminit(name);
520: }
521: #endif
522:
523: #ifndef BSD4_2
524: /*
525: * move n bytes from a to b
526: */
527: bcopy(a, b, n)
528: register char *a, *b;
529: register n;
530: {
531: while (--n >= 0)
532: *b++ = *a++;
533: }
534: #endif
535:
536: #if !defined(BSD4_2) && !defined(BSD4_1C)
537: rename(from,to)
538: register char *from, *to;
539: {
540: (void) unlink(to);
541: if (link(from, to) < 0)
542: return -1;
543:
544: (void) unlink(from);
545: return 0;
546: }
547: #endif /* !BSD4_2 && ! BSD4_1C */
548:
549: #ifndef DBM
550: /*
551: ** Generate the appropriate history subfile name
552: */
553: char *
554: histfile(hline)
555: char *hline;
556: {
557: char *p;
558: char chr; /* least significant digit of article number */
559: static char subfile[BUFLEN];
560:
561: p = strchr(hline, '@');
562: if (p != NULL && p > hline)
563: chr = *(p - 1);
564: else
565: chr = '0';
566: if (!isdigit(chr))
567: chr = '0';
568: sprintf(subfile, "%s.d/%c", ARTFILE, chr);
569: if (access(subfile, 04) < 0)
570: return(ARTFILE);
571: return(subfile);
572: }
573: #endif /* !DBM */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.