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 DEBUGx
|
||
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 = tolower((uchar)*a) - tolower((uchar)*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("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>%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("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>%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;
|
||
}
|
||
|
||
|
||
// ------------------------------------------------------------------
|