contrib/newshound/newshound.c

/* [<][>]
[^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. usage
  2. bangrps
  3. collect
  4. check
  5. fetch
  6. update
  7. stats
  8. 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;
     }
  }

/* [<][>][^][v][top][bottom][index][help] */