709 lines
16 KiB
C++
709 lines
16 KiB
C++
// This may look like C code, but it is really -*- C++ -*-
|
|
|
|
// ------------------------------------------------------------------
|
|
// The Goldware Library
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
// Copyright (C) 1999-2000 Alexander S. Aganichev
|
|
// ------------------------------------------------------------------
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Library General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Library General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this program; if not, write to the Free
|
|
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
// MA 02111-1307, USA
|
|
// ------------------------------------------------------------------
|
|
// $Id$
|
|
// ------------------------------------------------------------------
|
|
// Version 7 nodelist processing module.
|
|
// Based on source code from Binkley 2.50.
|
|
// V7+ support based on draft #2 by Thomas Waldmann.
|
|
// ------------------------------------------------------------------
|
|
|
|
#include <gfilutil.h>
|
|
#include <gstrall.h>
|
|
#include <gutlmisc.h>
|
|
#include <gftnnlv7.h>
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
char v7nodeflags[16][9] = {
|
|
{ "Hub" },
|
|
{ "Host" },
|
|
{ "Region" },
|
|
{ "Zone" },
|
|
{ "CM," },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" }
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
char v7modemtype[8][9] = {
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" },
|
|
{ "" }
|
|
};
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Unpack a dense version of a symbol (base 40 polynomial)
|
|
|
|
static void v7unpack(char* src, char* dest, uint count) {
|
|
|
|
// This table has been modified to minimize searches
|
|
// 1234567890123456789012345678901234567890
|
|
static char unwrk[] = " EANROSTILCHBDMUGPKYWFVJXZQ-\'0123456789";
|
|
|
|
union {
|
|
word w;
|
|
byte c[2];
|
|
} u;
|
|
|
|
int i, j;
|
|
char obuf[4];
|
|
|
|
*dest = NUL;
|
|
|
|
while(count) {
|
|
|
|
u.c[0] = *src++;
|
|
u.c[1] = *src++;
|
|
|
|
count -= 2;
|
|
|
|
for(j=2; j>=0; j--) {
|
|
|
|
i = u.w % 40;
|
|
u.w /= (word)40;
|
|
obuf[j] = unwrk[i];
|
|
}
|
|
|
|
obuf[3] = NUL;
|
|
|
|
strcat(dest, obuf);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("{%s}", dest);
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* ftn_version7_nodelist_index::namekey() const {
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const ftn_addr& ftn_version7_nodelist_index::addrkey() const {
|
|
|
|
return *((ftn_addr*)key);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ftn_version7_nodelist_index::namecmp() const {
|
|
|
|
#ifdef DEBUG
|
|
printf("[%s] [%s] ", searchname, namekey());
|
|
#endif
|
|
|
|
const char* a = searchname;
|
|
const char* b = namekey();
|
|
int n = 1;
|
|
int d;
|
|
while(1) {
|
|
d = g_tolower((uint8_t)*a) - g_tolower((uint8_t)*b);
|
|
if((d != 0) or (*a == NUL) or (*b == NUL))
|
|
break;
|
|
a++;
|
|
b++;
|
|
n++;
|
|
}
|
|
return d != 0 ? (d > 0 ? n : -n) : 0;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ftn_version7_nodelist_index::addrcmp() const {
|
|
|
|
#ifdef DEBUG
|
|
printf("[%d:%d/%d.%d] [%d:%d/%d.%d] ",
|
|
searchaddr.zone, searchaddr.net, searchaddr.node, searchaddr.point,
|
|
addrkey()->zone, addrkey()->net, addrkey()->node, keylength == 6 ? 0 : addrkey()->point
|
|
);
|
|
#endif
|
|
|
|
ftn_addr currentaddr;
|
|
currentaddr = addrkey();
|
|
if(keylength == 6)
|
|
currentaddr.point = 0;
|
|
|
|
return searchaddr.compare(currentaddr);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::fetchdata() {
|
|
|
|
if(node) {
|
|
|
|
// Get data package
|
|
_V7Data v7data;
|
|
lseek(dfh, block.ndx.lnodeblk.leafref[node-1].keyval, SEEK_SET);
|
|
read(dfh, &v7data, sizeof(_V7Data));
|
|
|
|
// Reset data buffers
|
|
char buf[160], buf2[1024];
|
|
memset(buf, 0, sizeof(buf));
|
|
memset(buf2, 0, sizeof(buf2));
|
|
|
|
// Get phone
|
|
read(dfh, data.phone, v7data.phone_len);
|
|
data.phone[v7data.phone_len] = NUL;
|
|
|
|
// Skip password
|
|
lseek(dfh, v7data.password_len, SEEK_CUR);
|
|
|
|
// Get packed data and unpack it
|
|
read(dfh, buf2, v7data.pack_len);
|
|
v7unpack(buf2, buf, v7data.pack_len);
|
|
|
|
// Get system name
|
|
struplow(strxcpy(data.system, buf, v7data.bname_len+1));
|
|
|
|
// Get name
|
|
if(namebrowse)
|
|
strunrevname(data.name, namekey());
|
|
else {
|
|
char* namep = buf + v7data.bname_len;
|
|
strxcpy(data.name, namep, v7data.sname_len+1);
|
|
}
|
|
struplow(data.name);
|
|
|
|
// Get location
|
|
char* locationp = buf + v7data.bname_len + v7data.sname_len;
|
|
struplow(strxcpy(data.location, locationp, v7data.cname_len+1));
|
|
|
|
// Check if V7+ data is available
|
|
char* v7plus = locationp + v7data.cname_len;
|
|
dword v7p = 0;
|
|
int i, j;
|
|
|
|
for(i=0; (i<8) and (*v7plus); v7plus++, i++) {
|
|
if(not isxdigit(*v7plus))
|
|
break;
|
|
else
|
|
v7p = (v7p <<4) | (xtoi(*v7plus));
|
|
}
|
|
|
|
use_v7plus = (tfh > 0) and (i == 8);
|
|
|
|
if(use_v7plus) {
|
|
|
|
lseek(tfh, v7p, SEEK_SET);
|
|
|
|
if(v7data.nodeflags & V7_B_Point) // node is a point
|
|
lseek(tfh, (long)dtpctl.AllFixSize, SEEK_CUR);
|
|
else
|
|
lseek(tfh, (long)dtpctl.AllFixSize + (long)dtpctl.AddFixSize, SEEK_CUR);
|
|
|
|
word raw_length;
|
|
|
|
read(tfh, &raw_length, sizeof(raw_length));
|
|
|
|
if(raw_length < sizeof(buf2)) {
|
|
read(tfh, buf2, raw_length);
|
|
data.unpack(buf2);
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Get status
|
|
for(j=1, i=0; i<4; j+=j, i++) {
|
|
if(v7data.nodeflags & j)
|
|
strcpy(data.status, v7nodeflags[i]);
|
|
}
|
|
*data.status = NUL;
|
|
|
|
// Get baud
|
|
sprintf(data.baud, "%lu", 300L * (long)v7data.baudrate);
|
|
|
|
// Get flags
|
|
*data.flags = NUL;
|
|
char* ptr = data.flags;
|
|
|
|
for(j=(1<<4),i=4; i<16; j+=j,i++)
|
|
if(v7data.nodeflags & j)
|
|
ptr = stpcpy(ptr, v7nodeflags[i]);
|
|
|
|
// Get modem types
|
|
for(j=1,i=0; i<8; j+=j,i++)
|
|
if(v7data.modemtype & j)
|
|
ptr = stpcpy(ptr, v7modemtype[i]);
|
|
|
|
// Erase the trailing comma
|
|
if(ptr != data.flags)
|
|
*(--ptr) = NUL;
|
|
}
|
|
|
|
// Get address
|
|
data.addr.zone = v7data.zone;
|
|
data.addr.net = v7data.net;
|
|
data.addr.node = v7data.node;
|
|
data.addr.point = (word)((v7data.nodeflags & V7_B_Point) ? v7data.hubnode : 0);
|
|
data.addr.make_string(data.address);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::getindexkey() {
|
|
|
|
_V7IndxRef* ip = &(block.ndx.inodeblk.indxref[inode-1]);
|
|
keylength = ip->indxlen;
|
|
memcpy(key, (char*)&block+ip->indxofs, keylength);
|
|
key[keylength] = NUL;
|
|
|
|
#ifdef DEBUG
|
|
printf("`---%02d:%02d <%04ld> ",
|
|
inode,
|
|
block.ndx.inodeblk.indxcnt,
|
|
block.ndx.inodeblk.indxref[inode-1].indxptr
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::getleafkey() {
|
|
|
|
_V7LeafRef* lp = &(block.ndx.lnodeblk.leafref[node-1]);
|
|
keylength = lp->keylen;
|
|
memcpy(key, (char*)&block+lp->keyofs, keylength);
|
|
key[keylength] = NUL;
|
|
|
|
#ifdef DEBUG
|
|
printf("`---%02d:%02d ", node, block.ndx.lnodeblk.indxcnt);
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::getblock() {
|
|
|
|
lseek(xfh, blockno*(long)ctl.ndx.ctlblk.ctlblksize, SEEK_SET);
|
|
read(xfh, &block, sizeof(_V7Ndx));
|
|
|
|
#ifdef DEBUG
|
|
if(block.ndx.inodeblk.indxfirst != -1) {
|
|
printf("INDEXINFO: Branch:%ld, Below:%ld, Left:%ld, Right:%ld.\n",
|
|
blockno,
|
|
block.ndx.inodeblk.indxfirst,
|
|
block.ndx.inodeblk.indxblink,
|
|
block.ndx.inodeblk.indxflink
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::getleaf() {
|
|
|
|
#ifdef DEBUG
|
|
printf("LEAF_INFO: Branch:%ld, Left:%ld, Right:%ld.\n",
|
|
blockno,
|
|
block.ndx.lnodeblk.indxblink,
|
|
block.ndx.lnodeblk.indxflink
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::search() {
|
|
|
|
int diff = 0;
|
|
int prevdiff = 0;
|
|
int previndexdiff = 0;
|
|
exactmatch = false;
|
|
|
|
xfh = namebrowse ? sfh : nfh;
|
|
node = 0;
|
|
|
|
// Get CtlRec
|
|
lseek(xfh, 0, SEEK_SET);
|
|
read(xfh, &ctl, sizeof(_V7Ndx));
|
|
|
|
// The guts of the matter -- walk from CtlRec to Leaf
|
|
blockno = ctl.ndx.ctlblk.ctlroot;
|
|
memset(&block, 0, sizeof(_V7Ndx));
|
|
inode = 1;
|
|
|
|
// Read the first Index node.
|
|
getblock();
|
|
|
|
// Follow the node tree until we either match a key right in the
|
|
// index node, or locate the leaf node which must contain the data.
|
|
while(block.ndx.inodeblk.indxfirst != -1) {
|
|
if(block.ndx.inodeblk.indxcnt == 0) {
|
|
exactmatch = false;
|
|
return false;
|
|
}
|
|
|
|
for(inode=1; inode<=block.ndx.inodeblk.indxcnt; inode++) {
|
|
|
|
getindexkey();
|
|
|
|
diff = namebrowse ? namecmp() : addrcmp();
|
|
previndexdiff = diff;
|
|
|
|
#ifdef DEBUG
|
|
printf("(%d)\n", diff);
|
|
#endif
|
|
|
|
if(diff <= 0)
|
|
break;
|
|
}
|
|
|
|
if(inode == 1)
|
|
blockno = block.ndx.inodeblk.indxfirst;
|
|
else if(diff == 0)
|
|
blockno = block.ndx.inodeblk.indxref[inode-1].indxptr;
|
|
else
|
|
blockno = block.ndx.inodeblk.indxref[(--inode)-1].indxptr;
|
|
|
|
getblock();
|
|
}
|
|
|
|
// We can only get here if we've found the leafnode which must
|
|
// contain our data. Find our guy here or die trying.
|
|
|
|
if(block.ndx.lnodeblk.indxcnt != 0) {
|
|
|
|
// Search for a higher key
|
|
|
|
getleaf();
|
|
|
|
for(node=1; node<=block.ndx.lnodeblk.indxcnt; node++) {
|
|
|
|
getleafkey();
|
|
|
|
prevdiff = diff;
|
|
diff = namebrowse ? namecmp() : addrcmp();
|
|
|
|
#ifdef DEBUG
|
|
printf("(%d)\n", diff);
|
|
#endif
|
|
|
|
if(diff < 0)
|
|
break;
|
|
if(diff == 0) {
|
|
while(previous()) {
|
|
if(not exactmatch) {
|
|
next();
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if((prevdiff > 0) and (diff <0)) {
|
|
if(absolute(prevdiff) > absolute(diff)) {
|
|
#ifdef DEBUG
|
|
printf("Begin lookup at previous blockno.\n");
|
|
#endif
|
|
prevnode();
|
|
}
|
|
else {
|
|
#ifdef DEBUG
|
|
printf("Begin lookup at current blockno.\n");
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
if(absolute(previndexdiff) > absolute(diff)) {
|
|
#ifdef DEBUG
|
|
printf("Begin lookup at next blockno.\n");
|
|
#endif
|
|
nextnode();
|
|
}
|
|
else {
|
|
#ifdef DEBUG
|
|
printf("Begin lookup at this blockno.\n");
|
|
#endif
|
|
if(node > 1)
|
|
node--;
|
|
}
|
|
}
|
|
|
|
fetchdata();
|
|
}
|
|
|
|
return exactmatch;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::prevnode() {
|
|
|
|
if(node == 1) {
|
|
// Reached first node in current leaf
|
|
if(block.ndx.lnodeblk.indxblink == 0)
|
|
return false;
|
|
blockno = block.ndx.inodeblk.indxblink;
|
|
getblock();
|
|
getleaf();
|
|
node = block.ndx.lnodeblk.indxcnt;
|
|
}
|
|
else {
|
|
node--;
|
|
}
|
|
getleafkey();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::nextnode() {
|
|
|
|
if(node >= block.ndx.lnodeblk.indxcnt) {
|
|
// Reached end of nodes in current leaf
|
|
if(block.ndx.lnodeblk.indxflink == 0)
|
|
return false;
|
|
blockno = block.ndx.inodeblk.indxflink;
|
|
getblock();
|
|
getleaf();
|
|
node = 1;
|
|
}
|
|
else {
|
|
node++;
|
|
}
|
|
getleafkey();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
ftn_version7_nodelist_index::ftn_version7_nodelist_index() {
|
|
|
|
nfh = sfh = dfh = tfh = -1;
|
|
use_v7plus = false;
|
|
isopen = false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
ftn_version7_nodelist_index::~ftn_version7_nodelist_index() {
|
|
|
|
if(isopen)
|
|
close();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::open() {
|
|
|
|
if(isopen)
|
|
close();
|
|
|
|
nfh = ::sopen(AddPath(nlpath, "NODEX.NDX"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
sfh = ::sopen(AddPath(nlpath, "SYSOP.NDX"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
if(sfh == -1)
|
|
sfh = ::sopen(AddPath(nlpath, "NODEX.SDX"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
dfh = ::sopen(AddPath(nlpath, "NODEX.DAT"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
tfh = ::sopen(AddPath(nlpath, "NODEX.DTP"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD);
|
|
|
|
if((nfh == -1) or (sfh == -1) or (dfh == -1)) {
|
|
// Unable to open an index file
|
|
close();
|
|
return false;
|
|
}
|
|
|
|
if(tfh != -1)
|
|
read(tfh, &dtpctl, sizeof(_V7DTPCtl));
|
|
|
|
isopen = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::close() {
|
|
|
|
if(dfh != -1) ::close(dfh); dfh = -1;
|
|
if(sfh != -1) ::close(sfh); sfh = -1;
|
|
if(nfh != -1) ::close(nfh); nfh = -1;
|
|
if(tfh != -1) ::close(tfh); tfh = -1;
|
|
|
|
isopen = false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::find(const char* lookup_name) {
|
|
|
|
namebrowse = true;
|
|
|
|
char tmpname[80];
|
|
strcpy(tmpname, lookup_name);
|
|
strchg(tmpname, '.', ' ');
|
|
struplow(strrevname(searchname, tmpname));
|
|
|
|
return search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::find(const ftn_addr& addr) {
|
|
|
|
namebrowse = false;
|
|
searchaddr = addr;
|
|
return search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::previous() {
|
|
|
|
bool moved = prevnode();
|
|
if(moved) {
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool ftn_version7_nodelist_index::next() {
|
|
|
|
bool moved = nextnode();
|
|
if(moved) {
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::first() {
|
|
|
|
if(namebrowse) {
|
|
*searchname = NUL;
|
|
}
|
|
else {
|
|
searchaddr.reset();
|
|
}
|
|
search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::last() {
|
|
|
|
if(namebrowse) {
|
|
memset(searchname, 0xFF, sizeof(searchname));
|
|
searchname[sizeof(searchname)-1] = NUL;
|
|
}
|
|
else {
|
|
searchaddr.set_all(0xFFFF);
|
|
}
|
|
search();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::push_state() {
|
|
|
|
state.blockno = blockno;
|
|
state.node = node;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ftn_version7_nodelist_index::pop_state() {
|
|
|
|
blockno = state.blockno;
|
|
node = state.node;
|
|
getblock();
|
|
getleaf();
|
|
getleafkey();
|
|
fetchdata();
|
|
compare();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* ftn_version7_nodelist_index::index_name() const {
|
|
|
|
return namebrowse ? "SYSOP.NDX" : "NODEX.NDX";
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* ftn_version7_nodelist_index::nodelist_name() const {
|
|
|
|
return use_v7plus ? "NODEX.DTP" : (const char*)NULL;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|