Logo Search packages:      
Sourcecode: leafnode version File versions

applyfilter.c

/*
 * apply filter file to all files in a newsgroup
 *
 * Written by Cornelius Krasel <krasel@wpxx02.toxi.uni-wuerzburg.de>.
 * Copyright 1999.
 *
 * Modified and copyright of the modifications 2002 by Matthias Andree
 * <matthias.andree@gmx.de> and Ralf Wildenhues <ralf.wildenhues@gmx.de>
 *
 * See file COPYING for restrictions on the use of this software.
 */

#include "leafnode.h"
#include "ln_log.h"

#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include "system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>

#define MAXHEADERSIZE 2047

int debug = 0;
int verbose;

/* read from file f into malloced buffer *bufp of size *size
 * up to delim or EOF.  Buffer is adjusted to fit input.
 * return pointer to match or end of file, NULL in case of error
 */
static /*@null@*/ /*@dependent@*/ char *
readtodelim(FILE *f, const char *name, /*@unique@*/ /*@observer@*/ const char *delim,
    char **bufp, size_t *size)
{
    size_t dlen = strlen(delim) - 1;
    size_t nread, res;
    char *k;

    nread = 0;
    if (*size < 1 || *bufp == NULL)
      *bufp = critmalloc((*size = MAXHEADERSIZE), "readtodelim");

    /*@+loopexec@*/
    for (;;) {
      res = fread(*bufp + nread, 1, *size - nread - 1, f);
      (*bufp)[nread + res] = '\0';
      /* skip as much as possible */
      k = strstr(nread > dlen ? *bufp + nread - dlen : *bufp, delim);
      if (ferror(f)) {
          printf("error reading %s\n", name);
          clearerr(f);
          return k;
      }
      nread += res;
      if (feof(f)) {
          clearerr(f);
          return k != NULL ? k : *bufp + nread;
      }
      if (k != NULL) {
          return k;
      }
      /* must read more */
      *bufp = critrealloc(*bufp, (*size)*=2, "readtodelim");
    }
    /*@=loopexec@*/
}

/* read article headers, cut off body
 * return 0 for success, -1 for error, -2 for article without body
 */
static int
readheaders(FILE *f, /*@unique@*/ const char *name, char **bufp, size_t *size)
{
    char *k = readtodelim(f, name, "\n\n", bufp, size);
    if (k != NULL) {
      if (*k == '\0')
          return -2;
      else {
          k[1] = '\0';
          return 0;
      }
    } else {
      return -1;
    }
}

int
main(int argc, char *argv[])
{
    const char c[] = "-\\|/";
    int i, score, option, deleted, kept;
    unsigned long n;
    char *msgid;
    char *l;
    size_t lsize;
    const char *msgidpath = "";
    FILE *f;
    DIR *d;
    struct dirent *de;
    struct stat st;
    struct utimbuf u;
    struct newsgroup *g;

    myopenlog("applyfilter");

    if (!initvars(argv[0]))
      exit(1);

    while ((option = getopt(argc, argv, "v")) != -1) {
      if (option == 'v')
          verbose++;
      else {
          printf("Usage: %s newsgroup\n", argv[0]);
          exit(1);
      }
    }

    if (argv[optind] == NULL) {
      printf("Usage: %s newsgroup\n", argv[0]);
      exit(1);
    }

    if (!readconfig(0)) {
      printf("Reading configuration failed, exiting "
             "(see syslog for more information).\n");
      exit(2);
    }
    freeservers();

    if (filterfile)
      readfilter(filterfile);
    else {
      printf("Nothing to filter -- no filterfile found.\n");
      freeconfig();
      exit(0);
    }

    if (try_lock(timeout_lock)) {
      printf("Cannot obtain lock file, aborting.\n");
      exit(1);
    }

    readactive();
    if (!active) {
      printf("Problem reading active file.\n");
      freeconfig();
      exit(1);
    }

    g = findgroup(argv[optind]);
    if (!g) {
      printf("Newsgroups %s not found in active file.\n", argv[optind]);
      unlink(lockfile);
      exit(1);
    }

    /* to automatically rise the low water mark, we reset g->first to
     * ULONG_MAX. */
    g->first = ULONG_MAX;
    /* We used to do g->last = 0; but that can severely confuse news
     * readers, we don't ever want to decrease the high water mark. */
    if (!chdirgroup(g->name, FALSE)) {
      printf("No such newsgroup: %s\n", g->name);
      unlink(lockfile);
      exit(1);
    }
    if (!(d = opendir("."))) {
      printf("Unable to open directory for newsgroup %s\n", g->name);
      unlink(lockfile);
      exit(1);
    }

    i = 0;
    deleted = 0;
    kept = 0;
    lsize = MAXHEADERSIZE + 1;
    l = critmalloc(lsize, "Space for article");
    while ((de = readdir(d)) != NULL) {
      if (!isdigit((unsigned char)de->d_name[0])) {
          /* no need to stat file */
          continue;
      }
      switch (verbose) {
      case 1:{
            printf("%c\b", c[i % 4]);
            fflush(stdout);
            i++;
            break;
          }
      case 2:{
            printf("%s\n", de->d_name);
          }
      }
      if ((f = fopen(de->d_name, "r")) != NULL
            && fstat(fileno(f), &st) == 0
            && S_ISREG(st.st_mode))
      {
          switch (readheaders(f, de->d_name, &l, &lsize)) {
            case 0:
                score = dofilter(l);
                break;
            case -1:
                score = -1; /* FIXME: how to handle read error? */
                break;
            case -2:
                /* bodyless article: filter in delaybody mode,
                   otherwise delete */
                if (delaybody)
                  score = dofilter(l);
                else
                  score = -1;
                break;
            default:
                /* this branch will never be executed, but
                 * eliminates a compiler warning */
                score = 0;
                break;
          }

          if (score) {
            msgid = fgetheader(f, "Message-ID:");
            fclose(f);
            unlink(de->d_name);
            /* delete stuff in message.id directory as well */
            if (msgid) {
                msgidpath = lookup(msgid);
                if ((stat(msgidpath, &st) == 0) /* RATS: ignore */
                            && (st.st_nlink < 2)) {
                  if (unlink(msgidpath) == 0)
                      deleted++;
                }
                free(msgid);
            }
            if (verbose)
                printf("%s %s deleted\n", de->d_name, msgidpath);
          } else {
            fclose(f);
            n = strtoul(de->d_name, NULL, 10);
            if (n) {
                if (n < g->first)
                  g->first = n;
                if (n > g->last)
                  g->last = n;
            }
            u.actime = st.st_atime;
            u.modtime = st.st_mtime;
            utime(de->d_name, &u);
            kept++;
          }
      } else {
          if (f) {
            ln_log(LNLOG_SERR, LNLOG_CARTICLE, 
                  "could not stat %s or not a regular file\n",
                  de->d_name);
            (void)fclose(f);
          } else {
            ln_log(LNLOG_SERR, LNLOG_CARTICLE, "could not open %s\n",
                  de->d_name);
          }
      }
    }
    closedir(d);
    free(l);
    if (g->first > g->last) {
      /* group is empty */
      g->first = g->last + 1;
    }
    if (writeactive()) ln_log(LNLOG_SERR, LNLOG_CTOP, "Error writing groupinfo.");
    freeactive(active);
    unlink(lockfile);
    printf("%d article%s deleted, %d kept.\n", deleted, PLURAL(deleted), kept);

    if (verbose)
      printf("Updating .overview file\n");
    getxover();
    freexover();
    freeconfig();
    exit(0);
}

Generated by  Doxygen 1.6.0   Back to index