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: rver_buf = fetchlines(artnum,RVER_LINE); 395: if ((t = instr(rver_buf,"; site ")) == Nullch) 396: inews_site = savestr(nullstr); 397: else { 398: char new_site[128]; 399: 400: cpytill(new_site,t + 7,'.'); 401: inews_site = savestr(new_site); 402: } 403: if (strNE(tmpbuf,inews_site)) { 404: #ifdef DEBUGGING 405: if (debug) 406: printf("Xref not from %s--ignoring\n",inews_site) FLUSH; 407: #endif 408: goto wild_goose; 409: } 410: } 411: #endif DBM 412: while (*curxref) { 413: /* for each newsgroup */ 414: curxref = cpytill(tmpbuf,curxref,' '); 415: #ifdef DBM 416: xartnum = index(tmpbuf,'/'); 417: #else 418: xartnum = index(tmpbuf,':'); 419: #endif DBM 420: if (!xartnum) /* probably an old-style Xref */ 421: break; 422: *xartnum++ = '\0'; 423: if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */ 424: x = atol(xartnum); 425: if (x) 426: if (markread) { 427: if (addartnum(x,tmpbuf)) 428: goto wild_goose; 429: } 430: #ifdef MCHASE 431: else 432: subartnum(x,tmpbuf); 433: #endif 434: } 435: while (*curxref && isspace(*curxref)) 436: curxref++; 437: } 438: wild_goose: 439: free(xref_buf); 440: #ifdef DBM 441: free(ident_buf); 442: #endif DBM 443: if (rver_buf != Nullch) 444: free(rver_buf); 445: } 446: return 0; 447: } 448: 449: int 450: initctl() 451: { 452: char *mybuf = buf; /* place to decode rc line */ 453: register char *s, *c, *h; 454: register long i; 455: register ART_NUM unread; 456: 457: #ifdef DELAYMARK 458: dmcount = 0; 459: #endif 460: if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */ 461: return -1; 462: 463: absfirst = getabsfirst(ng,lastart); /* remember first existing article */ 464: if (!absfirst) /* no articles at all? */ 465: absfirst = 1; /* pretend there is one */ 466: #ifndef lint 467: ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20); 468: #endif lint 469: ctlarea = safemalloc(ctlsize); /* allocate control area */ 470: 471: /* now modify ctlarea to reflect what has already been read */ 472: 473: for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ; 474: /* find numbers in rc line */ 475: i = strlen(s); 476: #ifndef lint 477: if (i >= LBUFLEN-2) /* bigger than buf? */ 478: mybuf = safemalloc((MEM_SIZE)(i+2)); 479: #endif lint 480: strcpy(mybuf,s); /* make scratch copy of line */ 481: mybuf[i++] = ','; /* put extra comma on the end */ 482: mybuf[i] = '\0'; 483: s = mybuf; /* initialize the for loop below */ 484: if (strnEQ(s,"1-",2)) { /* can we save some time here? */ 485: firstart = atol(s+2)+1; /* ignore first range thusly */ 486: s=index(s,',') + 1; 487: } 488: else 489: firstart = 1; /* all the bits are valid for now */ 490: if (absfirst > firstart) { /* do we know already? */ 491: firstart = absfirst; /* no point calling getngmin again */ 492: } 493: else if (artopen(firstart) == Nullfp) { 494: /* first unread article missing? */ 495: i = getngmin(".",firstart); /* see if expire has been busy */ 496: if (i) { /* avoid a bunch of extra opens */ 497: firstart = i; 498: } 499: } 500: #ifdef PENDING 501: # ifdef CACHESUBJ 502: subj_to_get = firstart; 503: # endif 504: #endif 505: unread = lastart - firstart + 1; /* assume this range unread */ 506: for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++) 507: ctlarea[i] = 0; /* assume unread */ 508: #ifdef DEBUGGING 509: if (debug & DEB_CTLAREA_BITMAP) { 510: printf("\n%s\n",mybuf) FLUSH; 511: for (i=1; i <= lastart; i++) 512: if (! was_read(i)) 513: printf("%ld ",(long)i) FLUSH; 514: } 515: #endif 516: for ( ; (c = index(s,',')) != Nullch; s = ++c) { 517: /* for each range */ 518: ART_NUM min, max; 519: 520: *c = '\0'; /* do not let index see past comma */ 521: if ((h = index(s,'-')) != Nullch) { /* is there a -? */ 522: min = atol(s); 523: max = atol(h+1); 524: if (min < firstart) /* make sure range is in range */ 525: min = firstart; 526: if (max > lastart) 527: max = lastart; 528: if (min <= max) /* non-null range? */ 529: unread -= max - min + 1;/* adjust unread count */ 530: for (i=min; i<=max; i++) /* for all articles in range */ 531: ctl_set(i); /* mark them read */ 532: } 533: else if ((i = atol(s)) >= firstart && i <= lastart) { 534: /* is single number reasonable? */ 535: ctl_set(i); /* mark it read */ 536: unread--; /* decrement articles to read */ 537: } 538: #ifdef DEBUGGING 539: if (debug & DEB_CTLAREA_BITMAP) { 540: printf("\n%s\n",s) FLUSH; 541: for (i=1; i <= lastart; i++) 542: if (! was_read(i)) 543: printf("%ld ",(long)i) FLUSH; 544: } 545: #endif 546: } 547: #ifdef DEBUGGING 548: if (debug & DEB_CTLAREA_BITMAP) { 549: fputs("\n(hit CR)",stdout) FLUSH; 550: gets(cmd_buf); 551: } 552: #endif 553: if (mybuf != buf) 554: free(mybuf); 555: toread[ng] = unread; 556: return 0; 557: } 558: 559: void 560: grow_ctl() 561: { 562: ART_NUM newlast; 563: ART_NUM tmpfirst; 564: MEM_SIZE newsize; 565: register ART_NUM i; 566: 567: forcegrow = FALSE; 568: newlast = getngsize(ng); 569: if (newlast > lastart) { 570: ART_NUM tmpart = art; 571: #ifndef lint 572: newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2); 573: #else 574: newsize = Null(MEM_SIZE); 575: #endif lint 576: if (newsize > ctlsize) { 577: newsize += 20; 578: ctlarea = saferealloc(ctlarea,newsize); 579: ctlsize = newsize; 580: } 581: toread[ng] += (ART_UNREAD)(newlast-lastart); 582: for (i=lastart+1; i<=newlast; i++) 583: ctl_clear(i); /* these articles are unread */ 584: #ifdef CACHESUBJ 585: if (subj_list != Null(char**)) { 586: #ifndef lint 587: subj_list = (char**)saferealloc((char*)subj_list, 588: (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) ); 589: #endif lint 590: for (i=lastart+1; i<=newlast; i++) 591: subj_list[OFFSET(i)] = Nullch; 592: } 593: #endif 594: tmpfirst = lastart+1; 595: lastart = newlast; 596: #ifdef KILLFILES 597: #ifdef VERBOSE 598: IF(verbose) 599: sprintf(buf, 600: "%ld more article%s arrived--looking for more to kill...\n\n", 601: (long)(lastart - firstart + 1), 602: (lastart > firstart ? "s have" : " has" ) ); 603: ELSE /* my, my, how clever we are */ 604: #endif 605: #ifdef TERSE 606: strcpy(buf, "More news--killing...\n\n"); 607: #endif 608: kill_unwanted(tmpfirst,buf,TRUE); 609: #endif 610: art = tmpart; 611: } 612: }