|
|
1.1 root 1: /* $Header: bits.c,v 4.3 85/05/01 11:36:15 lwall Exp $
2: *
3: * $Log: bits.c,v $
4: * Revision 4.3 85/05/01 11:36:15 lwall
5: * Baseline for release with 4.3bsd.
6: *
7: */
8:
9: #include "EXTERN.h"
10: #include "common.h"
11: #include "rcstuff.h"
12: #include "head.h"
13: #include "util.h"
14: #include "final.h"
15: #include "rn.h"
16: #include "cheat.h"
17: #include "ng.h"
18: #include "artio.h"
19: #include "intrp.h"
20: #include "ngdata.h"
21: #include "rcln.h"
22: #include "kfile.h"
23: #include "INTERN.h"
24: #include "bits.h"
25:
26: #ifdef DBM
27: # ifdef NULL
28: # undef NULL
29: # endif NULL
30: # include <dbm.h>
31: #endif DBM
32: MEM_SIZE ctlsize; /* size of bitmap in bytes */
33:
34: void
35: bits_init()
36: {
37: #ifdef DELAYMARK
38: dmname = savestr(filexp(RNDELNAME));
39: #else
40: ;
41: #endif
42: }
43:
44: /* checkpoint the .newsrc */
45:
46: void
47: checkpoint_rc()
48: {
49: #ifdef DEBUGGING
50: if (debug & DEB_CHECKPOINTING) {
51: fputs("(ckpt)",stdout);
52: fflush(stdout);
53: }
54: #endif
55: if (doing_ng)
56: restore_ng(); /* do not restore M articles */
57: if (rc_changed)
58: write_rc();
59: #ifdef DEBUGGING
60: if (debug & DEB_CHECKPOINTING) {
61: fputs("(done)",stdout);
62: fflush(stdout);
63: }
64: #endif
65: }
66:
67: /* reconstruct the .newsrc line in a human readable form */
68:
69: void
70: restore_ng()
71: {
72: register char *s, *mybuf = buf;
73: register ART_NUM i;
74: ART_NUM count=0;
75: int safelen = LBUFLEN - 16;
76:
77: strcpy(buf,rcline[ng]); /* start with the newsgroup name */
78: s = buf + rcnums[ng] - 1; /* use s for buffer pointer */
79: *s++ = rcchar[ng]; /* put the requisite : or !*/
80: *s++ = ' '; /* put the not-so-requisite space */
81: for (i=1; i<=lastart; i++) { /* for each article in newsgroup */
82: if (s-mybuf > safelen) { /* running out of room? */
83: safelen *= 2;
84: if (mybuf == buf) { /* currently static? */
85: *s = '\0';
86: mybuf = safemalloc((MEM_SIZE)safelen + 16);
87: strcpy(mybuf,buf); /* so we must copy it */
88: s = mybuf + (s-buf);
89: /* fix the pointer, too */
90: }
91: else { /* just grow in place, if possible */
92: char *newbuf;
93:
94: newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
95: s = newbuf + (s-mybuf);
96: mybuf = newbuf;
97: }
98: }
99: if (!was_read(i)) /* still unread? */
100: count++; /* then count it */
101: else { /* article was read */
102: ART_NUM oldi;
103:
104: sprintf(s,"%ld",(long)i); /* put out the min of the range */
105: s += strlen(s); /* keeping house */
106: oldi = i; /* remember this spot */
107: do i++; while (i <= lastart && was_read(i));
108: /* find 1st unread article or end */
109: i--; /* backup to last read article */
110: if (i > oldi) { /* range of more than 1? */
111: sprintf(s,"-%ld,",(long)i);
112: /* then it out as a range */
113: s += strlen(s); /* and housekeep */
114: }
115: else
116: *s++ = ','; /* otherwise, just a comma will do */
117: }
118: }
119: if (*(s-1) == ',') /* is there a final ','? */
120: s--; /* take it back */
121: *s++ = '\0'; /* and terminate string */
122: #ifdef DEBUGGING
123: if (debug & DEB_NEWSRC_LINE && !panic) {
124: printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
125: printf("%s\n",mybuf) FLUSH;
126: }
127: #endif
128: free(rcline[ng]); /* return old rc line */
129: if (mybuf == buf) {
130: rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
131: /* grab a new rc line */
132: strcpy(rcline[ng], buf); /* and load it */
133: }
134: else {
135: mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
136: /* be nice to the heap */
137: rcline[ng] = mybuf;
138: }
139: *(rcline[ng] + rcnums[ng] - 1) = '\0';
140: if (rcchar[ng] == NEGCHAR) { /* did they unsubscribe? */
141: printf(unsubto,ngname) FLUSH;
142: toread[ng] = TR_UNSUB; /* make line invisible */
143: }
144: else
145: /*NOSTRICT*/
146: toread[ng] = (ART_UNREAD)count; /* remember how many unread there are */
147: }
148:
149: /* mark an article unread, keeping track of toread[] */
150:
151: void
152: onemore(artnum)
153: ART_NUM artnum;
154: {
155: #ifdef DEBUGGING
156: if (debug && artnum < firstart) {
157: printf("onemore: %d < %d\n",artnum,firstart) FLUSH;
158: return;
159: }
160: #endif
161: if (ctl_read(artnum)) {
162: ctl_clear(artnum);
163: ++toread[ng];
164: }
165: }
166:
167: /* mark an article read, keeping track of toread[] */
168:
169: void
170: oneless(artnum)
171: ART_NUM artnum;
172: {
173: #ifdef DEBUGGING
174: if (debug && artnum < firstart) {
175: printf("oneless: %d < %d\n",artnum,firstart) FLUSH;
176: return;
177: }
178: #endif
179: if (!ctl_read(artnum)) {
180: ctl_set(artnum);
181: if (toread[ng] > TR_NONE)
182: --toread[ng];
183: }
184: }
185:
186: /* mark an article as unread, making sure that firstart is properly handled */
187: /* cross-references are left as read in the other newsgroups */
188:
189: void
190: unmark_as_read(artnum)
191: ART_NUM artnum;
192: {
193: check_first(artnum);
194: onemore(artnum);
195: #ifdef MCHASE
196: if (!parse_maybe(artnum))
197: chase_xrefs(artnum,FALSE);
198: #endif
199: }
200:
201: #ifdef DELAYMARK
202: /* temporarily mark article as read. When newsgroup is exited, articles */
203: /* will be marked as unread. Called via M command */
204:
205: void
206: delay_unmark(artnum)
207: ART_NUM artnum;
208: {
209: if (dmfp == Nullfp) {
210: dmfp = fopen(dmname,"w");
211: if (dmfp == Nullfp) {
212: printf(cantcreate,dmname) FLUSH;
213: sig_catcher(0);
214: }
215: }
216: oneless(artnum); /* set the correct bit */
217: dmcount++;
218: fprintf(dmfp,"%ld\n",(long)artnum);
219: }
220: #endif
221:
222: /* mark article as read. If article is cross referenced to other */
223: /* newsgroups, mark them read there also. */
224:
225: void
226: mark_as_read(artnum)
227: ART_NUM artnum;
228: {
229: oneless(artnum); /* set the correct bit */
230: checkcount++; /* get more worried about crashes */
231: chase_xrefs(artnum,TRUE);
232: }
233:
234: /* make sure we have bits set correctly down to firstart */
235:
236: void
237: check_first(min)
238: ART_NUM min;
239: {
240: register ART_NUM i = firstart;
241:
242: if (min < absfirst)
243: min = absfirst;
244: if (min < i) {
245: for (i--; i>=min; i--)
246: ctl_set(i); /* mark as read */
247: firstart = min;
248: }
249: }
250:
251: /* bring back articles marked with M */
252:
253: #ifdef DELAYMARK
254: void
255: yankback()
256: {
257: register ART_NUM anum;
258:
259: if (dmfp) { /* delayed unmarks pending? */
260: #ifdef VERBOSE
261: printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
262: dmcount == 1 ? nullstr : "s") FLUSH;
263: #endif
264: fclose(dmfp);
265: if (dmfp = fopen(dmname,"r")) {
266: while (fgets(buf,sizeof buf,dmfp) != Nullch) {
267: anum = (ART_NUM)atol(buf);
268: /*NOSTRICT*/
269: onemore(anum); /* then unmark them */
270: #ifdef MCHASE
271: chase_xrefs(anum,FALSE);
272: #endif
273: }
274: fclose(dmfp);
275: dmfp = Nullfp;
276: UNLINK(dmname); /* and be tidy */
277: }
278: else {
279: printf(cantopen,dmname) FLUSH;
280: sig_catcher(0);
281: }
282: }
283: dmcount = 0;
284: }
285: #endif
286:
287: /* run down xref list and mark as read or unread */
288:
289: int
290: chase_xrefs(artnum,markread)
291: ART_NUM artnum;
292: int markread;
293: {
294: #ifdef ASYNC_PARSE
295: if (parse_maybe(artnum)) /* make sure we have right header */
296: return -1;
297: #endif
298: #ifdef DBM
299: {
300: datum lhs, rhs;
301: datum fetch();
302: register char *idp;
303: char *ident_buf;
304: static FILE * hist_file = Nullfp;
305: #else
306: if (
307: #ifdef DEBUGGING
308: debug & DEB_FEED_XREF ||
309: #endif
310: htype[XREF_LINE].ht_minpos >= 0) {
311: /* are there article# xrefs? */
312: #endif DBM
313: char *xref_buf, *curxref;
314: register char *xartnum;
315: char *rver_buf = Nullch;
316: static char *inews_site = Nullch;
317: register ART_NUM x;
318: char tmpbuf[128];
319:
320: #ifdef DBM
321: rver_buf = fetchlines(artnum,NGS_LINE);
322: /* get Newsgroups */
323: if (!index(rver_buf,',')) /* if no comma, no Xref! */
324: return 0;
325: if (hist_file == Nullfp) { /* Init. file accesses */
326: #ifdef DEBUGGING
327: if (debug)
328: printf ("chase_xref: opening files\n");
329: #endif
330: dbminit(filexp(ARTFILE));
331: if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
332: return 0;
333: }
334: xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
335: ident_buf = fetchlines(artnum,MESSID_LINE);
336: /* get Message-ID */
337: #ifdef DEBUGGING
338: if (debug)
339: printf ("chase_xref: Message-ID: %s\n", ident_buf);
340: #endif
341: idp = ident_buf;
342: while (*++idp) /* make message-id case insensitive */
343: if (isupper(*idp))
344: *idp = tolower (*idp);
345: lhs.dptr = ident_buf; /* look up article by id */
346: lhs.dsize = strlen(lhs.dptr) + 1;
347: rhs = fetch(lhs); /* fetch the record */
348: if (rhs.dptr == NULL) /* if null, nothing there */
349: goto wild_goose;
350: fseek (hist_file, *((long *)rhs.dptr), 0);
351: /* datum returned is position in hist file */
352: fgets (xref_buf, BUFSIZ, hist_file);
353: #ifdef DEBUGGING
354: if (debug)
355: printf ("Xref from history: %s\n", xref_buf);
356: #endif
357: curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
358: curxref = cpytill(tmpbuf, curxref, '\t') + 1;
359: #ifdef DEBUGGING
360: if (debug)
361: printf ("chase_xref: curxref: %s\n", curxref);
362: #endif
363: #else !DBM
364: #ifdef DEBUGGING
365: if (htype[XREF_LINE].ht_minpos >= 0)
366: #endif
367: xref_buf = fetchlines(artnum,XREF_LINE);
368: /* get xrefs list */
369: #ifdef DEBUGGING
370: else {
371: xref_buf = safemalloc((MEM_SIZE)100);
372: printf("Give Xref: ") FLUSH;
373: gets(xref_buf);
374: }
375: #endif
376: #ifdef DEBUGGING
377: if (debug & DEB_XREF_MARKER)
378: printf("Xref: %s\n",xref_buf) FLUSH;
379: #endif
380: curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
381:
382: /* Make sure site name on Xref matches what inews thinks site is.
383: * Check first against last inews_site. If it matches, fine.
384: * If not, fetch inews_site from current Relay-Version line and
385: * check again. This is so that if the new administrator decides
386: * to change the system name as known to inews, rn will still do
387: * Xrefs correctly--each article need only match itself to be valid.
388: */
389: if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
390: char *t;
391:
392: if (inews_site != Nullch)
393: free(inews_site);
394: #ifndef NORELAY
395: rver_buf = fetchlines(artnum,RVER_LINE);
396: if ((t = instr(rver_buf,"; site ")) == Nullch)
397: #else NORELAY
398:
399: /* In version 2.10.3 of news or afterwards, the Relay-Version
400: * and Posting-Version header lines have been removed. For
401: * the code below to work as intended, I have modified it to
402: * extract the first component of the Path header line. This
403: * should give the same effect as did the old code with respect
404: * to the use of the Relay-Version site name.
405: */
406: rver_buf = fetchlines(artnum,PATH_LINE);
407: if ((t = instr(rver_buf,"!")) == Nullch)
408: #endif NORELAY
409: inews_site = savestr(nullstr);
410: else {
411: char new_site[128];
412:
413: #ifndef NORELAY
414: cpytill(new_site,t + 7,'.');
415: #else NORELAY
416: cpytill(new_site,rver_buf,'!');
417: #endif NORELAY
418: inews_site = savestr(new_site);
419: }
420: if (strNE(tmpbuf,inews_site)) {
421: #ifdef DEBUGGING
422: if (debug)
423: printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
424: #endif
425: goto wild_goose;
426: }
427: }
428: #endif DBM
429: while (*curxref) {
430: /* for each newsgroup */
431: curxref = cpytill(tmpbuf,curxref,' ');
432: #ifdef DBM
433: xartnum = index(tmpbuf,'/');
434: #else
435: xartnum = index(tmpbuf,':');
436: #endif DBM
437: if (!xartnum) /* probably an old-style Xref */
438: break;
439: *xartnum++ = '\0';
440: if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
441: x = atol(xartnum);
442: if (x)
443: if (markread) {
444: if (addartnum(x,tmpbuf))
445: goto wild_goose;
446: }
447: #ifdef MCHASE
448: else
449: subartnum(x,tmpbuf);
450: #endif
451: }
452: while (*curxref && isspace(*curxref))
453: curxref++;
454: }
455: wild_goose:
456: free(xref_buf);
457: #ifdef DBM
458: free(ident_buf);
459: #endif DBM
460: if (rver_buf != Nullch)
461: free(rver_buf);
462: }
463: return 0;
464: }
465:
466: int
467: initctl()
468: {
469: char *mybuf = buf; /* place to decode rc line */
470: register char *s, *c, *h;
471: register long i;
472: register ART_NUM unread;
473:
474: #ifdef DELAYMARK
475: dmcount = 0;
476: #endif
477: if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */
478: return -1;
479:
480: absfirst = getabsfirst(ng,lastart); /* remember first existing article */
481: if (!absfirst) /* no articles at all? */
482: absfirst = 1; /* pretend there is one */
483: #ifndef lint
484: ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
485: #endif lint
486: ctlarea = safemalloc(ctlsize); /* allocate control area */
487:
488: /* now modify ctlarea to reflect what has already been read */
489:
490: for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
491: /* find numbers in rc line */
492: i = strlen(s);
493: #ifndef lint
494: if (i >= LBUFLEN-2) /* bigger than buf? */
495: mybuf = safemalloc((MEM_SIZE)(i+2));
496: #endif lint
497: strcpy(mybuf,s); /* make scratch copy of line */
498: mybuf[i++] = ','; /* put extra comma on the end */
499: mybuf[i] = '\0';
500: s = mybuf; /* initialize the for loop below */
501: if (strnEQ(s,"1-",2)) { /* can we save some time here? */
502: firstart = atol(s+2)+1; /* ignore first range thusly */
503: s=index(s,',') + 1;
504: }
505: else
506: firstart = 1; /* all the bits are valid for now */
507: if (absfirst > firstart) { /* do we know already? */
508: firstart = absfirst; /* no point calling getngmin again */
509: }
510: else if (artopen(firstart) == Nullfp) {
511: /* first unread article missing? */
512: i = getngmin(".",firstart); /* see if expire has been busy */
513: if (i) { /* avoid a bunch of extra opens */
514: firstart = i;
515: }
516: }
517: #ifdef PENDING
518: # ifdef CACHESUBJ
519: subj_to_get = firstart;
520: # endif
521: #endif
522: unread = lastart - firstart + 1; /* assume this range unread */
523: for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++)
524: ctlarea[i] = 0; /* assume unread */
525: #ifdef DEBUGGING
526: if (debug & DEB_CTLAREA_BITMAP) {
527: printf("\n%s\n",mybuf) FLUSH;
528: for (i=1; i <= lastart; i++)
529: if (! was_read(i))
530: printf("%ld ",(long)i) FLUSH;
531: }
532: #endif
533: for ( ; (c = index(s,',')) != Nullch; s = ++c) {
534: /* for each range */
535: ART_NUM min, max;
536:
537: *c = '\0'; /* do not let index see past comma */
538: if ((h = index(s,'-')) != Nullch) { /* is there a -? */
539: min = atol(s);
540: max = atol(h+1);
541: if (min < firstart) /* make sure range is in range */
542: min = firstart;
543: if (max > lastart)
544: max = lastart;
545: if (min <= max) /* non-null range? */
546: unread -= max - min + 1;/* adjust unread count */
547: for (i=min; i<=max; i++) /* for all articles in range */
548: ctl_set(i); /* mark them read */
549: }
550: else if ((i = atol(s)) >= firstart && i <= lastart) {
551: /* is single number reasonable? */
552: ctl_set(i); /* mark it read */
553: unread--; /* decrement articles to read */
554: }
555: #ifdef DEBUGGING
556: if (debug & DEB_CTLAREA_BITMAP) {
557: printf("\n%s\n",s) FLUSH;
558: for (i=1; i <= lastart; i++)
559: if (! was_read(i))
560: printf("%ld ",(long)i) FLUSH;
561: }
562: #endif
563: }
564: #ifdef DEBUGGING
565: if (debug & DEB_CTLAREA_BITMAP) {
566: fputs("\n(hit CR)",stdout) FLUSH;
567: gets(cmd_buf);
568: }
569: #endif
570: if (mybuf != buf)
571: free(mybuf);
572: toread[ng] = unread;
573: return 0;
574: }
575:
576: void
577: grow_ctl()
578: {
579: ART_NUM newlast;
580: ART_NUM tmpfirst;
581: MEM_SIZE newsize;
582: register ART_NUM i;
583:
584: forcegrow = FALSE;
585: newlast = getngsize(ng);
586: if (newlast > lastart) {
587: ART_NUM tmpart = art;
588: #ifndef lint
589: newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
590: #else
591: newsize = Null(MEM_SIZE);
592: #endif lint
593: if (newsize > ctlsize) {
594: newsize += 20;
595: ctlarea = saferealloc(ctlarea,newsize);
596: ctlsize = newsize;
597: }
598: toread[ng] += (ART_UNREAD)(newlast-lastart);
599: for (i=lastart+1; i<=newlast; i++)
600: ctl_clear(i); /* these articles are unread */
601: #ifdef CACHESUBJ
602: if (subj_list != Null(char**)) {
603: #ifndef lint
604: subj_list = (char**)saferealloc((char*)subj_list,
605: (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
606: #endif lint
607: for (i=lastart+1; i<=newlast; i++)
608: subj_list[OFFSET(i)] = Nullch;
609: }
610: #endif
611: tmpfirst = lastart+1;
612: lastart = newlast;
613: #ifdef KILLFILES
614: #ifdef VERBOSE
615: IF(verbose)
616: sprintf(buf,
617: "%ld more article%s arrived--looking for more to kill...\n\n",
618: (long)(lastart - firstart + 1),
619: (lastart > firstart ? "s have" : " has" ) );
620: ELSE /* my, my, how clever we are */
621: #endif
622: #ifdef TERSE
623: strcpy(buf, "More news--killing...\n\n");
624: #endif
625: kill_unwanted(tmpfirst,buf,TRUE);
626: #endif
627: art = tmpart;
628: }
629: }
630:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.