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