contrib/newshound/newshound.c
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following functions.
- usage
- bangrps
- collect
- check
- fetch
- update
- stats
- main
/************************************************************************/
/* Version 2.0 */
/* Newshound is to be used with nntpcached. This program reads the */
/* cache.history file creates a list of news groups to access. Then */
/* connects to the news port to download the popular news groups. */
/* This is a major rewrite. I keep messy notes so I don't have any */
/* development history. Needless to say since newshound is becoming */
/* popular I'll keep better details. Thanks to all those who have send */
/* me ideas etc. */
/* */
/* Newhound written by andre@weblink.solutions.net.au */
/* Nntpcached written by proff@suburbia.net & puke@suburbia.net */
/* Socket code written by Vic Metcalfe vic@brutus.tlug.org */
/************************************************************************/
#include "conf.h"
char sgroup[128];
int group=0, head=0, mode;
int high, low, last, status;
void usage(char *prog)
/* [<][>][^][v][top][bottom][index][help] */
{
printf("Usage: %s [options...]\n", prog);
printf("-c Collect all newsgroups in %s file.\n", history);
printf("-f Fetch newsgroup messages from the %s file.\n", hound);
printf("-h Just grab article headers.\n");
printf("-A Automatic mode. Collects news every %d minutes\n", mins);
printf("-S Setting details for %s.\n",prog);
printf("-b Remove all newsgroups with ban strings in them.\n");
printf("-d nn Debug Mode level. 1 2 or 3\n");
printf("-u [l][m][h] Update %s index setting.\n", hound);
printf("-n [newsgroup] Just update this newsgroup's article index.\n");
printf("-l msg Low mark on number of articles read.\n");
printf("-g nn Download top nn newsgroups from hound.list. 0=all.\n");
printf("-s news.server.com News Server you access. Default %s\n",server);
printf("-p portnumber News Port nntpcached is on. Default %s\n",port);
printf("\nSend bugs to andre@weblink.solutions.net.au\n");
}
void bangrps()
/* [<][>][^][v][top][bottom][index][help] */
{
FILE *cp, *tp;
char fs[128];
int i, bangroup;
cp=fopen(hf, "r");
unlink(wf);
tp=fopen(wf, "w");
if (debug>=1) printf("Removing banned newsgroups.\n");
while((fgets(fs, 128, cp)) != NULL)
{
bangroup=i=0;
while(strcmp(banstr[i], "")!=0)
{
if (strstr(fs, banstr[i])!=NULL) bangroup=1;
++i;
}
if (!bangroup)
fprintf(tp, "%s", fs);
else
if (debug>=3) printf("%s has been banned.\n", fs);
}
fclose(tp);
fclose(cp);
if (debug>=3) printf("Renaming %s to %s\n", hf, bf);
rename(hf, bf);
if (debug>=3) printf("Renaming %s to %s\n", wf, hf);
rename(wf, hf);
}
void collect()
/* [<][>][^][v][top][bottom][index][help] */
{
FILE *cp, *tp;
char fs[128], tmp[128], bak[128], *fstmp;
cp=fopen(cf, "r");
if (cp==NULL)
{
fprintf(stderr, "Cannot open %s\n", cf);
exit(1);
}
unlink(rf);
tp=fopen(rf, "w");
if (tp==NULL)
{
printf("Cannot open %s", rf);
exit(1);
}
if (debug>=1) printf("Collecting newsgroups.\n");
while ((fgets(fs, 128, cp)) != NULL)
{
if ((strstr(fs, "/") != NULL) && (isalpha(fs[0])!='\0'))
{
strtok(fs, "/");
sprintf(tmp, "%s/", fs);
while ((fstmp = (strtok(NULL, "/"))) != NULL)
{
strcpy(bak, tmp); /* Lazy way to */
sprintf(tmp, "%s%s.", bak, fstmp);
}
strcpy(tmp, bak); /* drop message number */
tmp[strlen(tmp)-1]=0;
fprintf(tp, "%s\n", tmp);
if (debug>=4) printf("Wrote %s newsgroup.\n", tmp);
}
}
fclose(tp);
fclose(cp);
}
int check(char *server, char *group, int article)
/* [<][>][^][v][top][bottom][index][help] */
{ /* Check to see if article is cached */
FILE *cp, *cp_x, *cp_h;
int result;
char tmp[128], xtmp[128], htmp[128], bak[128], *fstmp;
fstmp = strcpy(bak, group);
while ((fstmp = strchr(fstmp, '.')) != NULL)
{
*fstmp++ = '/';
}
sprintf(tmp, "%s/%s/%s/%d", cachedir, server, bak, article);
cp = fopen(tmp, "r");
sprintf(xtmp, "%s/%s/%s/%d_xover", cachedir, server, bak, article);
cp_x = fopen(xtmp, "r");
sprintf(htmp, "%s/%s/%s/%d_head", cachedir, server, bak, article);
cp_h = fopen(htmp, "r");
if (
((cp == NULL) && (cp_x == NULL)) ||
((cp_h == NULL) && (head))
)
{
result=1;
if (debug>=3) /* This routine is called from a loop so is */
{
if (head) /* automatically a level 3 debug. */
printf("NH :> %s is NOT cached\n", htmp);
else
printf("NH :> %s or %s is NOT cached\n", tmp, xtmp);
}
}
else
{
result=0;
if (debug>=3)
{
if (head)
printf("NH :> %s is cached\n", htmp);
else
printf("NH :> %s or %s is cached\n", tmp, xtmp);
}
}
if (cp) fclose(cp);
if (cp_h) fclose(cp_h);
if (cp_x) fclose(cp_x);
return result;
}
int fetch()
/* [<][>][^][v][top][bottom][index][help] */
{
FILE *fp, *tp;
char fs[1024], tmp[128], srv[128], grp[128];
int sock, loop, n;
int count=0;
char buffer[1024];
char input[1024];
fp = fopen(hf, "r");
if (fp == NULL)
{
fprintf(stderr,"Hound list not found.\n");
return (-1);
}
unlink(wf);
tp = fopen(wf, "w");
if (tp == NULL)
{
fprintf(stderr,"Can't create work file.\n");
return (-1);
}
sock = make_connection(port, SOCK_STREAM, server);
if (sock == -1)
{
fprintf(stderr,"make_connection failed.\n");
return (-1);
}
if (debug>=1) printf("Fetching news articles.\n");
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=2) printf("NNTP:# %s\n",buffer);
while ((fgets(fs,128,fp))!=NULL)
{
if (group && count++==group) {
do {
fputs(fs, tp);
} while(fgets(fs, 128, fp)!=NULL);
break;
}
n=sscanf(fs, "%s %d", tmp, &last);
if (n==1)
{ fs[strlen(fs)-1]=0; last=0; }
strcpy(srv, strtok(tmp, "/"));
strcpy(grp, strtok(NULL, "/"));
sprintf(input, "group %s\n", grp);
if (debug>=3) printf("NH :> %s", input);
sock_puts(sock,input);
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=3) printf("NNTP:< %s\n",buffer);
sscanf(buffer, "%d %*d %d %d", &status, &low, &high);
if (last>low) low=last+1;
if (status!=411) /* 411 Bad newsgroup. */
{
if (debug>=2) printf("NH :> %d article to cache from %s\n",
((high+1)-low), grp);
for(loop=low; loop<=high; loop++)
{
if (head)
sprintf(input, "head %d\n", loop);
else
sprintf(input, "article %d\n", loop);
if (debug>=3)
{
printf("NH :> %s", input);
printf("NH :> %d left to cache from %s\n", ((high+1)-loop), grp);
}
if (check(srv, grp, loop))
{
sock_puts(sock,input);
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=3) printf("NNTP:< %s\n",buffer);
status=atoi((char *)strtok(buffer, " "));
if (status!=423) /* 423 Bad article */
{
while(strcmp(buffer, ".")!=0)
{
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=4) printf("NNTP:< %s\n",buffer);
}
}
}
}
sprintf(tmp, "%d", high);
fprintf(tp, "%s/%s %s\n", srv, grp, tmp);
}
}
fclose(tp);
fclose(fp);
if (debug>=3) printf("Renaming %s to %s\n", hf, bf);
rename(hf, bf);
if (debug>=3) printf("Renaming %s to %s\n", wf, hf);
rename(wf, hf);
close(sock);
return (0);
}
int update(char mode[2], char *sgroup)
/* [<][>][^][v][top][bottom][index][help] */
{
FILE *fp, *tp;
char fs[128], tmp[128], sgrp[128], srv[128], grp[128], val[10];
int sock;
char buffer[1024];
char input[1024];
fp = fopen(hf, "r");
if (fp == NULL)
{
fprintf(stderr,"Hound list not found.\n");
return -1;
}
unlink(wf);
tp=fopen(wf, "w");
if (tp==NULL)
{
fprintf(stderr,"Can't create work file.\n");
return -1;
}
sock=make_connection(port, SOCK_STREAM, server);
if (sock==-1)
{
fprintf(stderr,"make_connection failed.\n");
return -1;
}
if (debug>=1) printf("Updating newsgroup pointers.\n");
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=2) printf("NNTP:# %s\n",buffer);
while ((fgets(fs,128,fp))!=NULL)
{
strcpy(sgrp, fs);
if (strchr(fs, ' ')!=NULL)
strcpy(val, strtok(fs, " "));
else
fs[strlen(fs)-1]=0;
strcpy(srv, strtok(fs, "/"));
strcpy(grp, strtok(NULL, "/"));
if ((strcmp(sgroup, grp)==0) || (strcmp(sgroup, "-all-")==0))
{
sprintf(input, "group %s\n", grp);
if (debug>=2) printf("NH :> %s", input);
sock_puts(sock,input);
sock_gets(sock,buffer,sizeof(buffer));
if (debug>=3) printf("NNTP:< %s\n",buffer);
sscanf(buffer, "%d %*d %d %d", &status, &low, &high);
if (strcmp(mode, "l")==0) sprintf(tmp, "%d", low);
if (strcmp(mode, "m")==0) sprintf(tmp, "%d",
(low+((high-low)/2)));
if (strcmp(mode, "h")==0) sprintf(tmp, "%d", high);
if (debug>=3) printf("NH :> setting newsgroup pointer to %s\n",
tmp);
}
if ((strcmp(sgroup, grp)==0) || (strcmp(sgroup, "-all-")==0))
fprintf(tp, "%s/%s %s\n", srv, grp, tmp);
else
fprintf(tp, "%s", sgrp);
}
fclose(tp);
fclose(fp);
if (debug>=3) printf("Renaming %s to %s\n", hf, bf);
rename(hf, bf);
if (debug>=3) printf("Renaming %s to %s\n", wf, hf);
rename(wf, hf);
close(sock);
return (0);
}
int stats(char *prog)
/* [<][>][^][v][top][bottom][index][help] */
{
FILE *fp;
char fs[128];
int count=0;
printf("Setting details.\n\n");
printf("Program name :- %s\n", prog);
printf("Version number :- %s\n", VERSION);
printf("News server set to :- %s\n", server);
printf("News port set to :- %s\n", port);
printf("Cache history file :- %s\n", history);
printf("Hound list file :- %s\n", hound);
printf("Auto Mode running :- %d minute(s)\n", mins);
fp = fopen(hf, "r");
if (fp == NULL)
{
fprintf(stderr,"File :- %s not found.\n", hf);
return -1;
}
while ((fgets(fs,128,fp))!=NULL) ++count;
fclose(fp);
printf("Newsgroups sorted :- %d\n", count);
count=0;
printf("Newsgroup banning is %s.\n", ban?"on":"off");
if (ban)
{
printf("These words are in the ban list.\n");
while(strcmp(banstr[count], "") != 0)
printf("%s\n", banstr[count++]);
}
printf("Send bugs to andre@weblink.solutions.net.au\n");
return 1;
}
int main(int argc, char **argv)
/* [<][>][^][v][top][bottom][index][help] */
{
int ch, single=0;
char app[2];
extern int optind;
extern char *optarg;
getconf();
sprintf(cf, "%.128s/%.32s", cachedir, history);
sprintf(hf, "%.128s/%.32s", cachedir, hound);
sprintf(bf, "%.128s/%.32s.bak", cachedir, hound);
/* These temp file are built within the cachedir to avoid */
/* problems with rename()ing between partition. */
sprintf(rf, "%.128s/hound.rf", cachedir);
sprintf(sf, "%.128s/hound.sf", cachedir);
sprintf(wf, "%.128s/hound.wf", cachedir);
while((ch = getopt(argc, argv, "g:l:s:p:u:n:F:cbd:fhSA?")) != EOF)
switch((char)ch)
{
case 'g':
group=atoi(optarg);
break;
case 'l':
lowmark=atoi(optarg);
break;
case 'f':
mode=1;
break;
case 'h':
head=1;
break;
case 'c':
mode=2;
break;
case 'b':
ban=1;
break;
case 's':
strcpy(server, optarg);
break;
case 'p':
strcpy(port, optarg);
break;
case 'u':
strcpy(app, optarg);
mode=3;
break;
case 'n':
strcpy(sgroup, optarg);
single=1;
break;
case 'd': /* 1=report function, 2=misc jobs, 3=while loops */
debug=atoi(optarg); /* 4=blabber mouth */
break;
case 'S':
mode=4;
break;
case 'A':
mode=5;
break;
case '?':
usage(argv[0]);
exit(1);
break;
}
switch(mode)
{
case 1:
fetch();
break;
case 2:
collect();
sortit();
if (ban) bangrps();
break;
case 3:
if (single)
update(app, sgroup);
else
update(app, "-all-");
break;
case 4:
stats(argv[0]);
break;
case 5:
for(;;)
{
fetch();
if (debug>=1) printf("NH :> Sleeping for %d minutes.\n", mins);
sleep(mins*60);
}
break;
default:
printf("%s Version %s\n", argv[0], VERSION);
printf("You need at least one of these options [-c] [-f] [-u] [-A].\n");
printf("Do :- '%s -?' for help.\n", argv[0]);
printf("Send bugs to andre@weblink.solutions.net.au\n");
break;
}
}