/* addng.c
*/
/* This software is copyrighted as detailed in the LICENSE file. */
#include "EXTERN.h"
#include "common.h"
#include "list.h"
#include "trn.h"
#include "hash.h"
#include "ngdata.h"
#include "nntpclient.h"
#include "datasrc.h"
#include "nntp.h"
#include "last.h"
#include "util.h"
#include "util2.h"
#include "intrp.h"
#include "only.h"
#include "term.h"
#include "rcstuff.h"
#include "final.h"
#include "autosub.h"
#include "rt-select.h"
#include "INTERN.h"
#include "addng.h"
#include "addng.ih"
static int
addng_cmp(key, keylen, data)
char* key;
int keylen;
HASHDATUM data;
{
return bcmp(key, ((ADDGROUP*)data.dat_ptr)->name, keylen);
}
static int
build_addgroup_list(keylen, data, extra)
int keylen;
HASHDATUM* data;
int extra;
{
ADDGROUP* node = (ADDGROUP*)data->dat_ptr;
node->num = addgroup_cnt++;
node->next = NULL;
node->prev = last_addgroup;
if (last_addgroup)
last_addgroup->next = node;
else
first_addgroup = node;
last_addgroup = node;
return 0;
}
void
addng_init()
{
;
}
bool
find_new_groups()
{
NEWSRC* rp;
NG_NUM oldcnt = newsgroup_cnt; /* remember # newsgroups */
/* Skip this check if the -q flag was given. */
if (quickstart)
return FALSE;
for (rp = multirc->first; rp; rp = rp->next) {
if (ALLBITS(rp->flags, RF_ADD_NEWGROUPS | RF_ACTIVE)) {
#ifdef SUPPORT_NNTP
if (rp->datasrc->flags & DF_REMOTE)
new_nntp_groups(rp->datasrc);
else
#endif
new_local_groups(rp->datasrc);
}
}
addnewbydefault = 0;
process_list(GNG_RELOC);
return oldcnt != newsgroup_cnt;
}
static void
process_list(flag)
int flag;
{
ADDGROUP* node;
ADDGROUP* prevnode;
if (!flag) {
sprintf(cmd_buf,"\nUnsubscribed but mentioned in your current newsrc%s:\n",
multirc->first->next? "s" : nullstr);
print_lines(cmd_buf, STANDOUT);
}
if ((node = first_addgroup) != NULL && flag && UseAddSelector)
addgroup_selector(flag);
while (node) {
if (!flag) {
sprintf(cmd_buf, "%s\n", node->name);
print_lines(cmd_buf, NOMARKING);
}
else if (!UseAddSelector)
get_ng(node->name,flag); /* add newsgroup -- maybe */
prevnode = node;
node = node->next;
free((char*)prevnode);
}
first_addgroup = NULL;
last_addgroup = NULL;
addgroup_cnt = 0;
}
#ifdef SUPPORT_NNTP
static void
new_nntp_groups(dp)
DATASRC* dp;
{
register char* s;
int len;
time_t server_time;
NGDATA* np;
bool foundSomething = FALSE;
long high, low;
HASHTABLE* newngs;
set_datasrc(dp);
server_time = nntp_time();
if (server_time == -2)
return; /*$$*/
if (nntp_newgroups(dp->lastnewgrp) < 1) { /*$$*/
printf("Can't get new groups from server:\n%s\n", ser_line);
return;
}
newngs = hashcreate(33, addng_cmp);
while (1) {
high = 0, low = 1;
if (nntp_gets(ser_line, sizeof ser_line) < 0)
break;
#ifdef DEBUG
if (debug & DEB_NNTP)
printf("<%s\n", ser_line) FLUSH;
#endif
if (nntp_at_list_end(ser_line))
break;
foundSomething = TRUE;
if ((s = index(ser_line, ' ')) != NULL)
len = s - ser_line;
else
len = strlen(ser_line);
if (dp->act_sf.fp) {
if (find_actgrp(dp, buf, ser_line, len, (ART_NUM)0)) {
if (!s)
s = buf + len + 1;
}
else {
char ch = 'y';
if (s)
sscanf(s+1, "%ld %ld %c", &high, &low, &ch);
else
s = ser_line + len;
sprintf(s, " %010ld %05ld %c\n", high, low, ch);
(void) srcfile_append(&dp->act_sf, ser_line, len);
}
}
if (s) {
*s++ = '\0';
while (isdigit(*s) || isspace(*s)) s++;
if (*s == 'x' || *s == '=')
continue;
}
if ((np = find_ng(ser_line)) != NULL && np->toread > TR_UNSUB)
continue;
add_to_hash(newngs, ser_line, high-low, auto_subscribe(ser_line));
}
if (foundSomething) {
hashwalk(newngs, build_addgroup_list, 0);
srcfile_end_append(&dp->act_sf, dp->extra_name);
dp->lastnewgrp = server_time;
}
hashdestroy(newngs);
}
#endif
static void
new_local_groups(dp)
DATASRC* dp;
{
register char* s;
time_t lastone;
NGDATA* np;
char tmpbuf[LBUFLEN];
long high, low;
char ch;
HASHTABLE* newngs;
datasrc = dp;
/* did active.times file grow? */
stat(dp->extra_name,&filestat);
if (filestat.st_size == dp->act_sf.recent_cnt)
return;
tmpfp = fopen(dp->extra_name,"r");
if (tmpfp == NULL) {
printf(cantopen,dp->extra_name) FLUSH;
termdown(1);
return;
}
lastone = time((time_t*)NULL) - 24L * 60 * 60 - 1;
newngs = hashcreate(33, addng_cmp);
while (fgets(buf,LBUFLEN,tmpfp) != NULL) {
if ((s = index(buf, ' ')) == NULL
|| (lastone = atol(s+1)) < dp->lastnewgrp)
continue;
*s = '\0';
if (!find_actgrp(datasrc, tmpbuf, buf, s - buf, (ART_NUM)0))
continue;
high = 0, low = 1, ch = 'y';
sscanf(tmpbuf + (s-buf) + 1, "%ld %ld %c", &high, &low, &ch);
if (ch == 'x' || ch == '=')
continue;
if ((np = find_ng(buf)) != NULL)
continue;
add_to_hash(newngs, buf, high-low, auto_subscribe(buf));
}
fclose(tmpfp);
hashwalk(newngs, build_addgroup_list, 0);
hashdestroy(newngs);
dp->lastnewgrp = lastone+1;
dp->act_sf.recent_cnt = filestat.st_size;
}
static void
add_to_hash(ng, name, toread, ch)
HASHTABLE* ng;
char* name;
int toread;
char_int ch;
{
HASHDATUM data;
ADDGROUP* node;
unsigned namelen = strlen(name);
data.dat_len = namelen + sizeof (ADDGROUP);
node = (ADDGROUP*)safemalloc(data.dat_len);
data.dat_ptr = (char *)node;
switch (ch) {
case ':':
node->flags = AGF_SEL;
break;
case '!':
node->flags = AGF_DEL;
break;
default:
node->flags = 0;
break;
}
node->toread = (toread < 0)? 0 : toread;
strcpy(node->name, name);
node->datasrc = datasrc;
node->next = node->prev = NULL;
hashstore(ng, name, namelen, data);
}
static void
add_to_list(name, toread, ch)
char* name;
int toread;
char_int ch;
{
ADDGROUP* node = first_addgroup;
while (node) {
if (strEQ(node->name, name))
return;
node = node->next;
}
node = (ADDGROUP*)safemalloc(strlen(name) + sizeof (ADDGROUP));
switch (ch) {
case ':':
node->flags = AGF_SEL;
break;
case '!':
node->flags = AGF_DEL;
break;
default:
node->flags = 0;
break;
}
node->toread = (toread < 0)? 0 : toread;
node->num = addgroup_cnt++;
strcpy(node->name, name);
node->datasrc = datasrc;
node->next = NULL;
node->prev = last_addgroup;
if (last_addgroup)
last_addgroup->next = node;
else
first_addgroup = node;
last_addgroup = node;
}
bool
scanactive(add_matching)
bool_int add_matching;
{
DATASRC* dp;
NG_NUM oldcnt = newsgroup_cnt; /* remember # of newsgroups */
if (!add_matching)
print_lines("Completely unsubscribed newsgroups:\n", STANDOUT);
for (dp = datasrc_first(); dp && dp->name; dp = datasrc_next(dp)) {
if (!(dp->flags & DF_OPEN))
continue;
set_datasrc(dp);
if (dp->act_sf.fp)
hashwalk(dp->act_sf.hp, list_groups, add_matching);
#ifdef SUPPORT_NNTP
else {
if (maxngtodo != 1)
strcpy(buf, "*");
else {
if (ngtodo[0][0] == '^')
sprintf(buf,"%s*", &ngtodo[0][1]);
else
sprintf(buf,"*%s*", ngtodo[0]);
if (buf[strlen(buf)-2] == '$')
buf[strlen(buf)-2] = '\0';
}
if (nntp_list("active", buf, strlen(buf)) == 1) {
while (!nntp_at_list_end(ser_line)) {
scanline(ser_line,add_matching);
if (nntp_gets(ser_line, sizeof ser_line) < 0)
break; /*$$*/
}
}
}
#endif
}
process_list(add_matching);
if (in_ng) /*$$*/
set_datasrc(ngptr->rc->datasrc);
return oldcnt != newsgroup_cnt;
}
static int
list_groups(keylen, data, add_matching)
int keylen;
HASHDATUM* data;
int add_matching;
{
char* bp = ((LISTNODE*)data->dat_ptr)->data + data->dat_len;
int linelen = index(bp, '\n') - bp + 1;
(void) bcopy(bp, buf, linelen);
buf[linelen] = '\0';
scanline(buf,add_matching);
return 0;
}
static void
scanline(actline, add_matching)
char* actline;
bool_int add_matching;
{
register char* s;
NGDATA* np;
long high, low;
char ch;
if ((s = index(actline,' ')) == NULL)
return;
*s++ = '\0'; /* this buffer is expendable */
high = 0, low = 1, ch = 'y';
sscanf(s, "%ld %ld %c", &high, &low, &ch);
if (ch == 'x' || strnEQ(actline,"to.",3))
return;
if (!inlist(actline))
return;
if ((np = find_ng(actline)) != NULL && np->toread > TR_UNSUB)
return;
if (add_matching || np) {
/* it's not in a newsrc */
add_to_list(actline, high-low, 0);
}
else {
strcat(actline,"\n");
print_lines(actline, NOMARKING);
}
}
static int
agorder_number(app1, app2)
register ADDGROUP** app1;
register ADDGROUP** app2;
{
ART_NUM eq = (*app1)->num - (*app2)->num;
return eq > 0? sel_direction : -sel_direction;
}
static int
agorder_groupname(app1, app2)
register ADDGROUP** app1;
register ADDGROUP** app2;
{
return strcaseCMP((*app1)->name, (*app2)->name) * sel_direction;
}
static int
agorder_count(app1, app2)
register ADDGROUP** app1;
register ADDGROUP** app2;
{
long eq = (*app1)->toread - (*app2)->toread;
if (eq)
return eq > 0? sel_direction : -sel_direction;
return agorder_groupname(app1, app2);
}
/* Sort the newsgroups into the chosen order.
*/
void
sort_addgroups()
{
register ADDGROUP* ap;
register int i;
ADDGROUP** lp;
ADDGROUP** ag_list;
int (*sort_procedure)();
switch (sel_sort) {
case SS_NATURAL:
default:
sort_procedure = agorder_number;
break;
case SS_STRING:
sort_procedure = agorder_groupname;
break;
case SS_COUNT:
sort_procedure = agorder_count;
break;
}
ag_list = (ADDGROUP**)safemalloc(addgroup_cnt * sizeof *ag_list);
for (lp = ag_list, ap = first_addgroup; ap; ap = ap->next)
*lp++ = ap;
assert(lp - ag_list == addgroup_cnt);
qsort(ag_list, addgroup_cnt, sizeof *ag_list, sort_procedure);
first_addgroup = ap = ag_list[0];
ap->prev = NULL;
for (i = addgroup_cnt, lp = ag_list; --i; lp++) {
lp[0]->next = lp[1];
lp[1]->prev = lp[0];
}
last_addgroup = lp[0];
last_addgroup->next = NULL;
free((char*)ag_list);
}
syntax highlighted by Code2HTML, v. 0.9.1