/*
* 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.
*/
/* $Orig-Id: util.c,v 1.22 1997/07/23 18:35:18 agulbra Exp $ */
/*
Written by Arnt Gulbrandsen <agulbra@troll.no> and copyright 1995
Troll Tech AS, Postboks 6133 Etterstad, 0602 Oslo, Norway, fax +47
22646949.
Use, modification and distribution is allowed without limitation,
warranty, or liability of any kind. */
/*
This code is derived from only leafnode+ by using same structure
of Cornelius's leafnode to prepare for merging with Cornelius's code.
*/
#ifdef SOCKS
#include <socks.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <dirent.h>
#include "leafnode.h"
struct newsgroup * active;
/* insert or update a newsgroup in the global list */
void insertgroup(const char* name,
unsigned long first, unsigned long last,
const char* desc, unsigned long server)
{
struct newsgroup** a;
int c;
if (!desc)
desc = "";
a = &active;
while(a) {
if (*a) {
c = strcmp((*a)->name, name);
if (c < 0) {
a = &((*a)->left);
} else if (c > 0) {
a = &((*a)->right);
} else {
if (first >= 0)
(*a)->first = first;
if (last >= 0)
(*a)->last = last;
if (server >= 0)
(*a)->server = server;
if (desc && *desc) {
/* This leaks memory if the new desc > old one, but I
cannot see a way round this... */
if (strlen((*a)->desc) >= strlen(desc))
strcpy((*a)->desc, desc);
else
(*a)->desc = strdup(desc);
}
return;
}
} else {
*a = (struct newsgroup *)
critmalloc(sizeof(struct newsgroup) + 2 +
strlen(name) + strlen(desc),
"Building newsgroups info list");
if (!*a)
return;
(*a)->left = (*a)->right = NULL;
(*a)->first = first;
(*a)->last = last;
(*a)->server = server;
(*a)->alive = 0;
(*a)->newarticles = 0;
(*a)->name = (char*)(1 + *a);
strcpy((*a)->name, name);
(*a)->desc = strlen((*a)->name) + 1 + ((*a)->name);
strcpy((*a)->desc, desc);
return;
}
}
}
/* find a group by name */
struct newsgroup* findgroup(const char* name)
{
struct newsgroup* a;
int c;
a = active;
while (a) {
c = strcmp(a->name, name);
if (c < 0)
a = a->left;
else if (c > 0)
a = a->right;
else
return a;
}
return a;
}
static void freeactive(struct newsgroup* g)
{
if (g) {
freeactive(g->right);
freeactive(g->left);
free((char*)g);
}
}
static int lockfd = -1;
void lockactive(void)
{
const char* s = getinfofname();
if ((lockfd = open(s, O_RDWR | O_CREAT, S_IWGRP|S_IWOTH)) < 0) {
mysyslog(LOG_ERR, "can't open %s for lock: %s", s, strerror(errno));
exit(2);
}
#ifdef USE_LOCKF
# ifdef NOWAIT_LOCK
if (lockf(lockfd, F_TLOCK, (off_t)0))
# else
if (lockf(lockfd, F_LOCK, (off_t)0))
# endif
#else
# ifdef NOWAIT_LOCK
if (flock(lockfd, LOCK_EX | LOCK_NB))
# else
if (flock(lockfd, LOCK_EX))
# endif
#endif
{
mysyslog(LOG_ERR, "can't lock %s: %s", s, strerror(errno));
exit(2);
}
/* keep file open to hold a lock */
}
void unlockactive(void)
{
if (lockfd >= 0) {
close(lockfd);
lockfd = -1;
}
}
/* this uses a nifty technique for building a binary tree from a
sorted list... the basic observation is that if you count from one
end, with 1 being the rightmost node, then the number of nodes
between N and the leaf nodes is equal to the number of zero bits
at the small end of N. this tree probably doesn't make it obvious:
1 2 3 4 5 6 7
1
1 0 1
1 0 1 0 1 0 1
| | | | | | + no zeroes: leaf node
| | | | | +-- one zero: one step up
| | | | +---- no zeroes: leaf node
| | | +------ two zeroes: two steps up
| | +-------- no zeroes: leaf node
| +---------- one zero: one step up
+------------ no zeroes: leaf node
this can be used to build a smallest-height tree, and with a bit more
care, a _perfectly_ balanced tree */
void readactive(void)
{
char* p;
char* q;
unsigned long first, last, server;
int fd;
struct newsgroup* g;
struct stat st;
int line;
struct newsgroup* levels[32]; /* theoretically finite size :) */
int l;
static char* stuff;
const char* s = getinfofname();
if (stuff) {
freeactive(active);
active = NULL;
free((char*)stuff);
stuff = NULL;
}
fd = open(s, O_RDONLY);
if (stat(s, &st) < 0) {
mysyslog(LOG_ERR, "can't stat %s: %s", s, strerror(errno));
return;
}
stuff = critmalloc(st.st_size + 1, "Reading group info");
if ((fd = open(s, O_RDONLY)) < 0 ||
read(fd, stuff, st.st_size) < st.st_size) {
mysyslog(LOG_ERR, "can't open/read %s: %s", s, strerror(errno));
return;
} else {
close(fd);
stuff[st.st_size] = '\0'; /* 0-terminate string */
}
line = 1;
for(l = 0; l < 32; levels[l++] = NULL)
;
p = stuff;
while (p && *p) {
q = p;
p = strchr(p, ' ');
if (p && *p) {
*p++ = '\0';
if (*q) {
last = p ? strtoul(p, &p, 10) : 0;
first = p ? strtoul(p, &p, 10) : 0;
server = p ? strtoul(p, &p, 10) : 0;
p = skipspaces(p);
if (first < 1)
first = 1;
g = (struct newsgroup *)critmalloc(sizeof(struct newsgroup),
"reading groupinfo");
g->right = g->left = NULL;
g->first = first;
g->last = last;
g->server = server;
g->alive = 0;
g->newarticles = 0;
g->name = q;
g->desc = p;
for (l = 0; (line & (1 << l)) == 0; l++)
;
if (l) {
g->right = levels[l - 1];
}
if (active == g->right)
active = g;
if (l < 31 && levels[l + 1] && !levels[l + 1]->left)
levels[l + 1]->left = g;
levels[l] = g;
p = strchr(p, '\n');
if (p)
*p++ = '\0';
line++;
} else {
p = strchr(p, '\n');
if (p)
p++;
}
}
}
g = NULL;
for (l = 0; l < 31; l++) {
if (levels[l]) {
if (g && levels[l] &&
levels[l]->left == NULL && levels[l]->right != g) {
levels[l]->left = g;
g = NULL;
}
if (!levels[l + 1] ||
(levels[l] != levels[l + 1]->left &&
levels[l] != levels[l + 1]->right)) {
if (g)
mysyslog(LOG_ERR, "2+5=2");
g = levels[l];
}
}
}
}
static void helpwriteactive(struct newsgroup* g, FILE* f)
{
if (g) {
helpwriteactive(g->right, f);
fprintf(f, "%s %lu %lu %lu %s\n", g->name, g->last, g->first, 0LU,
g->desc && *(g->desc) ? g->desc : "-x-");
helpwriteactive(g->left, f);
}
}
void writeactive(void)
{
const char* s;
FILE* a;
char c[PATH_MAX];
s = getinfonewfname();
a = fopen(s, "w");
if (!a)
return;
helpwriteactive(active, a);
fflush(a);
if (ferror(a)) {
fclose(a);
mysyslog(LOG_ERR, "%s has error while writing: %s", s, strerror(errno));
return;
}
fclose(a);
strcpy(c, s);
s = getinfofname();
rename(c, s);
}
#if 0
/* Cornelius's code has fakeactive here */
/*
* fake an active file if the groupinfo file is corrupted
*/
void fakeactive(void)
{
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1