/* * Copyright (c) 1998,1999,2000 Kazushi (Jam) Marukawa * All rights of my changes are reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice in the documentation and/or other materials provided with * the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef SOCKS #include #endif #include #ifdef BSD #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "leafnode.h" static void getactive(void) { const char* s; nntpactive(); s = getactivefname(servers->servername); unlink(s); close(open(s, O_WRONLY|O_CREAT, 0664)); writeactive(); /* write groupinfo file */ } static void fixgroup(struct newsgroup* g) { DIR* d; struct dirent* de; char* p; unsigned long art; unsigned long xfirst, xlast; /* eliminate empty groups */ if (!chdirgroup(g, 0)) return; /* find article range, without locking problems */ d = opendir("."); if (!d) { mysyslog(LOG_ERR, "opendir: %s", strerror(errno)); return; } xfirst = ULONG_MAX; xlast = 0; while ((de=readdir(d))) { art = strtoul(de->d_name, &p, 10); if (p && !*p) { if (art < xfirst) xfirst = art; if (art > xlast) xlast = art; } } closedir(d); if (xlast < xfirst) return; if (xfirst > g->first || xlast > g->last) { unsigned long oldxfirst = g->first; unsigned long oldxlast = g->last; if (xfirst > g->first) g->first = xfirst; if (xlast > g->last) g->last = xlast; mysyslog(LOG_INFO, "fixed %s: %lu, %lu -> %lu, %lu", g->name, oldxfirst, oldxlast, g->first, g->last); if (verbose) { fprintf(stderr, "fixed %s: %lu, %lu -> %lu, %lu\n", g->name, oldxfirst, oldxlast, g->first, g->last); } } } static void fixgroupinfo(struct newsgroup* g) { if (g) { fixgroupinfo(g->right); fixgroup(g); fixgroupinfo(g->left); } } static void usage(void) { fprintf(stderr, "Usage: leaftool [-hviu] [-rl ...]\n" " -h: show this usage\n" " -v: more verbose (may be repeated)\n" " -i: collect news group information via NNTP\n" " -u: correct actives by checking all articles\n" " -r: remove all articles containing message-id\n" " -l: make a list of articles containing message-id " "(conflicts with -r)\n"); exit(1); } int main(int argc, char** argv) { struct passwd* pw; int option; extern int optind; int opti = 0; int optu = 0; int optr = 0; int optl = 0; verbose = 0; pw = getpwnam("news"); if (!pw) { fprintf(stderr, "no such user: news\n"); exit(1); } setregid(-1, pw->pw_gid); setreuid(-1, pw->pw_uid); if (geteuid() != pw->pw_uid || getegid() != pw->pw_gid) { fprintf(stderr, "%s: must be run as news or root\n", argv[0]); exit(1); } while ((option = getopt(argc, argv, "hviurl")) != -1) { if (option == 'h') usage(); else if (option == 'v') verbose++; else if (option == 'i') opti = 1; else if (option == 'u') optu = 1; else if (option == 'r') optr = 1; else if (option == 'l') optl = 1; } argc -= optind - 1; argv += optind - 1; if (argc == 1 && ((!opti && !optu) || optr || optl)) usage(); else if (argc != 1 && !optr && !optl) usage(); else if (optr && optl) usage(); if (verbose) { printf("%s: verbosity level is %d\n", version, verbose); } whoami(); umask(2); openlog("leaftool", LOG_PID|LOG_CONS, LOG_NEWS); readconfig(); if (opti) { /* * Force read all acrive and re-create groupinfo file. */ if (verbose) printf("update all information\n"); lockactive(); readactive(); correctnewsdesc(); while (servers) { if (verbose) printf("Trying to connect to %s ... ", servers->servername); if (nntpreconnect()) { if (verbose) printf("connected.\n"); getactive(); /* get active from server */ } else { if (verbose) printf("failed.\n"); } servers = servers->next; } writeactive(); unlockactive(); } if (optu) { /* * Update first and last value in active file. * When fetchnews program halted after writing some article and before * writing active file, the number may be corrupted. */ if (verbose) printf("update index information\n"); lockactive(); readactive(); fixgroupinfo(active); writeactive(); unlockactive(); } if (optr) { int i; if (verbose) printf("remove articles\n"); readactive(); for (i = 1; i < argc; i++) { removearts(argv[i]); } } if (optl) { int i; if (verbose) printf("list articles\n"); readactive(); for (i = 1; i < argc; i++) { struct articles* p = findarticles(argv[i]); int j; if (p) { printf("articles containing %s are...\n", argv[i]); for (j = 0; j < p->num; j++) printf("%s:%lu\n", p->arts[j].ng->name, p->arts[j].art); } else { printf("cannot find any articles containing %s\n", argv[i]); } } } mysyslog(LOG_INFO, "done"); exit(0); }