// 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$ // ------------------------------------------------------------------ // FrontDoor Nodelist Indexing. // Based on code kindly provided by Scott Dudley. // ------------------------------------------------------------------ #include #include #include // ------------------------------------------------------------------ inline const _FDUdx& ftn_frontdoor_nodelist_index::namerec() const { return block.node.name[node-1]; } // ------------------------------------------------------------------ inline const _FDFdx& ftn_frontdoor_nodelist_index::addrrec() const { return block.node.addr[node-1]; } // ------------------------------------------------------------------ inline const _FDGdx& ftn_frontdoor_nodelist_index::noderec() const { return namebrowse ? *((_FDGdx*)&block.node.name[node-1]) : *((_FDGdx*)&block.node.addr[node-1]); } // ------------------------------------------------------------------ int ftn_frontdoor_nodelist_index::namecmp() const { #ifdef DEBUG printf("[%s] [%-15.15s] ", searchname, namerec().name); #endif const char* a = searchname; const char* b = namerec().name; int n = 1; while(n <= 15) { int d = (int)((byte)*a) - (int)((byte)*b); if(d != 0) return d > 0 ? n : -n; a++; b++; n++; } return 0; } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::getaddr(ftn_addr& addr) const { if(namebrowse) { addr.zone = (word)((namerec().zone_hi << 8) | namerec().zone_lo); addr.net = (word)((namerec().net_hi << 8) | namerec().net_lo); addr.node = (word)((namerec().node_hi << 8) | namerec().node_lo); addr.point = (word)((namerec().point_hi << 8) | namerec().point_lo); } else { addr.zone = (word)((addrrec().zone_hi << 8) | addrrec().zone_lo); addr.net = (word)((addrrec().net_hi << 8) | addrrec().net_lo); addr.node = (word)((addrrec().node_hi << 8) | addrrec().node_lo); addr.point = (word)((addrrec().point_hi << 8) | addrrec().point_lo); } } // ------------------------------------------------------------------ int ftn_frontdoor_nodelist_index::addrcmp() const { ftn_addr currentaddr; getaddr(currentaddr); #ifdef DEBUG printf("[%d:%d/%d.%d] [%d:%d/%d.%d] ", searchaddr.zone, searchaddr.net, searchaddr.node, searchaddr.point, currentaddr.zone, currentaddr.net, currentaddr.node, currentaddr.point ); #endif return searchaddr.compare(currentaddr); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::getstatus(char* _status, int type) const { switch(type) { case ISZC: strcpy(_status, "Zone"); break; case ISRC: strcpy(_status, "Region"); break; case ISNC: strcpy(_status, "Host"); break; case ISHUB: strcpy(_status, "Hub"); break; case ISPVT: strcpy(_status, "Pvt"); break; case ISHOLD: strcpy(_status, "Hold"); break; case ISDOWN: strcpy(_status, "Down"); break; case ISPOINT: strcpy(_status, "Point"); break; default: *_status = NUL; } } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::fetchdata() { bool infdpvt = !!(noderec().nlofs & IN_FDNET); bool infdpoint = !!(noderec().nlofs & IN_FDPOINT); bool infdnode = !!(noderec().nlofs & IN_FDNODE); if(infdnode) { int fd = ::sopen(AddPath(nlpath, "FDNODE.FDA"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD); if(fd != -1) { _FDFdn fda; while(read(fd, &fda, sizeof(_FDFdn)) == sizeof(_FDFdn)) { if(not fda.erased) { if((fda.zone == data.addr.zone) and (fda.net == data.addr.net) and (fda.node == data.addr.node) and (fda.point == data.addr.point)) { strnp2cc(data.name, fda.user, 36); strnp2cc(data.system, fda.name, 30); strnp2cc(data.phone, fda.telephone, 40); strnp2cc(data.location, fda.location, 40); switch(fda.maxbaud) { case ISBAUD300 : strcpy(data.baud, "300"); break; case ISBAUD1200 : strcpy(data.baud, "1200"); break; case ISBAUD2400 : strcpy(data.baud, "2400"); break; case ISBAUD4800 : strcpy(data.baud, "4800"); break; case ISBAUD7200 : strcpy(data.baud, "7200"); break; case ISBAUD9600 : strcpy(data.baud, "9600"); break; case ISBAUD12000 : strcpy(data.baud, "12000"); break; case ISBAUD14400 : strcpy(data.baud, "14400"); break; case ISBAUD16800 : strcpy(data.baud, "16800"); break; case ISBAUD19200 : strcpy(data.baud, "19200"); break; case ISBAUD38400 : strcpy(data.baud, "38400"); break; case ISBAUD57600 : strcpy(data.baud, "57600"); break; case ISBAUD64000 : strcpy(data.baud, "64000"); break; case ISBAUD76800 : strcpy(data.baud, "76800"); break; case ISBAUD115200: strcpy(data.baud, "115200"); break; default: *data.baud = NUL; } getstatus(data.status, fda.status); *data.flags = NUL; long c = fda.capability; char* f = data.flags; if(c & CMflag) strcat(f, "CM,"); if(c & MOflag) strcat(f, "MO,"); if(c & LOflag) strcat(f, "LO,"); if(c & V32flag) strcat(f, "V32,"); if(c & V32bflag) strcat(f, "V32B,"); if(c & V33flag) strcat(f, "V33,"); if(c & V34flag) strcat(f, "V34,"); if(c & V42flag) strcat(f, "V42,"); if(c & V42bflag) strcat(f, "V42B,"); if(c & MNPflag) strcat(f, "MNP,"); if(c & H96flag) strcat(f, "H96,"); if(c & HSTflag) strcat(f, "HST,"); if(c & HST14flag) strcat(f, "H14,"); if(c & HST16flag) strcat(f, "H16,"); if(c & MAXflag) strcat(f, "MAX,"); if(c & PEPflag) strcat(f, "PEP,"); if(c & ZYXflag) strcat(f, "ZYX,"); if(c & XAflag) strcat(f, "XA,"); if(c & XBflag) strcat(f, "XB,"); if(c & XCflag) strcat(f, "XC,"); if(c & XPflag) strcat(f, "XP,"); if(c & XRflag) strcat(f, "XR,"); if(c & XWflag) strcat(f, "XW,"); if(c & XXflag) strcat(f, "XX,"); if(c & FAXflag) strcat(f, "FAX,"); if(c & UISDNAflag) strcat(f, "V110L,"); if(c & UISDNBflag) strcat(f, "V110H,"); if(c & UISDNCflag) strcat(f, "X75,"); if(*f) f[strlen(f)-1] = NUL; break; } } } ::close(fd); } } else { int fd = infdpvt ? pfd : (infdpoint ? ppfd : nfd); long offset = noderec().nlofs & ~(IN_FDNET|IN_FDPOINT); char buf[256]; buf[255] = NUL; lseek(fd, offset, SEEK_SET); read(fd, buf, 255); if(*buf != ';') { char* end = strchr(buf, '\r'); if(end) *end = NUL; strchg(strtrim(buf), '_', ' '); *data.name = NUL; *data.system = NUL; *data.location = NUL; *data.phone = NUL; *data.flags = NUL; *data.baud = NUL; char* q = buf; char* p = strchr(buf, ','); if(p) { *p++ = NUL; strxcpy(data.system, q, sizeof(data.system)); p = strchr((q=p), ','); if(p) { *p++ = NUL; strxcpy(data.location, q, sizeof(data.location)); p = strchr((q=p), ','); if(p) { *p++ = NUL; strxcpy(data.name, q, sizeof(data.name)); p = strchr((q=p), ','); if(p) { *p++ = NUL; strxcpy(data.phone, q, sizeof(data.phone)); p = strchr((q=p), ','); sprintf(data.baud, "%lu", atol(q)); if(p) strxcpy(data.flags, p+1, sizeof(data.flags)); } } } } } getstatus(data.status, namebrowse ? namerec().type : addrrec().type); } data.addr.make_string(data.address); } // ------------------------------------------------------------------ #ifdef DEBUG void ftn_frontdoor_nodelist_index::printnode() const { printf("<%05d.%05d.%05d.%d> <%02d:%02d> ", blockno, block.info.index, noderec().block_num, depth, block.info.nodes, node ); } #endif // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::getnodedata() { #ifdef DEBUG printnode(); #endif getaddr(data.addr); fetchdata(); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::getblock() { lseek(xfd, (long)blockno*(long)blocksize, SEEK_SET); read(xfd, &block, blocksize); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::push() { stack[depth].blockno = blockno; stack[depth].block_num = noderec().block_num; stack[depth].maxnodes = block.info.nodes; stack[depth].node = node; depth++; } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::pop() { depth--; node = stack[depth].node; blockno = stack[depth].blockno; } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::search() { xfd = namebrowse ? ufd : fdfd; blocksize = namebrowse ? sizeof(_FDUdb) : sizeof(_FDFdb); // Read beginning control block lseek(xfd, 0L, SEEK_SET); read(xfd, &ctl, sizeof(_FDCtl)); // Now trace down the tree, starting at the master index exactmatch = false; int diff = 0; int prevdiff = 0; blockno = ctl.hdr.master_idx; maxblockno = (uint)(lseek(xfd, 0L, SEEK_END)/blocksize); depth = 0; node = 1; push(); // Do one block at a time... while((not exactmatch) and (blockno < maxblockno)) { // Get one block node = 0; getblock(); // Scan all nodes in this block to find a match lastblockno = block.info.index; do { node++; if(namebrowse) { #ifdef DEBUG printnode(); #endif prevdiff = diff; diff = namecmp(); #ifdef DEBUG printf("{%d}\n", diff); #endif if(diff <= 0) { if(diff == 0) { exactmatch = true; } break; } lastblockno = namerec().block_num; } else { #ifdef DEBUG printnode(); #endif prevdiff = diff; diff = addrcmp(); #ifdef DEBUG printf("{%d}\n", diff); #endif if(diff <= 0) { if(diff == 0) { exactmatch = true; } break; } lastblockno = addrrec().block_num; } } while(node < block.info.nodes); if(not exactmatch) { if(lastblockno) { push(); blockno = lastblockno; } else { break; } } } if(diff == 0) { #ifdef DEBUG printf("Gotcha!\n"); #endif while(previous()) { if(not exactmatch) { next(); break; } } return true; } else 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 } getnodedata(); return exactmatch; } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::prevnode() { if(node == 1) { if(blockno == 1) return false; if(depth > 0) { pop(); getblock(); node--; if(node <= 0) { blockno = block.info.index; getblock(); node = block.info.nodes; } } else { return false; } } else { node--; if(noderec().block_num) { node++; push(); node--; blockno = noderec().block_num; getblock(); node = block.info.nodes; } } return true; } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::nextnode() { if(noderec().block_num) { // Current node has a block. Go to it. node++; push(); node--; blockno = noderec().block_num; node = 1; getblock(); } else if(node >= block.info.nodes) { // Reached end of nodes in current block. if(depth > 0) { if((stack[depth-1].node == stack[depth-1].maxnodes) and (stack[depth-1].block_num == blockno)) return false; // Go back to previous block pop(); getblock(); } else { // Reached final leaf return false; } } else { node++; } return true; } // ------------------------------------------------------------------ ftn_frontdoor_nodelist_index::ftn_frontdoor_nodelist_index() { fdfd = nfd = pfd = ppfd = ufd = -1; is_intermail = false; isopen = false; blocksize = 0; depth = 0; } // ------------------------------------------------------------------ ftn_frontdoor_nodelist_index::~ftn_frontdoor_nodelist_index() { if(isopen) close(); } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::open() { if(isopen) close(); if(fexist(AddPath(nlpath, "IMNODE.CTL"))) is_intermail = true; // Open the nodelist binary file first fdfd = ::sopen(AddPath(nlpath, "NODELIST.FDX"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD); if(fdfd == -1) { close(); return false; } // Read the control block up front read(fdfd, &ctl, sizeof(_FDCtl)); // Now use that info to open the primary nodelist Path primary; sprintf(nodelist, "NODELIST.%3.3s", ctl.nl_ext); sprintf(primary, "%s%s", nlpath, nodelist); nfd = ::sopen(primary, O_RDONLY | O_BINARY, SH_DENYNO, S_STDRD); // Don't check for failure, since there may not be a primary nodelist! // Open the userlist file ufd = ::sopen(AddPath(nlpath, "USERLIST.FDX"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD); if(ufd == -1) { close(); return false; } // Failing to open the private nodelist is not an error, since there may not be one! pfd = ::sopen(AddPath(nlpath, is_intermail ? "IMNET.PVT" : "FDNET.PVT"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD); // Failing to open the point nodelist is not an error, since there may not be one! ppfd = ::sopen(AddPath(nlpath, is_intermail ? "IMPOINT.PVT" : "FDPOINT.PVT"), O_RDONLY|O_BINARY, SH_DENYNO, S_STDRD); isopen = true; return true; } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::close() { if(fdfd != -1) ::close(fdfd); fdfd = -1; if(nfd != -1) ::close(nfd); nfd = -1; if(pfd != -1) ::close(pfd); pfd = -1; if(ppfd != -1) ::close(ppfd); ppfd = -1; if(ufd != -1) ::close(ufd); ufd = -1; isopen = false; } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::find(const char* lookup_name) { char buf[80], tmp[80]; strcpy(tmp, lookup_name); namebrowse = true; char* ptr = strrchr(tmp, ' '); if(ptr) { if(ptr == (tmp+strlen(tmp)-1)) { while((*ptr == ' ') and (ptr > tmp)) ptr--; ptr++; } *ptr = NUL; sprintf(buf, "%s %s", ptr+1, tmp); *ptr = ' '; } else { strcpy(buf, tmp); } strupr(strtrim(buf)); sprintf(searchname, "%-15.15s", buf); return search(); } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::find(const ftn_addr& addr) { namebrowse = false; searchaddr = addr; return search(); } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::previous() { bool moved = prevnode(); if(moved) { getnodedata(); compare(); } return moved; } // ------------------------------------------------------------------ bool ftn_frontdoor_nodelist_index::next() { bool moved = nextnode(); if(moved) { getnodedata(); compare(); } return moved; } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::first() { if(namebrowse) { memset(searchname, ' ', sizeof(searchname)-1); searchname[sizeof(searchname)-1] = NUL; } else { searchaddr.reset(); } search(); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::last() { if(namebrowse) { memset(searchname, 0xFF, sizeof(searchname)-1); searchname[sizeof(searchname)-1] = NUL; } else { searchaddr.set_all(0xFFFF); } search(); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::push_state() { state.node = node; state.depth = depth; state.blockno = blockno; memcpy(state.stack, stack, sizeof(stack)); } // ------------------------------------------------------------------ void ftn_frontdoor_nodelist_index::pop_state() { memcpy(stack, state.stack, sizeof(stack)); blockno = state.blockno; depth = state.depth; node = state.node; getblock(); getnodedata(); compare(); } // ------------------------------------------------------------------ const char* ftn_frontdoor_nodelist_index::index_name() const { return namebrowse ? "USERLIST.FDX" : "NODELIST.FDX"; } // ------------------------------------------------------------------ const char* ftn_frontdoor_nodelist_index::nodelist_name() const { if(noderec().nlofs & IN_FDNODE) return "FDNODE.FDA"; else if(noderec().nlofs & IN_FDNET) return is_intermail ? "IMNET.PVT" : "FDNET.PVT"; else if(noderec().nlofs & IN_FDPOINT) return is_intermail ? "IMPOINT.PVT" : "FDPOINT.PVT"; return nodelist; } // ------------------------------------------------------------------