/*
* 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 <socks.h>
#endif
#include <sys/types.h>
#ifdef BSD
#include <sys/errno.h>
#endif
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#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 <msg-id>...]\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);
}
syntax highlighted by Code2HTML, v. 0.9.1