Initial revision
This commit is contained in:
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* binkleyforce -- unix FTN mailer project
|
||||
*
|
||||
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "confread.h"
|
||||
#include "logger.h"
|
||||
#include "util.h"
|
||||
#include "nodelist.h"
|
||||
|
||||
#define NODELIST_LOCK_TRIES 3
|
||||
#define NODELIST_LOCK_DELAY 1 /* seconds */
|
||||
|
||||
struct keyword {
|
||||
const char *keystr;
|
||||
const int keyval;
|
||||
} keywords[] = {
|
||||
{ "", KEYWORD_EMPTY },
|
||||
{ "Zone", KEYWORD_ZONE },
|
||||
{ "Region", KEYWORD_REGION },
|
||||
{ "Host", KEYWORD_HOST },
|
||||
{ "Hub", KEYWORD_HUB },
|
||||
{ "Pvt", KEYWORD_PVT },
|
||||
{ "Hold", KEYWORD_HOLD },
|
||||
{ "Down", KEYWORD_DOWN },
|
||||
{ "Boss", KEYWORD_BOSS },
|
||||
{ "Point", KEYWORD_POINT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Check flag for existing in nodelist flags string
|
||||
*
|
||||
* Arguments:
|
||||
* nodeflags pointer to the node's nodelist flags string
|
||||
* flag pointer to the flag that we want to check
|
||||
*
|
||||
* Return value:
|
||||
* zero value if flag is presented in flags, and non-zero if not
|
||||
*/
|
||||
int nodelist_checkflag(const char *nodeflags, const char *flag)
|
||||
{
|
||||
char *p, *q;
|
||||
|
||||
if( (p = strstr(nodeflags, flag)) )
|
||||
{
|
||||
if( p == nodeflags || *(p-1) == ',' )
|
||||
{
|
||||
if( (q = strchr(p, ',')) == NULL || (q - p) == strlen(flag) )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Get nodelist keyword (e.g. Host, Hub, Point, etc.) value
|
||||
* (e.g. KEYWORD_HOST, KEYWORD_HUB, etc.)
|
||||
*
|
||||
* Arguments:
|
||||
* keywordval pointer to the keyword string
|
||||
*
|
||||
* Return value:
|
||||
* One of KEYWORD_* values, and -1 for unknown keywords
|
||||
*/
|
||||
int nodelist_keywordval(const char *keyword)
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; keywords[i].keystr; i++ )
|
||||
{
|
||||
if( strcmp(keyword, keywords[i].keystr) == 0 )
|
||||
{
|
||||
return keywords[i].keyval;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nodelist_parse_Txy(s_node *node, const char *xy)
|
||||
{
|
||||
long beg;
|
||||
long end;
|
||||
long tz;
|
||||
|
||||
if( xy[0] >= 'A' && xy[0] <= 'X' )
|
||||
beg = (xy[0] - 'A') * 60;
|
||||
else if( xy[0] >= 'a' && xy[0] <= 'x' )
|
||||
beg = (xy[0] - 'a') * 60 + 30;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if( xy[1] >= 'A' && xy[1] <= 'X' )
|
||||
end = (xy[1] - 'A') * 60;
|
||||
else if( xy[1] >= 'a' && xy[1] <= 'x' )
|
||||
end = (xy[1] - 'a') * 60 + 30;
|
||||
else
|
||||
return -1;
|
||||
|
||||
if( beg == end )
|
||||
return -1;
|
||||
|
||||
/* Convert it to local time */
|
||||
if( (tz = time_gmtoffset()) )
|
||||
{
|
||||
beg -= tz;
|
||||
if( beg > 1440 )
|
||||
beg = beg - 1440;
|
||||
else if( beg < 0 )
|
||||
beg = beg + 1440;
|
||||
else if( beg == 1440 )
|
||||
beg = 0;
|
||||
|
||||
end -= tz;
|
||||
if( end > 1440 )
|
||||
end = end - 1440;
|
||||
else if( end < 0 )
|
||||
end = end + 1440;
|
||||
else if( end == 1440 )
|
||||
end = 0;
|
||||
}
|
||||
|
||||
timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, beg, end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Nodelist string parser
|
||||
*
|
||||
* Arguments:
|
||||
* node put here all obtained information
|
||||
* str pointer to the nodelist string
|
||||
*
|
||||
* Return value:
|
||||
* zero value if string was parsed successfuly, and non-zero if wasn't
|
||||
*/
|
||||
int nodelist_parsestring(s_node *node, char *str)
|
||||
{
|
||||
char *argv[NODELIST_POSFLAGS+1];
|
||||
char *p;
|
||||
|
||||
if( string_parse(argv, NODELIST_POSFLAGS+1, str, ',') != NODELIST_POSFLAGS+1 )
|
||||
return -1;
|
||||
|
||||
if( !ISDEC(argv[NODELIST_POSNUMBER]) || !ISDEC(argv[NODELIST_POSSPEED]) )
|
||||
return -1;
|
||||
if( (node->keyword = nodelist_keywordval(argv[NODELIST_POSKEYWORD])) == -1 )
|
||||
return -1;
|
||||
|
||||
if( node->addr.zone )
|
||||
{
|
||||
int number = atoi(argv[NODELIST_POSNUMBER]);
|
||||
bool goodstr = FALSE;
|
||||
|
||||
switch(node->keyword) {
|
||||
case KEYWORD_ZONE:
|
||||
goodstr = (node->addr.zone == number);
|
||||
break;
|
||||
case KEYWORD_REGION:
|
||||
case KEYWORD_HOST:
|
||||
goodstr = (node->addr.net == number);
|
||||
break;
|
||||
case KEYWORD_POINT:
|
||||
goodstr = (node->addr.point == number);
|
||||
break;
|
||||
default:
|
||||
goodstr = (node->addr.node == number);
|
||||
break;
|
||||
}
|
||||
if( !goodstr ) return -1;
|
||||
}
|
||||
|
||||
strnxcpy(node->name, argv[NODELIST_POSNAME], sizeof(node->name));
|
||||
strnxcpy(node->location, argv[NODELIST_POSLOCATION], sizeof(node->location));
|
||||
strnxcpy(node->sysop, argv[NODELIST_POSSYSOP], sizeof(node->sysop));
|
||||
strnxcpy(node->phone, argv[NODELIST_POSPHONE], sizeof(node->phone));
|
||||
strnxcpy(node->flags, argv[NODELIST_POSFLAGS], sizeof(node->flags));
|
||||
node->speed = atoi(argv[NODELIST_POSSPEED]);
|
||||
|
||||
/*
|
||||
* Replace all '_' by space character
|
||||
*/
|
||||
string_replchar(node->name, '_', ' ');
|
||||
string_replchar(node->location, '_', ' ');
|
||||
string_replchar(node->sysop, '_', ' ');
|
||||
|
||||
/*
|
||||
* Get system work time (usefull flags: CM,Txy)
|
||||
*/
|
||||
if( nodelist_checkflag(node->flags, "CM") == 0 )
|
||||
{
|
||||
timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, 0, 1440);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( p = node->flags; p && *p; p = strchr(p, ',') )
|
||||
{
|
||||
if( p[1] == 'T' && p[2] && p[3] && (p[4] == ',' || p[4] == '\0') )
|
||||
{
|
||||
if( nodelist_parse_Txy(node, p+2) == -1 )
|
||||
log("invalid nodelist Txy flag in \"%s\"", node->flags);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set default work time according to ZMH
|
||||
*/
|
||||
if( node->addr.point == 0 )
|
||||
{
|
||||
switch(node->addr.zone) {
|
||||
case 1: nodelist_parse_Txy(node, "JK"); break;
|
||||
case 2: nodelist_parse_Txy(node, "cd"); break;
|
||||
case 3: nodelist_parse_Txy(node, "ST"); break;
|
||||
case 4: nodelist_parse_Txy(node, "IJ"); break;
|
||||
case 5: nodelist_parse_Txy(node, "BC"); break;
|
||||
case 6: nodelist_parse_Txy(node, "UV"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Open nodelist, nodelist index, do some checks
|
||||
*
|
||||
* Arguments:
|
||||
* dir pointer to the nodelist's directory
|
||||
* name pointer to the nodelist file name
|
||||
* mode are we going to read nodelist index? Or write?
|
||||
*
|
||||
* Return value:
|
||||
* pointer to the allocated nodelist structure (will be used with all
|
||||
* nodelist operations), and NULL to indicate errors.
|
||||
*/
|
||||
s_nodelist *nodelist_open(const char *dir, const char *name, int mode)
|
||||
{
|
||||
s_nodelist tmp;
|
||||
const char *openmode;
|
||||
int lockmode;
|
||||
|
||||
memset(&tmp, '\0', sizeof(s_nodelist));
|
||||
|
||||
/*
|
||||
* Select nodelist index open mode
|
||||
*/
|
||||
if( mode == NODELIST_READ )
|
||||
{
|
||||
openmode = "r";
|
||||
lockmode = FILELOCK_READ;
|
||||
}
|
||||
else if( mode == NODELIST_WRITE )
|
||||
{
|
||||
openmode = "w";
|
||||
lockmode = FILELOCK_WRITE;
|
||||
}
|
||||
else
|
||||
ASSERT(0);
|
||||
|
||||
/*
|
||||
* Get nodelist and nodelist index file names
|
||||
*/
|
||||
if( *name == DIRSEPCHR )
|
||||
{
|
||||
strnxcpy(tmp.name_nodelist, name, sizeof(tmp.name_nodelist));
|
||||
strnxcpy(tmp.name_index, name, sizeof(tmp.name_index));
|
||||
}
|
||||
else
|
||||
{
|
||||
strnxcpy(tmp.name_nodelist, dir, sizeof(tmp.name_nodelist));
|
||||
strnxcat(tmp.name_nodelist, name, sizeof(tmp.name_nodelist));
|
||||
strnxcpy(tmp.name_index, tmp.name_nodelist, sizeof(tmp.name_index));
|
||||
}
|
||||
strnxcat(tmp.name_index, ".index", sizeof(tmp.name_index));
|
||||
|
||||
DEB((D_NODELIST, "nodelist_open: nodelist name = \"%s\"", tmp.name_nodelist));
|
||||
DEB((D_NODELIST, "nodelist_open: nodelist index = \"%s\"", tmp.name_index));
|
||||
DEB((D_NODELIST, "nodelist_open: open mode = \"%s\"", openmode));
|
||||
|
||||
/*
|
||||
* Try to open and lock nodelist
|
||||
*/
|
||||
if( (tmp.fp_nodelist = file_open(tmp.name_nodelist, "r")) == NULL )
|
||||
{
|
||||
logerr("cannot open nodelist \"%s\"", tmp.name_nodelist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to open and lock nodelist index
|
||||
*/
|
||||
if( (tmp.fp_index = file_open(tmp.name_index, openmode)) == NULL )
|
||||
{
|
||||
logerr("cannot open nodelist index \"%s\"", tmp.name_index);
|
||||
fclose(tmp.fp_nodelist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we open nodelist for reading then we should check that
|
||||
* nodelist index has correct header and up to date
|
||||
*/
|
||||
if( mode == NODELIST_READ )
|
||||
{
|
||||
if( nodelist_checkheader(&tmp) == -1 )
|
||||
{
|
||||
file_close(tmp.fp_nodelist);
|
||||
file_close(tmp.fp_index);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return xmemcpy(&tmp, sizeof(s_nodelist));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Check nodelist index header for valid nodelist date and size
|
||||
*
|
||||
* Arguments:
|
||||
* nlp opened nodelist
|
||||
*
|
||||
* Return value:
|
||||
* zero value if header is correct, and -1 if not
|
||||
*/
|
||||
int nodelist_checkheader(s_nodelist *nlp)
|
||||
{
|
||||
unsigned long nltime;
|
||||
unsigned long nlsize;
|
||||
struct stat nlstat;
|
||||
char buffer[NODELIST_HDRSIZE];
|
||||
|
||||
if( fread(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 )
|
||||
{
|
||||
logerr("cannot read header from nodelist index \"%s\"", nlp->name_index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 )
|
||||
{
|
||||
logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nltime = buffer_getlong(buffer + 0);
|
||||
nlsize = buffer_getlong(buffer + 4);
|
||||
|
||||
if( (unsigned long)nlstat.st_mtime != nltime )
|
||||
{
|
||||
log("invalid nodelist index: incorrect nodelist date %ld (expected %ld)",
|
||||
(long)nlstat.st_mtime, (long)nltime);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (unsigned long)nlstat.st_size != nlsize )
|
||||
{
|
||||
log("invalid nodelist index: incorrect nodelist size %ld (expected %ld)",
|
||||
(long)nlstat.st_size, (long)nlsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Create/update nodelist index header. Nodelist must be opened for
|
||||
* writing. Now nodelist index header contain nodelist modification
|
||||
* time and nodelist size.
|
||||
*
|
||||
* Arguments:
|
||||
* nlp opened nodelist
|
||||
*
|
||||
* Return value:
|
||||
* zero value on success, and -1 at errors
|
||||
*/
|
||||
int nodelist_createheader(s_nodelist *nlp)
|
||||
{
|
||||
struct stat nlstat;
|
||||
char hdrbuf[NODELIST_HDRSIZE];
|
||||
|
||||
memset(&hdrbuf, '\0', sizeof(hdrbuf));
|
||||
|
||||
if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 )
|
||||
{
|
||||
logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_putlong(hdrbuf + 0, nlstat.st_mtime);
|
||||
buffer_putlong(hdrbuf + 4, nlstat.st_size);
|
||||
|
||||
if( fseek(nlp->fp_index, 0L, SEEK_SET) == -1 )
|
||||
{
|
||||
logerr("cannot seek to zero offset of index");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( fwrite(hdrbuf, sizeof(hdrbuf), 1, nlp->fp_index) != 1 )
|
||||
{
|
||||
logerr("cannot write nodelist index header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Close nodelist and nodelist index files
|
||||
*
|
||||
* Arguments:
|
||||
* nlp pointer to the opened nodelist
|
||||
*
|
||||
* Return value:
|
||||
* Zero value if close was successful, and non-zero if not
|
||||
*/
|
||||
int nodelist_close(s_nodelist *nlp)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
ASSERT(nlp && nlp->fp_nodelist && nlp->fp_index);
|
||||
|
||||
if( nlp->fp_nodelist && file_close(nlp->fp_nodelist) )
|
||||
logerr("cannot close nodelist \"%s\"", nlp->name_nodelist);
|
||||
|
||||
if( nlp->fp_index && file_close(nlp->fp_index) )
|
||||
{
|
||||
logerr("cannot close nodelist index \"%s\"", nlp->name_index);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
free(nlp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int nodelist_putindex(s_nodelist *nlp, const s_bni *bni)
|
||||
{
|
||||
char buffer[NODELIST_ENTRYSIZE];
|
||||
|
||||
ASSERT(nlp && nlp->fp_index);
|
||||
|
||||
buffer_putint(buffer + 0, bni->zone);
|
||||
buffer_putint(buffer + 2, bni->net);
|
||||
buffer_putint(buffer + 4, bni->node);
|
||||
buffer_putint(buffer + 6, bni->point);
|
||||
buffer_putint(buffer + 8, bni->hub);
|
||||
buffer_putlong(buffer + 10, bni->offset);
|
||||
|
||||
if( fwrite(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 )
|
||||
{
|
||||
logerr("error writing nodelist index file \"%s\"", nlp->name_index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nodelist_findindex(s_nodelist *nlp, s_bni *bni, s_faddr addr)
|
||||
{
|
||||
long readitems;
|
||||
char buffer[NODELIST_ENTRYSIZE * NODELIST_READAHEAD];
|
||||
char *p;
|
||||
|
||||
if( fseek(nlp->fp_index, NODELIST_HDRSIZE, SEEK_SET) ) return -1;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if( (readitems = fread(buffer, NODELIST_ENTRYSIZE, NODELIST_READAHEAD, nlp->fp_index)) > 0 )
|
||||
{
|
||||
for( p = buffer; readitems > 0; readitems-- )
|
||||
{
|
||||
if( buffer_getint(p + 0) == addr.zone
|
||||
&& buffer_getint(p + 2) == addr.net
|
||||
&& buffer_getint(p + 4) == addr.node
|
||||
&& buffer_getint(p + 6) == addr.point )
|
||||
{
|
||||
bni->zone = buffer_getint(p + 0);
|
||||
bni->net = buffer_getint(p + 2);
|
||||
bni->node = buffer_getint(p + 4);
|
||||
bni->point = buffer_getint(p + 6);
|
||||
bni->hub = buffer_getint(p + 8);
|
||||
bni->offset = buffer_getlong(p + 10);
|
||||
return 0;
|
||||
}
|
||||
p += NODELIST_ENTRYSIZE;
|
||||
}
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nodelist_getstr(s_nodelist *nlp, size_t offset, char *buffer, size_t buflen)
|
||||
{
|
||||
ASSERT(nlp && nlp->fp_nodelist);
|
||||
|
||||
if( fseek(nlp->fp_nodelist, offset, SEEK_SET) == 0
|
||||
&& fgets(buffer, buflen, nlp->fp_nodelist) )
|
||||
{
|
||||
string_chomp(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nodelist_lookup_string(char *buffer, size_t buflen, s_faddr addr)
|
||||
{
|
||||
s_bni bni;
|
||||
s_cval_entry *ptrl;
|
||||
s_nodelist *nlp;
|
||||
const char *ndldir = NULL;
|
||||
|
||||
ndldir = conf_string(cf_nodelist_directory);
|
||||
|
||||
/*
|
||||
* Try all nodelists with matching address mask
|
||||
*/
|
||||
for( ptrl = conf_first(cf_nodelist); ptrl; ptrl = conf_next(ptrl) )
|
||||
{
|
||||
if( ftn_addrcomp_mask(addr, ptrl->d.falist.addr) == 0 )
|
||||
{
|
||||
if( (nlp = nodelist_open(ndldir, ptrl->d.falist.what, NODELIST_READ)) )
|
||||
{
|
||||
int rc = nodelist_findindex(nlp, &bni, addr);
|
||||
|
||||
if( !rc )
|
||||
rc = nodelist_getstr(nlp, bni.offset, buffer, buflen);
|
||||
|
||||
nodelist_close(nlp);
|
||||
|
||||
if( !rc )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nodelist_lookup(s_node *node, s_faddr addr)
|
||||
{
|
||||
char buf[512];
|
||||
char abuf[BF_MAXADDRSTR+1];
|
||||
|
||||
nodelist_initnode(node, addr);
|
||||
|
||||
if( nodelist_lookup_string(buf, sizeof(buf), addr) == 0 )
|
||||
{
|
||||
node->listed = TRUE;
|
||||
if( nodelist_parsestring(node, buf) == -1 )
|
||||
{
|
||||
log("invalid nodelist string for address %s",
|
||||
ftn_addrstr(abuf, addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void nodelist_initnode(s_node *node, s_faddr addr)
|
||||
{
|
||||
memset(node, '\0', sizeof(s_node));
|
||||
|
||||
node->addr = addr;
|
||||
strcpy(node->name, "<none>");
|
||||
strcpy(node->sysop, "<none>");
|
||||
strcpy(node->location, "<none>");
|
||||
strcpy(node->phone, "<none>");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user