/* rcln.c
*/
/* This software is copyrighted as detailed in the LICENSE file. */
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "util2.h"
#include "list.h"
#include "hash.h"
#include "ngdata.h"
#include "nntpclient.h"
#include "datasrc.h"
#include "nntp.h"
#include "rcstuff.h"
#include "term.h"
#include "INTERN.h"
#include "rcln.h"
#define MAX_DIGITS 7
void
rcln_init()
{
;
}
#ifdef CATCHUP
void
catch_up(np, leave_count, output_level)
NGDATA* np;
int leave_count;
int output_level;
{
char tmpbuf[128];
if (leave_count) {
if (output_level) {
#ifdef VERBOSE
IF(verbose)
printf("\nMarking all but %d articles in %s as read.\n",
leave_count,np->rcline) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\nAll but %d marked as read.\n",leave_count) FLUSH;
#endif
}
checkexpired(np, getngsize(np) - leave_count + 1);
set_toread(np, ST_STRICT);
}
else {
if (output_level) {
#ifdef VERBOSE
IF(verbose)
printf("\nMarking %s as all read.\n",np->rcline) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("\nMarked read\n",stdout) FLUSH;
#endif
}
sprintf(tmpbuf,"%s: 1-%ld", np->rcline,(long)getngsize(np));
free(np->rcline);
np->rcline = savestr(tmpbuf);
*(np->rcline + np->numoffset - 1) = '\0';
if (ng_min_toread > TR_NONE && np->toread > TR_NONE)
newsgroup_toread--;
np->toread = TR_NONE;
}
np->rc->flags |= RF_RCCHANGED;
if (!write_newsrcs(multirc))
get_anything();
}
#endif
/* add an article number to a newsgroup, if it isn't already read */
int
addartnum(dp,artnum,ngnam)
DATASRC* dp;
ART_NUM artnum;
char* ngnam;
{
register NGDATA* np;
register char* s;
register char* t;
register char* maxt = NULL;
ART_NUM min = 0, max = -1, lastnum = 0;
char* mbuf;
bool_int morenum;
if (!artnum)
return 0;
np = find_ng(ngnam);
if (np == NULL) /* not found in newsrc? */
return 0;
if (dp != np->rc->datasrc) { /* punt on cross-host xrefs */
#ifdef DEBUG
if (debug & DEB_XREF_MARKER)
printf("Cross-host xref to group %s ignored.\n",ngnam) FLUSH;
#endif
return 0;
}
if (!np->numoffset)
return 0;
#ifndef ANCIENT_NEWS
if (!np->abs1st) {
/* Trim down the list due to expires if we haven't done so yet. */
set_toread(np, ST_LAX);
}
#endif
#if 0
if (artnum > np->ngmax + 200) { /* allow for incoming articles */
printf("\nCorrupt Xref line!!! %ld --> %s(1..%ld)\n",
artnum,ngnam,
np->ngmax) FLUSH;
paranoid = TRUE; /* paranoia reigns supreme */
return -1; /* hope this was the first newsgroup */
}
#endif
if (np->toread == TR_BOGUS)
return 0;
if (artnum > np->ngmax) {
if (np->toread > TR_NONE)
np->toread += artnum - np->ngmax;
np->ngmax = artnum;
}
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("%ld->\n%s%c%s\n",(long)artnum,np->rcline, np->subscribechar,
np->rcline + np->numoffset) FLUSH;
}
#endif
s = np->rcline + np->numoffset;
while (*s == ' ') s++; /* skip spaces */
t = s;
while (isdigit(*s) && artnum >= (min = atol(s))) {
/* while it might have been read */
for (t = s; isdigit(*t); t++) ; /* skip number */
if (*t == '-') { /* is it a range? */
t++; /* skip to next number */
if (artnum <= (max = atol(t)))
return 0; /* it is in range => already read */
lastnum = max; /* remember it */
maxt = t; /* remember position in case we */
/* want to overwrite the max */
while (isdigit(*t)) t++; /* skip second number */
}
else {
if (artnum == min) /* explicitly a read article? */
return 0;
lastnum = min; /* remember what the number was */
maxt = NULL; /* last one was not a range */
}
while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
s = t;
}
/* we have not read it, so insert the article number before s */
morenum = isdigit(*s); /* will it need a comma after? */
*(np->rcline + np->numoffset - 1) = np->subscribechar;
mbuf = safemalloc((MEM_SIZE)(strlen(s)+(s - np->rcline)+MAX_DIGITS+2+1));
strcpy(mbuf,np->rcline); /* make new rc line */
if (maxt && lastnum && artnum == lastnum+1)
/* can we just extend last range? */
t = mbuf + (maxt - np->rcline); /* then overwrite previous max */
else {
t = mbuf + (t - np->rcline); /* point t into new line instead */
if (lastnum) { /* have we parsed any line? */
if (!morenum) /* are we adding to the tail? */
*t++ = ','; /* supply comma before */
if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
/* adjacent singletons? */
*(t-1) = '-'; /* turn them into a range */
}
}
if (morenum) { /* is there more to life? */
if (min == artnum+1) { /* can we consolidate further? */
bool range_before = (*(t-1) == '-');
bool range_after;
char* nextmax;
for (nextmax = s; isdigit(*nextmax); nextmax++) ;
range_after = *nextmax++ == '-';
if (range_before)
*t = '\0'; /* artnum is redundant */
else
sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
if (range_after)
s = nextmax; /* *s is redundant */
/* else
s = s */ /* *s is new max */
}
else
sprintf(t,"%ld,",(long)artnum); /* put the number and comma */
}
else
sprintf(t,"%ld",(long)artnum); /* put the number there (wherever) */
strcat(t,s); /* copy remainder of line */
#ifdef DEBUG
if (debug & DEB_XREF_MARKER)
printf("%s\n",mbuf) FLUSH;
#endif
free(np->rcline);
np->rcline = mbuf; /* pull the switcheroo */
*(np->rcline + np->numoffset - 1) = '\0';
/* wipe out : or ! */
if (np->toread > TR_NONE) /* lest we turn unsub into bogus */
np->toread--;
return 0;
}
/* delete an article number from a newsgroup, if it is there */
#ifdef MCHASE
void
subartnum(dp,artnum,ngnam)
DATASRC* dp;
register ART_NUM artnum;
char* ngnam;
{
register NGDATA* np;
register char* s;
register char* t;
register ART_NUM min, max;
char* mbuf;
int curlen;
if (!artnum)
return;
np = find_ng(ngnam);
if (np == NULL) /* not found in newsrc? */
return;
if (dp != np->rc->datasrc) /* punt on cross-host xrefs */
return;
if (!np->numoffset)
return;
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("%ld<-\n%s%c%s\n",(long)artnum,np->rcline,np->subscribechar,
np->rcline + np->numoffset) FLUSH;
}
#endif
s = np->rcline + np->numoffset;
while (*s == ' ') s++; /* skip spaces */
/* a little optimization, since it is almost always the last number */
for (t=s; *t; t++) ; /* find end of string */
curlen = t - np->rcline;
for (t--; isdigit(*t); t--) ; /* find previous delim */
if (*t == ',' && atol(t+1) == artnum) {
*t = '\0';
if (np->toread >= TR_NONE)
++np->toread;
#ifdef DEBUG
if (debug & DEB_XREF_MARKER)
printf("%s%c %s\n",np->rcline,np->subscribechar,s) FLUSH;
#endif
return;
}
/* not the last number, oh well, we may need the length anyway */
while (isdigit(*s) && artnum >= (min = atol(s))) {
/* while it might have been read */
for (t = s; isdigit(*t); t++) ; /* skip number */
if (*t == '-') { /* is it a range? */
t++; /* skip to next number */
max = atol(t);
while (isdigit(*t)) t++; /* skip second number */
if (artnum <= max) {
/* it is in range => already read */
if (artnum == min) {
min++;
artnum = 0;
}
else if (artnum == max) {
max--;
artnum = 0;
}
*(np->rcline + np->numoffset - 1) = np->subscribechar;
mbuf = safemalloc((MEM_SIZE)(curlen+(artnum?(MAX_DIGITS+1)*2+1:1+1)));
*s = '\0';
strcpy(mbuf,np->rcline); /* make new rc line */
s = mbuf + (s - np->rcline);
/* point s into mbuf now */
if (artnum) { /* split into two ranges? */
prange(s,min,artnum-1);
s += strlen(s);
*s++ = ',';
prange(s,artnum+1,max);
}
else /* only one range */
prange(s,min,max);
strcat(s,t); /* copy remainder over */
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("%s\n",mbuf) FLUSH;
}
#endif
free(np->rcline);
np->rcline = mbuf; /* pull the switcheroo */
*(np->rcline + np->numoffset - 1) = '\0';
/* wipe out : or ! */
if (np->toread >= TR_NONE)
np->toread++;
return;
}
}
else {
if (artnum == min) { /* explicitly a read article? */
if (*t == ',') /* pick a comma, any comma */
t++;
else if (s[-1] == ',')
s--;
else if (s[-2] == ',') /* (in case of space) */
s -= 2;
strcpy(s,t); /* no need to realloc */
if (np->toread >= TR_NONE)
np->toread++;
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("%s%c%s\n",np->rcline,np->subscribechar,
np->rcline + np->numoffset) FLUSH;
}
#endif
return;
}
}
while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
s = t;
}
}
void
prange(where,min,max)
char* where;
ART_NUM min,max;
{
if (min == max)
sprintf(where,"%ld",(long)min);
else
sprintf(where,"%ld-%ld",(long)min,(long)max);
}
#endif
/* calculate the number of unread articles for a newsgroup */
void
set_toread(np, lax_high_check)
register NGDATA* np;
bool_int lax_high_check;
{
register char* s;
register char* c;
register char* h;
char tmpbuf[64];
char* mybuf = tmpbuf;
char* nums;
int length;
bool virgin_ng = (!np->abs1st);
ART_NUM ngsize = getngsize(np);
ART_NUM unread = ngsize;
ART_NUM newmax;
if (ngsize == TR_BOGUS) {
if (!toread_quiet) {
printf("\nInvalid (bogus) newsgroup found: %s\n",np->rcline)
FLUSH;
}
paranoid = TRUE;
if (virgin_ng || np->toread >= ng_min_toread) {
newsgroup_toread--;
missing_count++;
}
np->toread = TR_BOGUS;
return;
}
if (virgin_ng) {
sprintf(tmpbuf," 1-%ld",(long)ngsize);
if (strNE(tmpbuf,np->rcline+np->numoffset))
checkexpired(np,np->abs1st); /* this might realloc rcline */
}
nums = np->rcline + np->numoffset;
length = strlen(nums);
if (length+MAX_DIGITS+1 > sizeof tmpbuf)
mybuf = safemalloc((MEM_SIZE)(length+MAX_DIGITS+1));
strcpy(mybuf,nums);
mybuf[length++] = ',';
mybuf[length] = '\0';
for (s = mybuf; isspace(*s); s++)
;
for ( ; (c = index(s,',')) != NULL ; s = ++c) { /* for each range */
*c = '\0'; /* keep index from running off */
if ((h = index(s,'-')) != NULL) /* find - in range, if any */
unread -= (newmax = atol(h+1)) - atol(s) + 1;
else if ((newmax = atol(s)) != 0)
unread--; /* recalculate length */
if (newmax > ngsize) { /* paranoia check */
if (!lax_high_check && newmax > ngsize) {
unread = -1;
break;
} else {
unread += newmax - ngsize;
np->ngmax = ngsize = newmax;
}
}
}
if (unread < 0) { /* SOMEONE RESET THE NEWSGROUP!!! */
unread = (ART_UNREAD)ngsize; /* assume nothing carried over */
if (!toread_quiet) {
printf("\nSomebody reset %s -- assuming nothing read.\n",
np->rcline) FLUSH;
}
*(np->rcline + np->numoffset) = '\0';
paranoid = TRUE; /* enough to make a guy paranoid */
np->rc->flags |= RF_RCCHANGED;
}
if (np->subscribechar == NEGCHAR)
unread = TR_UNSUB;
if (unread >= ng_min_toread) {
if (!virgin_ng && np->toread < ng_min_toread)
newsgroup_toread++;
}
else if (unread <= 0) {
if (np->toread > ng_min_toread) {
newsgroup_toread--;
if (virgin_ng)
missing_count++;
}
}
np->toread = (ART_UNREAD)unread; /* remember how many are left */
if (mybuf != tmpbuf)
free(mybuf);
}
/* make sure expired articles are marked as read */
void
checkexpired(np,a1st)
register NGDATA* np;
register ART_NUM a1st;
{
register char* s;
register ART_NUM num, lastnum = 0;
char* mbuf;
char* cp;
int len;
if (a1st<=1)
return;
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),np->rcline,np->subscribechar,
np->rcline + np->numoffset) FLUSH;
}
#endif
for (s = np->rcline + np->numoffset; isspace(*s); s++) ;
while (*s && (num = atol(s)) <= a1st) {
while (isdigit(*s)) s++;
while (*s && !isdigit(*s)) s++;
lastnum = num;
}
len = strlen(s);
if (len && s[-1] == '-') { /* landed in a range? */
if (lastnum != 1) {
if (3+len <= (int)strlen(np->rcline+np->numoffset))
mbuf = np->rcline;
else {
mbuf = safemalloc((MEM_SIZE)(np->numoffset+3+len+1));
strcpy(mbuf, np->rcline);
}
cp = mbuf + np->numoffset;
*cp++ = ' '; *cp++ = '1'; *cp++ = '-';
safecpy(cp, s, len+1);
if (np->rcline != mbuf) {
free(np->rcline);
np->rcline = mbuf;
}
np->rc->flags |= RF_RCCHANGED;
}
}
else {
/* s now points to what should follow the first range */
char numbuf[32];
int nlen;
sprintf(numbuf," 1-%ld",(long)(a1st - (lastnum != a1st)));
nlen = strlen(numbuf) + (len != 0);
if (s - np->rcline >= np->numoffset + nlen)
mbuf = np->rcline;
else {
mbuf = safemalloc((MEM_SIZE)(np->numoffset+nlen+len+1));
strcpy(mbuf,np->rcline);
}
cp = mbuf + np->numoffset;
strcpy(cp, numbuf);
cp += nlen;
if (len) {
cp[-1] = ',';
if (cp != s)
safecpy(cp,s,len+1);
}
if (!checkflag && np->rcline == mbuf)
np->rcline = saferealloc(np->rcline, (MEM_SIZE)(cp-mbuf+len+1));
else {
if (!checkflag)
free(np->rcline);
np->rcline = mbuf;
}
np->rc->flags |= RF_RCCHANGED;
}
#ifdef DEBUG
if (debug & DEB_XREF_MARKER) {
printf("%s%c%s\n",np->rcline,np->subscribechar,
np->rcline + np->numoffset) FLUSH;
}
#endif
}
/* Returns TRUE if article is marked as read or does not exist */
/* could use a better name */
bool
was_read_group(dp,artnum,ngnam)
DATASRC* dp;
ART_NUM artnum;
char* ngnam;
{
register NGDATA* np;
register char* s;
register char* t;
register char* maxt = NULL;
ART_NUM min = 0, max = -1, lastnum = 0;
if (!artnum)
return TRUE;
np = find_ng(ngnam);
if (np == NULL) /* not found in newsrc? */
return TRUE;
if (!np->numoffset) /* no numbers on line */
return FALSE;
#if 0
/* consider this code later */
if (!np->abs1st) {
/* Trim down the list due to expires if we haven't done so yet. */
set_toread(np, ST_LAX);
}
#endif
if (np->toread == TR_BOGUS)
return TRUE;
if (artnum > np->ngmax) {
return FALSE; /* probably doesn't exist, however */
}
s = np->rcline + np->numoffset;
while (*s == ' ') s++; /* skip spaces */
t = s;
while (isdigit(*s) && artnum >= (min = atol(s))) {
/* while it might have been read */
for (t = s; isdigit(*t); t++) ; /* skip number */
if (*t == '-') { /* is it a range? */
t++; /* skip to next number */
if (artnum <= (max = atol(t)))
return TRUE; /* it is in range => already read */
lastnum = max; /* remember it */
maxt = t; /* remember position in case we */
/* want to overwrite the max */
while (isdigit(*t)) t++; /* skip second number */
}
else {
if (artnum == min) /* explicitly a read article? */
return TRUE;
lastnum = min; /* remember what the number was */
maxt = NULL; /* last one was not a range */
}
while (*t && !isdigit(*t)) t++; /* skip comma and any spaces */
s = t;
}
/* we have not read it, so return FALSE */
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1