home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / c / bts314b4 / nodeproc.c < prev    next >
C/C++ Source or Header  |  1994-05-29  |  48KB  |  2,002 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                                                            */
  3. /*                                                                            */
  4. /*        ------------         Bit-Bucket Software, Co.                        */
  5. /*        \ 10001101 /         Writers and Distributors of                    */
  6. /*         \ 011110 /          Freely Available<tm> Software.                 */
  7. /*          \ 1011 /                                                            */
  8. /*           ------                                                            */
  9. /*                                                                            */
  10. /*    (C) Copyright 1987-90, Bit Bucket Software Co., a Delaware Corporation. */
  11. /*                                                                            */
  12. /*                                                                            */
  13. /*                 This module was written by Vince Perriello                 */
  14. /*                                                                            */
  15. /*                                                                            */
  16. /*                   BinkleyTerm Nodelist processing module                    */
  17. /*                                                                            */
  18. /*                                                                            */
  19. /*      For complete    details  of the licensing restrictions, please refer    */
  20. /*      to the License  agreement,  which  is published in its entirety in    */
  21. /*      the MAKEFILE and BT.C, and also contained in the file LICENSE.240.    */
  22. /*                                                                            */
  23. /*      USE  OF THIS FILE IS SUBJECT TO THE  RESTRICTIONS CONTAINED IN THE    */
  24. /*      BINKLEYTERM  LICENSING  AGREEMENT.  IF YOU DO NOT FIND THE TEXT OF    */
  25. /*      THIS    AGREEMENT IN ANY OF THE  AFOREMENTIONED FILES,    OR IF YOU DO    */
  26. /*      NOT HAVE THESE FILES,  YOU  SHOULD  IMMEDIATELY CONTACT BIT BUCKET    */
  27. /*      SOFTWARE CO.    AT ONE OF THE  ADDRESSES  LISTED BELOW.  IN NO EVENT    */
  28. /*      SHOULD YOU  PROCEED TO USE THIS FILE    WITHOUT HAVING    ACCEPTED THE    */
  29. /*      TERMS  OF  THE  BINKLEYTERM  LICENSING  AGREEMENT,  OR  SUCH OTHER    */
  30. /*      AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO.        */
  31. /*                                                                            */
  32. /*                                                                            */
  33. /* You can contact Bit Bucket Software Co. at any one of the following        */
  34. /* addresses:                                                                */
  35. /*                                                                            */
  36. /* Bit Bucket Software Co.          FidoNet  1:104/501, 1:132/491, 1:141/491    */
  37. /* P.O. Box 460398                  AlterNet 7:491/0                            */
  38. /* Aurora, CO 80046               BBS-Net  86:2030/1                        */
  39. /*                                  Internet f491.n132.z1.fidonet.org         */
  40. /*                                                                            */
  41. /* Please feel free to contact us at any time to share your comments about    */
  42. /* our software and/or licensing policies.                                    */
  43. /*                                                                            */
  44. /*--------------------------------------------------------------------------*/
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <signal.h>
  49. #include <ctype.h>
  50. #include <conio.h>
  51. #include <string.h>
  52. #include <errno.h>
  53.  
  54. #ifdef __TOS__
  55. #include <time.h>
  56. #include <ext.h>
  57. #else
  58. #include <sys\types.h>
  59. #include <sys\stat.h>
  60. #include <fcntl.h>
  61. #include <dos.h>
  62. #endif
  63.  
  64. #ifndef LATTICE
  65. #include <io.h>
  66. #endif
  67.  
  68. #include "bink.h"
  69. #include "msgs.h"
  70. #include "com.h"
  71. #include "nodeproc.h"
  72. #include "sbuf.h"
  73.  
  74. #if defined(__TURBOC__) /* || defined(LATTICE) */
  75. typedef size_t off_t;
  76. #endif
  77.  
  78.  
  79. /*
  80.  * Global variables
  81.  */
  82.  
  83.  
  84. NODELISTTYPE nodeListType = VERSION6;
  85.  
  86. char *node_prefix = NULL;            /* Dial Prefix for this node */
  87. int autobaud = 0;                    /* Use highest baudrate when calling out */
  88. int found_zone = 0;                 /* What zone found node is in*/
  89. int found_net = 0;                    /* What net found node is in */
  90. struct _newnode newnodedes;         /* structure in new list     */
  91.  
  92.  
  93. /*
  94.  * Local Variables
  95.  */
  96.  
  97. static const char nodelist_name[] = "NODELIST";        /* Default Nodelist name */
  98. static int last_zone = -1;
  99.  
  100. static const char btnc_idx[] = "INDEX.BNL";
  101. static const char btnc_dat[] = "NODEINFO.BNL";
  102. static const char btnc_dmn[] = "DOMAINS.BNL";
  103.  
  104. /*--------------------------------------------------------
  105.  * NodeList cache
  106.  */
  107.  
  108. typedef enum { MODE_DEFAULT, MODE_KNOWN, MODE_PROTECTED } PROTMODE;
  109.  
  110. /* An entry in the cache */
  111.  
  112. typedef struct {
  113.     ADDR ad;
  114.     int next;        /* Index to next item in cache */
  115.     int prev;        /* Index to previous item */
  116.     struct _newnode des;
  117.     char *nodePrefix;
  118.     PROTMODE mode;
  119.     int assumed;    /* Node to assume */
  120. } NODECACHE;
  121.  
  122. unsigned int cacheSize = 16;        /* Size of cache */
  123. NODECACHE *nodeCache = NULL;        /* The actual cache */
  124. int firstCache = -1;                /* Entry point to used slots */
  125. int lastCache = -1;                    /* Last used slot */
  126. int freeCache = -1;                    /* Entry to unused slots */
  127.  
  128.  
  129. BOOLEAN checkNodeCache(ADDR *ad)
  130. {
  131.     int i;
  132.  
  133.     /* Initialise the cache if not already done so */
  134.  
  135.     if(nodeCache == NULL)
  136.     {
  137.         int i;
  138.         NODECACHE *cache;
  139.  
  140.         if(cacheSize == 0)        /* Cache not active */
  141.             return FALSE;
  142.  
  143.         nodeCache = calloc(sizeof(NODECACHE), cacheSize);
  144.         if(nodeCache == NULL)
  145.             return FALSE;
  146.  
  147.         /* Initialise linked list of free slots */
  148.  
  149.         for(cache = nodeCache, i = 0; i < cacheSize; i++, cache++)
  150.         {
  151.             cache->next = i - 1;
  152.         }
  153.  
  154.         freeCache = cacheSize - 1;
  155.  
  156.     }
  157.  
  158.     /* Search used spaces for address */
  159.  
  160.     i = firstCache;
  161.     while(i >= 0)
  162.     {
  163. #ifdef DEBUG
  164.         if(debugging_log)
  165.             status_line(">nodeCache: %d <- %d -> %d",
  166.                 nodeCache[i].prev, i, nodeCache[i].next);
  167. #endif
  168.         if(memcmp(&nodeCache[i].ad, ad, sizeof(ADDR)) == 0)        /* Structure compare */
  169.         {
  170. #ifdef DEBUG
  171.             if(debugging_log)
  172.                 status_line(">%s found in cache (slot %d)!", Pretty_Addr_Str(ad), i);
  173. #endif
  174.  
  175.             /* Copy the data and return success */
  176.  
  177.             newnodedes = nodeCache[i].des;        /* Structure copy */
  178.             switch(nodeCache[i].mode)
  179.             {
  180.             case MODE_PROTECTED:
  181.                 CurrentOKFile = PROT.rq_OKFile;
  182.                 CurrentFILES = PROT.rq_FILES;
  183.                 CurrentAbout = PROT.rq_About;
  184.                 CurrentReqTemplate = PROT.rq_Template;
  185.                 CurrentNetFiles = PROT.sc_Inbound;
  186.                 CurrentReqLim = PROT.rq_Limit;
  187.                 CurrentByteLim = PROT.byte_Limit;
  188.                 CurrentTimeLim = PROT.time_Limit;
  189.                 break;
  190.             case MODE_KNOWN:
  191.                 CurrentOKFile = KNOWN.rq_OKFile;
  192.                 CurrentFILES = KNOWN.rq_FILES;
  193.                 CurrentAbout = KNOWN.rq_About;
  194.                 CurrentReqTemplate = KNOWN.rq_Template;
  195.                 CurrentNetFiles = KNOWN.sc_Inbound;
  196.                 CurrentReqLim = KNOWN.rq_Limit;
  197.                 CurrentByteLim = KNOWN.byte_Limit;
  198.                 CurrentTimeLim = KNOWN.time_Limit;
  199.                 break;
  200.             case MODE_DEFAULT:
  201.                 CurrentOKFile = DEFAULT.rq_OKFile;     /* Set the default f.req paths */
  202.                 CurrentFILES = DEFAULT.rq_FILES;
  203.                 CurrentAbout = DEFAULT.rq_About;
  204.                 CurrentReqTemplate = DEFAULT.rq_Template;
  205.                 CurrentNetFiles = DEFAULT.sc_Inbound;
  206.                 CurrentReqLim = DEFAULT.rq_Limit;
  207.                 CurrentByteLim = DEFAULT.byte_Limit;
  208.                 CurrentTimeLim = DEFAULT.time_Limit;
  209.                 break;
  210.             }
  211.             found_zone = ad->Zone;
  212.             found_net = ad->Net;
  213.             node_prefix = nodeCache[i].nodePrefix;
  214.             assumed = nodeCache[i].assumed;
  215.  
  216.             /*
  217.              * Move to front of list
  218.              */
  219.  
  220.             if(firstCache != i)    /* Not already at front! */
  221.             {
  222.                 int next;
  223.                 int prev;
  224.  
  225.                 /* unlink */
  226.  
  227.                 next = nodeCache[i].next;
  228.                 prev = nodeCache[i].prev;
  229.                 if(next >= 0)
  230.                     nodeCache[next].prev = prev;
  231.                 else
  232.                     lastCache = prev;
  233.                 if(prev >= 0)
  234.                     nodeCache[prev].next = next;
  235.  
  236.                 nodeCache[i].prev = -1;
  237.                 nodeCache[i].next = firstCache;
  238.                 if(firstCache >= 0)
  239.                     nodeCache[firstCache].prev = i;
  240.                 firstCache = i;
  241.  
  242.             }
  243.  
  244. #ifdef DEBUG
  245.             if(debugging_log)
  246.                 status_line(">NodeCache: free=%d, first=%d, last=%d",
  247.                     freeCache, firstCache, lastCache);
  248. #endif
  249.             return TRUE;
  250.         }
  251.         i = nodeCache[i].next;
  252.     }
  253.  
  254. #ifdef DEBUG
  255.     if(debugging_log)
  256.         status_line(">NodeCache: %s not found", Pretty_Addr_Str(ad));
  257. #endif
  258.     return FALSE;
  259. }
  260.  
  261. /*
  262.  * Add an address to the node cache
  263.  */
  264.  
  265. void addNodeCache(ADDR *ad, PROTMODE mode)
  266. {
  267.     int i;
  268.  
  269.     /* Quit if cache not active */
  270.  
  271.     if(cacheSize == 0)
  272.         return;
  273.  
  274.     /* 1st check it isn't already in! */
  275.  
  276.     if(checkNodeCache(ad))
  277.         return;
  278.  
  279. #ifdef DEBUG
  280.     if(debugging_log)
  281.         status_line(">%s added to cache!", Pretty_Addr_Str(ad));
  282. #endif
  283.  
  284.     /* Find a free slot */
  285.  
  286.     if(freeCache >= 0)
  287.     {
  288.         i = freeCache;                    /* Remove a free slot */
  289.         freeCache = nodeCache[i].next;
  290.         if(lastCache < 0)
  291.             lastCache = i;
  292. #ifdef DEBUG
  293.         if(debugging_log)
  294.             status_line(">NodeCache: Free slot %d", i);
  295. #endif
  296.     }
  297.     else    /* Need to free an old one */
  298.     {
  299.         i = lastCache;
  300.         lastCache = nodeCache[i].prev;
  301.         nodeCache[lastCache].next = -1;
  302. #ifdef DEBUG
  303.         if(debugging_log)
  304.             status_line(">NodeCache: reused slot %d (%s)",
  305.                     i, Pretty_Addr_Str(&nodeCache[i].ad));
  306. #endif
  307.     }
  308.  
  309.     /* We got a free slot */
  310.  
  311.     /* Fill in the info */
  312.  
  313.     nodeCache[i].ad = *ad;                    /* Structure copy */
  314.     nodeCache[i].des = newnodedes;            /* structure copy */
  315.     nodeCache[i].nodePrefix = node_prefix;    /* Dialling prefix */
  316.     nodeCache[i].mode = mode;
  317.     nodeCache[i].assumed = assumed;
  318.  
  319.     /* Link it to front of list */
  320.  
  321.     nodeCache[i].prev = -1;
  322.     nodeCache[i].next = firstCache;
  323.     if(firstCache >= 0)
  324.         nodeCache[firstCache].prev = i;
  325.     firstCache = i;
  326.  
  327. #ifdef DEBUG
  328.     if(debugging_log)
  329.         status_line(">NodeCache: free=%d, first=%d, last=%d",
  330.             freeCache, firstCache, lastCache);
  331. #endif
  332. }
  333.  
  334. /*-----------------------------------------------------------
  335.  * Nodelist locking
  336.  *
  337.  * This keeps the nodelist open during nodelist intensive processing
  338.  *
  339.  * It should only be used when accessing a single domain
  340.  *
  341.  * Also it currently only works for opus newnodelist
  342.  *
  343.  * TRUE enables locking, FALSE disables it
  344.  *
  345.  * Calls may be nested, but there must always be an equal number of each.
  346.  */
  347.  
  348. #ifdef __TOS__
  349. static int fp_nodelist = -1;            /* GEMDOS handle */
  350. #else
  351. static FILE *fp_nodelist = NULL;        /* File handle for nodelist when locked */
  352. #endif
  353.  
  354. static int nodelock = 0;
  355.  
  356. void lock_nodelist(BOOLEAN flag)
  357. {
  358.     if(flag)    /* Lock the nodelist */
  359.         nodelock++;
  360.     else        /* Unlock it */
  361.         if(!--nodelock)
  362. #ifdef __TOS__
  363.             if(fp_nodelist >= 0)
  364.             {
  365.                 Fclose(fp_nodelist);
  366.                 fp_nodelist = -1;
  367.             }
  368. #else
  369.             if(fp_nodelist)
  370.             {
  371.                 fclose(fp_nodelist);
  372.                 fp_nodelist = NULL;
  373.             }
  374. #endif
  375. }
  376.  
  377.  
  378.  
  379. /*
  380.  * STeVeN's fast nodelist lookup
  381.  *
  382.  * Index file is made into 3 sorted lists
  383.  */
  384.  
  385. typedef struct {
  386.     int zone;            /* Zone */
  387.     long netIndex;        /* For Zone... index to net linked list */
  388.     long netCount;        /* Number of nets in this zone */
  389. } ZONESLIST;
  390.  
  391. typedef struct {
  392.     int net;            /* Our net */
  393.     long nodeIndex;        /* Index to nodes list */
  394.     long nodeCount;        /* Number of nodes in this net */
  395. } NETSLIST;
  396.  
  397. typedef struct {
  398.     long node;
  399. } NODESLIST;
  400.  
  401. /*
  402.  * Point lists
  403.  * If consecutive nodes have the same address then it is assumed that
  404.  * they are points and a search should be made in here
  405.  *
  406.  * One of these is maintained for each domain
  407.  *
  408.  * It is assumed that there are not very many point bosses
  409.  * If this assumtion is wrong then a hierarchy similar to the
  410.  * nodes can be done... in fact the same structures could be
  411.  * used except the nodeIndex would point to a POINTBOSSLIST, which
  412.  * would contain node, pointCount, pointIndex
  413.  */
  414.  
  415. typedef struct {
  416.     long zone;
  417.     long net;
  418.     long node;
  419.     long pointCount;
  420.     long pointIndex;
  421. } POINTBOSSLIST;
  422.  
  423. typedef struct {
  424.     int point;        /* The point number.. the position in this table     */
  425.                     /* is added to the bosses index to obtain the record */
  426. } POINTLIST;
  427.  
  428. /*
  429.  * Information for a Domain's nodelist
  430.  */
  431.  
  432. typedef struct s_domainList DOMAINLIST;
  433.  
  434. struct s_domainList {
  435.     DOMAINLIST *next;                    /* Linked list */
  436.  
  437.     char       *domain;                    /* Domain name */
  438.     char       *nodelist_base;            /* Nodelist basename, e.g. "NODELIST", "NESTLIST" */
  439.  
  440.     size_t        record_size;            /* Size of a record in the DAT file */
  441.  
  442.     off_t        index_filesize;            /* Size and time of IDX file used */
  443.     time_t        index_filetime;            /*    to see if a refresh is needed */
  444.     char       *index_filename;            /* Name of IDX file */
  445.  
  446.     NODESLIST  *nodesList;                /* List of nodes in nets */
  447.     NETSLIST   *netsList;                /* List of nets in zones */
  448.     ZONESLIST  *zoneList;                /* List of zones */
  449.     long         nZones;                    /* Number of zones in domain */
  450.     POINTBOSSLIST *pointBossList;        /* List of systems with points */
  451.     long         nPoints;                /* Number of entries in pointBossList */
  452.     POINTLIST  *pointsList;                /* List of point numbers */
  453.  
  454.     long        recordOffset;            /* Offset in dat file */
  455. };
  456.  
  457.  
  458. static DOMAINLIST *domainLists = NULL;    /* Entry to domain linked lists */
  459. static DOMAINLIST *cdl = NULL;            /* Current Domain list */
  460.  
  461.  
  462. /*
  463.  * Function used by QuickSort
  464.  */
  465.  
  466. #ifdef LATTICE
  467. int compareNet(const void *net1, const void *net2)
  468. {
  469.     return ((NETSLIST *)net1)->net - ((NETSLIST *)net2)->net;
  470. }
  471.  
  472. int compareZone(const void *z1, const void *z2)
  473. {
  474.     return ((ZONESLIST *)z1)->zone - ((ZONESLIST *)z2)->zone;
  475. }
  476. #else
  477. int compareNet(const NETSLIST *net1, const NETSLIST *net2)
  478. {
  479.     return net1->net - net2->net;
  480. }
  481.  
  482. int compareZone(const ZONESLIST *z1, const ZONESLIST *z2)
  483. {
  484.     return z1->zone - z2->zone;
  485. }
  486. #endif
  487.  
  488. typedef struct {
  489.     long zoneCount;
  490.     long netCount;
  491.     long bossCount;
  492.     long pointCount;
  493. } BUILDCOUNTS;
  494.  
  495. static void opusCount(BUILDCOUNTS *b, struct _ndi *idx, size_t i)
  496. {
  497.     long lastNet = -1;
  498.  
  499.     idx++;        /* Lose first record */
  500.     i--;
  501.     while(i--)
  502.     {
  503.         if(idx->node == -2)            /* New zone */
  504.         {
  505.             b->zoneCount++;
  506.             b->netCount++;                /* Independent nodes in a zone need a net */
  507.             lastNet = idx->net;
  508.         }
  509.         else if(idx->net != lastNet)
  510.         {
  511.             b->netCount++;
  512.             lastNet = idx->net;
  513.         }
  514.         idx++;
  515.     }
  516. }
  517.  
  518.  
  519. static void countBTNC(BUILDCOUNTS *b, INDEX_BNL *idx, size_t i)
  520. {
  521.     BOOLEAN doingPoint = FALSE;
  522.  
  523. #if 0
  524.     idx++;        /* Lose first record */
  525.     i--;
  526. #endif
  527.     while(i--)
  528.     {
  529.         switch(idx->type)
  530.         {
  531.         case BNL_ZONECOORD:                /* The lack of break's are deliberate */
  532.             b->zoneCount++;
  533.         case BNL_REGCOORD:
  534.         case BNL_NETCOORD:
  535.             b->netCount++;
  536.         case BNL_NODE:
  537.         case BNL_HUB:
  538.             doingPoint = FALSE;
  539.             break;
  540.         case BNL_POINT:
  541.             b->pointCount++;
  542.             if(!doingPoint)
  543.             {
  544.                 b->bossCount++;
  545.                 doingPoint = TRUE;
  546.             }
  547.             break;
  548.         }
  549.         idx++;
  550.     }
  551. }
  552.  
  553. void buildOpus(DOMAINLIST *dlist, struct _ndi *idx, size_t idxCount)
  554. {
  555.     long i = 1;
  556.     long nextZone = 0;
  557.     long nextNet = 0;
  558.     long nextNode = 0;
  559.     long lastNet = -1;
  560.  
  561.     idx++;                /* Lose 1st entry */
  562.     while(i < idxCount)
  563.     {
  564.         if(idx->node == -2)        /* Going to a new zone */
  565.         {
  566.             dlist->zoneList[nextZone].zone = idx->net;
  567.             dlist->zoneList[nextZone].netIndex = (long)nextNet;
  568.             dlist->zoneList[nextZone].netCount = 0;
  569.             nextZone++;
  570.         }
  571.  
  572.         if(idx->net != lastNet)    /* Going to a new net */
  573.         {
  574.             lastNet = idx->net;
  575.             dlist->netsList[nextNet].net = idx->net;
  576.             dlist->netsList[nextNet].nodeIndex = nextNode;
  577.             dlist->netsList[nextNet].nodeCount = 0;
  578.             dlist->zoneList[nextZone-1].netCount++;
  579.             nextNet++;
  580.             idx->node = 0;
  581.         }
  582.         dlist->nodesList[nextNode].node = idx->node;
  583.         dlist->netsList[nextNet-1].nodeCount++;
  584.         nextNode++;
  585.  
  586.         idx++;
  587.         i++;
  588.     }
  589. }
  590.  
  591. void buildBTNC(DOMAINLIST *dlist, INDEX_BNL *idx, size_t idxCount)
  592. {
  593.     long i = 0;
  594.     long nextZone = 0;
  595.     long nextNet = 0;
  596.     long nextNode = 0;
  597.     long nextBoss = 0;
  598.     long nextPoint = 0;
  599.  
  600.     long lastNode = -1;
  601.     long lastNet = -1;
  602.     long lastZone = -1;
  603.     BOOLEAN doingPoint = FALSE;
  604.  
  605. #ifdef DEBUG
  606.     if(debugging_log)
  607.         status_line(">buildBTNC: %s %ld", strToAscii(dlist->domain), (long)idxCount);
  608. #endif
  609.  
  610. #if 0
  611.     idx++;                /* Lose 1st entry */
  612.     i = 1;
  613. #endif
  614.     while(i < idxCount)
  615.     {
  616.         switch(idx->type)
  617.         {
  618.         case BNL_ZONECOORD:                /* The lack of break's are deliberate */
  619.             lastZone = idx->value;
  620.             dlist->zoneList[nextZone].zone = idx->value;
  621.             dlist->zoneList[nextZone].netIndex = (long)nextNet;
  622.             dlist->zoneList[nextZone].netCount = 0;
  623.             nextZone++;
  624.         case BNL_REGCOORD:
  625.         case BNL_NETCOORD:
  626.             lastNet = idx->value;
  627.             dlist->netsList[nextNet].net = idx->value;
  628.             dlist->netsList[nextNet].nodeIndex = nextNode;
  629.             dlist->netsList[nextNet].nodeCount = 0;
  630.             dlist->zoneList[nextZone-1].netCount++;
  631.             nextNet++;
  632.             idx->value = 0;
  633.         case BNL_NODE:
  634.         case BNL_HUB:
  635.             lastNode = idx->value;
  636.             dlist->nodesList[nextNode].node = idx->value;
  637.             dlist->netsList[nextNet-1].nodeCount++;
  638.             nextNode++;
  639.             doingPoint = FALSE;
  640.             break;
  641.         case BNL_POINT:
  642.             dlist->nodesList[nextNode].node = lastNode;
  643.             dlist->netsList[nextNet-1].nodeCount++;
  644.             nextNode++;
  645.  
  646.             if(doingPoint)
  647.             {
  648.                 dlist->pointBossList[nextBoss-1].pointCount++;
  649.             }
  650.             else    /* A boss */
  651.             {
  652.                 dlist->pointBossList[nextBoss].zone = lastZone;
  653.                 dlist->pointBossList[nextBoss].net    = lastNet;
  654.                 dlist->pointBossList[nextBoss].node = lastNode;
  655.                 dlist->pointBossList[nextBoss].pointCount = 1;
  656.                 dlist->pointBossList[nextBoss].pointIndex = nextPoint;
  657.                 doingPoint = TRUE;
  658.                 nextBoss++;
  659.             }
  660.             dlist->pointsList[nextPoint].point = idx->value;
  661.             nextPoint++;
  662.             break;
  663.         }
  664.  
  665.         idx++;
  666.         i++;
  667.     }
  668. }
  669.  
  670.  
  671. /*
  672.  * Construct the sorted lists from the index file
  673.  */
  674.  
  675. static int buildIndex(DOMAINLIST *dlist, void *idxmem, size_t idxCount)
  676. {
  677.     BUILDCOUNTS bc;
  678.  
  679.     /*
  680.      * Count the zones and nets
  681.      */
  682.  
  683.     if(fullscreen)
  684.     {
  685.         sb_fillc (holdwin, ' ');
  686.         sb_move(holdwin, 3, 10);
  687.         sb_puts(holdwin, "Counting Nodes");
  688.         sb_show();
  689.     }
  690.  
  691.     bc.zoneCount = 0;
  692.     bc.netCount = 0;
  693.     bc.bossCount = 0;
  694.     bc.pointCount = 0;
  695.     if(nodeListType == BTNC)
  696.         countBTNC(&bc, idxmem, idxCount);
  697.     else
  698.         opusCount(&bc, idxmem, idxCount);
  699.  
  700. #ifdef DEBUG
  701.     if(debugging_log)
  702.         status_line(">There are %d zones, %d nets, %ld nodes, %d pointnets, %d points",
  703.             bc.zoneCount, bc.netCount, (long)idxCount, bc.bossCount, bc.pointCount);
  704. #endif
  705.  
  706.     if(fullscreen)
  707.     {
  708.         sb_fillc (holdwin, ' ');
  709.         sb_move(holdwin, 3, 10);
  710.         sb_puts(holdwin, "Building lists");
  711.         sb_show();
  712.     }
  713.  
  714.     /*
  715.      * Create memory
  716.      */
  717.  
  718.     if(dlist->zoneList)
  719.     {
  720.         free(dlist->zoneList);
  721.         dlist->zoneList = NULL;
  722.         dlist->netsList = NULL;
  723.         dlist->nodesList = NULL;
  724.         dlist->pointsList = NULL;
  725.         dlist->pointBossList = NULL;
  726.     }
  727.  
  728.     dlist->zoneList = malloc(bc.zoneCount  * sizeof(ZONESLIST)       +
  729.                              bc.netCount   * sizeof(NETSLIST)       +
  730.                              bc.bossCount  * sizeof(POINTBOSSLIST) +
  731.                              bc.pointCount * sizeof(POINTLIST) );
  732.  
  733.     if(dlist->zoneList)
  734.     {
  735.         dlist->netsList      =        (NETSLIST *)(dlist->zoneList      + bc.zoneCount);
  736.         dlist->pointBossList = (POINTBOSSLIST *)(dlist->netsList      + bc.netCount );
  737.         dlist->pointsList     =       (POINTLIST *)(dlist->pointBossList + bc.bossCount);
  738.  
  739.         dlist->nodesList = (NODESLIST *)idxmem;
  740.  
  741.         dlist->nZones = bc.zoneCount;
  742.         dlist->nPoints = bc.bossCount;
  743.  
  744.         if(nodeListType == BTNC)
  745.             buildBTNC(dlist, idxmem, idxCount);
  746.         else
  747.             buildOpus(dlist, idxmem, idxCount);
  748.  
  749.  
  750.         if(fullscreen)
  751.         {
  752.             sb_fillc (holdwin, ' ');
  753.             sb_move(holdwin, 3, 10);
  754.             sb_puts(holdwin, "Sorting Nets");
  755.             sb_show();
  756.         }
  757.  
  758.         /* Sort the Zone list */
  759.  
  760.         qsort(dlist->zoneList, dlist->nZones, sizeof(ZONESLIST), compareZone);
  761.  
  762.         /* Sort Nets */
  763.  
  764.         {
  765.             int z = 0;
  766.             while(z < dlist->nZones)
  767.             {
  768.                 long net;
  769.                 long count;
  770.  
  771.  
  772.                 net = dlist->zoneList[z].netIndex;
  773.                 count = dlist->zoneList[z].netCount;
  774.  
  775.                 qsort(&dlist->netsList[net], count, sizeof(NETSLIST), compareNet);
  776.  
  777. #ifdef DEBUG
  778.                 if(debugging_log)
  779.                 {
  780.                     /* Display information */
  781.  
  782.                     status_line(">Zone %d, %d nets at %d",
  783.                         dlist->zoneList[z].zone, count, net);
  784.  
  785.                     while(count--)
  786.                     {
  787.                         status_line(">Net %d, %d nodes at %ld",
  788.                             dlist->netsList[net].net,
  789.                             dlist->netsList[net].nodeCount,
  790.                             (long) dlist->netsList[net].nodeIndex);
  791.  
  792.  
  793.                         net++;
  794.                     }
  795.                 }
  796. #endif
  797.  
  798.                 z++;
  799.             }
  800. #ifdef DEBUG
  801.             if(debugging_log)
  802.             {
  803.                 POINTBOSSLIST *pb;
  804.                 long count;
  805.  
  806.                 count = dlist->nPoints;
  807.                 status_line(">%d Point systems", count);
  808.                 pb = dlist->pointBossList;
  809.                 while(count--)
  810.                 {
  811.                     status_line(">%d:%d/%d has %d points at %d",
  812.                         pb->zone, pb->net, pb->node, pb->pointCount, pb->pointIndex);
  813.                 }
  814.             }
  815. #endif
  816.         }
  817.         realloc(idxmem, idxCount * sizeof(NODESLIST));
  818.         return 0;
  819.     }
  820.     else
  821.         status_line(msgtxt[M_NODELIST_MEM]);
  822.  
  823.     return -1;
  824. }
  825.  
  826. /*
  827.  * read the index file in
  828.  */
  829.  
  830. static int makeVersion6Index(DOMAINLIST *dlist)
  831. {
  832.     struct stat idxstat;
  833.     int error = -1;
  834.  
  835. #ifdef DEBUG
  836.     if(debugging_log)
  837.         status_line(">Reading index file %s", strToAscii(dlist->index_filename));
  838. #endif
  839.     if(fullscreen)
  840.     {
  841.         sb_fillc (holdwin, ' ');
  842.         sb_move(holdwin, 3, 2);
  843.         sb_puts(holdwin, "Reading:");
  844.         sb_move(holdwin, 4, 2);
  845.         sb_puts(holdwin, dlist->index_filename);
  846.         sb_show();
  847.     }
  848.  
  849.     errno = 0;
  850.     if(!stat(dlist->index_filename, &idxstat))
  851.     {
  852.         struct _ndi *idxmem;
  853.  
  854.         idxmem = malloc(idxstat.st_size);
  855.         if(idxmem)
  856.         {
  857. #if defined(USEBUFFEREDFILE)
  858.             FILE *fd = fopen(dlist->index_filename, "rb");
  859.             if(fd)
  860.             {
  861.                 fread(idxmem, idxstat.st_size, 1, fd);
  862.                 fclose(fd);
  863. #elif defined(__TOS__)
  864.             int fp = (int) Fopen(dlist->index_filename, FO_READ);
  865.             if(fp >= 0)
  866.             {
  867.                 if(Fread(fp, idxstat.st_size, idxmem) != idxstat.st_size)
  868.                     errno = -1;
  869.                 Fclose(fp);
  870. #else
  871.             int fp = open(dlist->index_filename, O_RDONLY|O_BINARY);
  872.             if(fp >= 0)
  873.             {
  874.                 read(fp, idxmem, idxstat.st_size);
  875.                 close(fp);
  876. #endif
  877.                 if(errno == 0)
  878.                 {
  879.                     error = buildIndex(dlist, idxmem, idxstat.st_size / sizeof(struct _ndi));
  880.                     if(!error)
  881.                     {
  882.                         dlist->index_filesize = idxstat.st_size;
  883.                         dlist->index_filetime = idxstat.st_mtime;
  884.                     }
  885.                 }
  886.             }
  887.             if(error)    /* Otherwise buildIndex has used it */
  888.                 free(idxmem);
  889.         }
  890.         else
  891.             status_line(msgtxt[M_NODELIST_MEM]);
  892.     }
  893.  
  894.     if(fullscreen)
  895.     {
  896.         sb_fillc (holdwin, ' ');
  897.         sb_show();
  898.     }
  899.  
  900.     return error;
  901. }
  902.  
  903. /*
  904.  * Find a BTNC Domain structure
  905.  */
  906.  
  907. DOMAINS_BNL *findBTNCDomain(DOMAINLIST *dlist, DOMAINS_BNL *dest)
  908. {
  909.     FILE *fd;
  910.     char buffer[FMSIZE];
  911.  
  912.     sprintf(buffer, "%s%s", net_info, btnc_dmn);
  913.  
  914. #ifdef DEBUG
  915.     if(debugging_log)
  916.         status_line(">Reading %s", buffer);
  917. #endif
  918.  
  919.     fd = fopen(buffer, "rb");
  920.     if(fd)
  921.     {
  922.         while(fread(dest, sizeof(DOMAINS_BNL), 1, fd) == 1)
  923.         {
  924. #ifdef DEBUG
  925.             if(debugging_log)
  926.                 status_line(">domain.bnl: %s %s %d %ld %ld",
  927.                     dest->name, dest->listfile, dest->zone,
  928.                     dest->startoffset, dest->length);
  929. #endif
  930.             if((dlist->domain == NULL) || (stricmp(dlist->domain, dest->name) == 0))
  931.             {
  932. #ifdef DEBUG
  933.                 if(debugging_log)
  934.                     status_line(">found Domain: %s", strToAscii(dlist->domain));
  935. #endif
  936.                 fclose(fd);
  937.                 return dest;
  938.             }
  939.         }
  940.         
  941.         fclose(fd);
  942.     }
  943.     else
  944.         status_line (msgtxt[M_UNABLE_TO_OPEN], buffer);
  945.  
  946.     return NULL;
  947. }
  948.  
  949. static int makeBTNCIndex(DOMAINLIST *dlist)
  950. {
  951.     struct stat idxstat;
  952.     int error = -1;
  953.     DOMAINS_BNL domain;
  954.  
  955. #ifdef DEBUG
  956.     if(debugging_log)
  957.         status_line(">Reading index file %s, domain %s",
  958.             strToAscii(dlist->index_filename), strToAscii(dlist->domain));
  959. #endif
  960.  
  961.     /*
  962.      * First look in the domain file to find where to load
  963.      */
  964.  
  965.     if(findBTNCDomain(dlist, &domain) == NULL)
  966.         return -1;
  967.  
  968.     dlist->recordOffset = (long) (domain.startoffset / sizeof(INDEX_BNL));
  969.  
  970.     if(fullscreen)
  971.     {
  972.         sb_fillc (holdwin, ' ');
  973.         sb_move(holdwin, 3, 2);
  974.         sb_puts(holdwin, "Scanning:");
  975.         sb_move(holdwin, 4, 2);
  976.         sb_puts(holdwin, dlist->index_filename);
  977.         sb_move(holdwin, 5, 2);
  978.         sb_puts(holdwin, dlist->domain);
  979.         sb_show();
  980.     }
  981.  
  982.     errno = 0;
  983.     if(!stat(dlist->index_filename, &idxstat))
  984.     {
  985.         INDEX_BNL *idxmem;
  986.         size_t size = domain.length * sizeof(INDEX_BNL);
  987.  
  988.         idxmem = malloc(size);
  989.         if(idxmem)
  990.         {
  991. #if defined(USEBUFFEREDFILE)
  992.             FILE *fd = fopen(dlist->index_filename, "rb");
  993.             if(fd)
  994.             {
  995.                 fseek(fd, domain.startoffset, SEEK_SET);
  996.                 fread(idxmem, size, 1, fd);
  997.                 fclose(fd);
  998. #elif defined(__TOS__)
  999.             int fp = (int) Fopen(dlist->index_filename, FO_READ);
  1000.             if(fp >= 0)
  1001.             {
  1002.                 if(Fseek(domain.startoffset, fp, SEEK_SET) != domain.startoffset)
  1003.                     errno = -1;
  1004.                 else
  1005.                 if(Fread(fp, size, idxmem) != size)
  1006.                     errno = -1;
  1007.                 Fclose(fp);
  1008. #else
  1009.             int fp = open(dlist->index_filename, O_RDONLY|O_BINARY);
  1010.             if(fp >= 0)
  1011.             {
  1012.                 lseek(fp, domain.startoffset, SEEK_SET);
  1013.                 read(fp, idxmem, size);
  1014.                 close(fp);
  1015. #endif
  1016.                 if(errno == 0)
  1017.                 {
  1018.                     error = buildIndex(dlist, idxmem, domain.length);
  1019.                     if(!error)
  1020.                     {
  1021.                         dlist->index_filesize = idxstat.st_size;
  1022.                         dlist->index_filetime = idxstat.st_mtime;
  1023.                     }
  1024.                 }
  1025.             }
  1026.             if(error)    /* Otherwise buildIndex has used it */
  1027.                 free(idxmem);
  1028.         }
  1029.         else
  1030.             status_line(msgtxt[M_NODELIST_MEM]);
  1031.     }
  1032.  
  1033.     if(fullscreen)
  1034.     {
  1035.         sb_fillc (holdwin, ' ');
  1036.         sb_show();
  1037.     }
  1038.  
  1039.     return error;
  1040. }
  1041.  
  1042. static int makeIndex(DOMAINLIST *dlist)
  1043. {
  1044.     if(nodeListType == VERSION6)
  1045.         return makeVersion6Index(dlist);
  1046.     else
  1047.         return makeBTNCIndex(dlist);
  1048. }
  1049.  
  1050.  
  1051. /*-------------------------------------------------
  1052.  * Actually get bytes from NODELIST.DAT
  1053.  */
  1054.  
  1055. static BOOLEAN opusGetInfo (DOMAINLIST *dlist, size_t recno)
  1056. {
  1057.     long nodeoff;                                 /* Offset into NODELIST.DAT  */
  1058.     char temp[80];                                 /* where we build filenames  */
  1059. #ifdef __TOS__
  1060.     int stream;
  1061.  
  1062.     /* actual file offset */
  1063.     nodeoff = (long) recno * dlist->record_size;
  1064.  
  1065.     if(!nodelock || (fp_nodelist < 0))
  1066.     {
  1067.         strcpy (temp, net_info);                    /* take nodelist path         */
  1068.         strcat (temp, dlist->nodelist_base);        /* add in the file name        */
  1069.         strcat (temp, ".DAT");                        /* add in the file name      */
  1070.         if ((stream = (int) Fopen (temp, FO_READ)) < 0)    /* OK, let's open the file     */
  1071.         {
  1072.             status_line (msgtxt[M_UNABLE_TO_OPEN], temp);
  1073.             return FALSE;
  1074.         }
  1075.         if(nodelock)
  1076.             fp_nodelist = stream;
  1077.     }
  1078.     else
  1079.         stream = fp_nodelist;
  1080.  
  1081.     if(Fseek (nodeoff, stream, SEEK_SET) != nodeoff)    /* try to point at record      */
  1082.     {
  1083.         status_line (msgtxt[M_NODELIST_SEEK_ERR], temp);
  1084.         if(!nodelock)
  1085.             Fclose (stream);
  1086.         return FALSE;
  1087.     }
  1088.  
  1089.     if(Fread (stream, sizeof(newnodedes), &newnodedes) != sizeof(newnodedes))
  1090.     {
  1091.         status_line (msgtxt[M_NODELIST_REC_ERR], temp);
  1092.         if(!nodelock)
  1093.             Fclose (stream);
  1094.         return FALSE;
  1095.     }
  1096.     if(!nodelock)
  1097.         Fclose (stream);
  1098. #else
  1099.     FILE *stream;
  1100.  
  1101.     /* actual file offset */
  1102.     nodeoff = (long) recno * dlist->record_size;
  1103.  
  1104.     if(!nodelock || (fp_nodelist == NULL))
  1105.     {
  1106.         strcpy (temp, net_info);                        /* take nodelist path         */
  1107.         strcat (temp, dlist->nodelist_base);            /* add in the file name        */
  1108.         strcat (temp, ".DAT");                            /* add in the file name      */
  1109.         if ((stream = fopen (temp, read_binary)) == NULL)     /* OK, let's open the file   */
  1110.         {
  1111.             status_line (msgtxt[M_UNABLE_TO_OPEN], temp);
  1112.             return FALSE;
  1113.         }
  1114.         if(nodelock)
  1115.             fp_nodelist = stream;
  1116.     }
  1117.     else
  1118.         stream = fp_nodelist;
  1119.  
  1120.     if (fseek (stream, nodeoff, SEEK_SET))         /* try to point at record      */
  1121.     {
  1122.         status_line (msgtxt[M_NODELIST_SEEK_ERR], temp);
  1123.         if(!nodelock)
  1124.             fclose (stream);
  1125.         return FALSE;
  1126.     }
  1127.  
  1128.     if (!fread (&newnodedes, sizeof (newnodedes), 1, stream))
  1129.     {
  1130.         status_line (msgtxt[M_NODELIST_REC_ERR], temp);
  1131.         if(!nodelock)
  1132.             fclose (stream);
  1133.         return FALSE;
  1134.     }
  1135.     if(!nodelock)
  1136.         fclose (stream);
  1137. #endif
  1138.  
  1139.     /* Do any conversion */
  1140.  
  1141.     if(newnodedes.NodeFlags & B_CrashM)
  1142.         newnodedes.NodeFlags = B_CM;
  1143.     else
  1144.         newnodedes.NodeFlags = 0;
  1145.  
  1146.     return TRUE;
  1147. }
  1148.  
  1149. static BOOLEAN BTNCGetInfo (DOMAINLIST *dlist, size_t recno, ADDR *addr)
  1150. {
  1151.     long nodeoff;                                 /* Offset into NODELIST.DAT  */
  1152.     char temp[80];                                 /* where we build filenames  */
  1153.     NODEINFO_BNL info;
  1154.  
  1155. #ifdef __TOS__
  1156.     int stream;
  1157.  
  1158.     /* actual file offset */
  1159.  
  1160.     recno += dlist->recordOffset;
  1161.     nodeoff = (long) recno * dlist->record_size;
  1162.  
  1163.     if(!nodelock || (fp_nodelist < 0))
  1164.     {
  1165.         strcpy (temp, net_info);                    /* take nodelist path         */
  1166.         strcat (temp, btnc_dat);            /* add in the file name        */
  1167.         if ((stream = (int) Fopen (temp, FO_READ)) < 0)    /* OK, let's open the file     */
  1168.         {
  1169.             status_line (msgtxt[M_UNABLE_TO_OPEN], temp);
  1170.             return FALSE;
  1171.         }
  1172.         if(nodelock)
  1173.             fp_nodelist = stream;
  1174.     }
  1175.     else
  1176.         stream = fp_nodelist;
  1177.  
  1178.     if(Fseek (nodeoff, stream, SEEK_SET) != nodeoff)    /* try to point at record      */
  1179.     {
  1180.         status_line (msgtxt[M_NODELIST_SEEK_ERR], temp);
  1181.         if(!nodelock)
  1182.             Fclose (stream);
  1183.         return FALSE;
  1184.     }
  1185.  
  1186.     if(Fread (stream, sizeof(info), &info) != sizeof(info))
  1187.     {
  1188.         status_line (msgtxt[M_NODELIST_REC_ERR], temp);
  1189.         if(!nodelock)
  1190.             Fclose (stream);
  1191.         return FALSE;
  1192.     }
  1193.     if(!nodelock)
  1194.         Fclose (stream);
  1195. #else
  1196.     FILE *stream;
  1197.  
  1198.     /* actual file offset */
  1199.  
  1200.     recno += dlist->recordOffset;
  1201.     nodeoff = (long) recno * dlist->record_size;
  1202.  
  1203.     if(!nodelock || (fp_nodelist == NULL))
  1204.     {
  1205.         strcpy (temp, net_info);                /* take nodelist path         */
  1206.         strcat (temp, btnc_dat);            /* add in the file name        */
  1207.         if ((stream = fopen (temp, read_binary)) == NULL)     /* OK, let's open the file   */
  1208.         {
  1209.             status_line (msgtxt[M_UNABLE_TO_OPEN], temp);
  1210.             return FALSE;
  1211.         }
  1212.         if(nodelock)
  1213.             fp_nodelist = stream;
  1214.     }
  1215.     else
  1216.         stream = fp_nodelist;
  1217.  
  1218.     if (fseek (stream, nodeoff, SEEK_SET))         /* try to point at record      */
  1219.     {
  1220.         status_line (msgtxt[M_NODELIST_SEEK_ERR], temp);
  1221.         if(!nodelock)
  1222.             fclose (stream);
  1223.         return FALSE;
  1224.     }
  1225.  
  1226.     if (!fread (&info, sizeof(info), 1, stream))
  1227.     {
  1228.         status_line (msgtxt[M_NODELIST_REC_ERR], temp);
  1229.         if(!nodelock)
  1230.             fclose (stream);
  1231.         return FALSE;
  1232.     }
  1233.     if(!nodelock)
  1234.         fclose (stream);
  1235. #endif
  1236.  
  1237.     /* Convert information into newnodedes */
  1238.  
  1239.     newnodedes.NetNumber = addr->Net;
  1240.     newnodedes.NodeNumber = addr->Node;
  1241.     newnodedes.Cost = 0;
  1242.     strncpy(newnodedes.SystemName, info.sysname, 34);
  1243.     strncpy(newnodedes.PhoneNumber, info.phone, 40);
  1244.     strncpy(newnodedes.MiscInfo, info.location, 30);
  1245.     newnodedes.Password[0] = 0;
  1246.     newnodedes.RealCost = 0;
  1247.     newnodedes.HubNode = info.hubnode;
  1248.     newnodedes.BaudRate = info.maxbaud;
  1249.     newnodedes.ModemType = info.modemtype;
  1250.     newnodedes.NodeFlags = info.flags;
  1251.     newnodedes.NodeFiller = 0;
  1252.  
  1253.     return TRUE;
  1254. }
  1255.  
  1256. static BOOLEAN getNodeListInfo(DOMAINLIST *dlist, size_t recno, ADDR *addr)
  1257. {
  1258. #ifdef DEBUG
  1259.     if(debugging_log)
  1260.         status_line(">getNodeListInfo(%s,%ld,%s)",
  1261.             strToAscii(dlist->domain), (long)recno, Pretty_Addr_Str(addr));
  1262. #endif
  1263.     switch(nodeListType)
  1264.     {
  1265.     case BTNC:
  1266.         return BTNCGetInfo(dlist, recno, addr);
  1267.     case VERSION6:
  1268.         return opusGetInfo(dlist, recno+1);
  1269.     }
  1270.     return FALSE;
  1271. }
  1272.  
  1273.  
  1274. static char *get_nodelist_name(char *domain)
  1275. {
  1276.     int i;
  1277.  
  1278.     for (i = 0; domain_name[i] != NULL; i++)
  1279.     {
  1280.         if (domain_name[i] == domain)
  1281.         {
  1282.             if(domain_nodelist[i] == NULL)
  1283.                 return nodelist_name;
  1284.             else
  1285.                 return domain_nodelist[i];
  1286.         }
  1287.     }
  1288.  
  1289.     return nodelist_name;
  1290. }
  1291.  
  1292.  
  1293.  
  1294. BOOLEAN checkIDX(DOMAINLIST *dlist)
  1295. {
  1296.     struct stat idxstat;
  1297.  
  1298.     if(dlist->index_filesize == 0L)
  1299.         return TRUE;
  1300.  
  1301.     if(stat(dlist->index_filename, &idxstat))
  1302.     {    /* Doesn't exist! */
  1303.         return TRUE;
  1304.     }
  1305.     else
  1306.     {
  1307.         if( (dlist->index_filesize != idxstat.st_size) ||    /* It has changed */
  1308.             (dlist->index_filetime != idxstat.st_mtime) )
  1309.         {
  1310.             status_line (msgtxt[M_REFRESH_NODELIST]);
  1311.             return TRUE;
  1312.         }
  1313.     }
  1314.  
  1315.     return FALSE;    /* Doesn't need reading */
  1316. }
  1317.  
  1318.  
  1319. /*------------------------------------------------------
  1320.  * Nodelist lookup functions
  1321.  */
  1322.  
  1323. static int nextZone(DOMAINLIST *dlist)
  1324. {
  1325.     static int zonePos = 0;
  1326.  
  1327.     if(no_zones)
  1328.         return -1;
  1329.  
  1330.     if (!dlist->zoneList)
  1331.         return -1;
  1332.         
  1333.     if(last_zone == -1)                    /* reset to 1st zone */
  1334.         zonePos = 0;
  1335.     else if(zonePos >= dlist->nZones)        /* We've finished */
  1336.     {
  1337.         zonePos = 0;
  1338.         return -1;
  1339.     }
  1340.  
  1341.     last_zone = dlist->zoneList[zonePos++].zone;    /* Get the value and increment pointer */
  1342.     return last_zone;
  1343. }
  1344.  
  1345. static BOOLEAN nodeLookup(ADDR *opus_addr, int have_boss_data)
  1346. {
  1347.     int zoneCount;
  1348.     DOMAINLIST *dlist = domainLists;
  1349.  
  1350.     newnodedes.NetNumber = newnodedes.NodeNumber = 0;
  1351.  
  1352.     /* Don't even TRY looking for points! */
  1353.  
  1354.     if((nodeListType == VERSION6) && opus_addr->Point && ((int)opus_addr->Zone != -1))
  1355.         return 0;
  1356.  
  1357.     /*
  1358.      * Find our domainList and/or read it in
  1359.      */
  1360.  
  1361.     /*
  1362.      * Look for existing list
  1363.      */
  1364.  
  1365.     while(dlist)
  1366.     {
  1367.         if(opus_addr->Domain == NULL)    /* Not using domains */
  1368.             break;
  1369.         if(dlist->domain == opus_addr->Domain)
  1370.             break;
  1371.  
  1372.         dlist = dlist->next;
  1373.     }
  1374.  
  1375.     /*
  1376.      * Create a new domainList
  1377.      */
  1378.  
  1379.     if(dlist == NULL)
  1380.     {
  1381.         char buffer[FMSIZE];
  1382.  
  1383.         dlist = calloc(sizeof(DOMAINLIST), 1);
  1384.         if(dlist == NULL)
  1385.         {
  1386.             status_line(msgtxt[M_NODELIST_MEM]);
  1387.             return 0;
  1388.         }
  1389.  
  1390.         /* fill in the values */
  1391.  
  1392.         dlist->domain = opus_addr->Domain;
  1393.  
  1394.         strcpy (buffer, net_info);                /* take nodelist path          */
  1395.  
  1396.         if(nodeListType == BTNC)
  1397.         {
  1398.             strcat(buffer, btnc_idx);
  1399.         }
  1400.         else    /* Assume version 6 */
  1401.         {
  1402.             dlist->nodelist_base = get_nodelist_name(opus_addr->Domain);
  1403.  
  1404.             strcat (buffer, dlist->nodelist_base);    /* add in the file name  */
  1405.             strcat (buffer, ".IDX");                /* add in the file ext      */
  1406.         }
  1407.         dlist->index_filename = strdup(buffer);
  1408.  
  1409.         /* All other values are 0 or NULL from calloc() */
  1410.  
  1411.         /* Link to start of list */
  1412.  
  1413.         dlist->next = domainLists;
  1414.         domainLists = dlist;
  1415. #ifdef DEBUG
  1416.         if(debugging_log)
  1417.             status_line(">Made DOMAINLIST %s %s %s",
  1418.                 strToAscii(dlist->domain),
  1419.                 strToAscii(dlist->nodelist_base),
  1420.                 strToAscii(dlist->index_filename));
  1421. #endif
  1422.     }
  1423.  
  1424.     cdl = dlist;        /* Make domainList current */
  1425.  
  1426.     /*
  1427.      * see if the Index needs to be re-read
  1428.      */
  1429.  
  1430.  
  1431.     if(checkIDX(dlist))
  1432.     {
  1433.         int error = makeIndex(dlist);
  1434.  
  1435.         if(error
  1436.           && (have_boss_data != 2)
  1437.           && ((int)opus_addr->Zone != -1)
  1438.           )
  1439.           if (dlist->zoneList)
  1440.             {
  1441.                     status_line (msgtxt[M_UNABLE_TO_OPEN], dlist->index_filename);
  1442.                     return (0);                            /* no file, no work to do      */
  1443.             }
  1444.         else
  1445.             return(0);
  1446.  
  1447.         /*
  1448.          * Now take into account that the .DAT file can be bigger than we
  1449.          * really expect it to be.    Just take the number of records, and
  1450.          * divide into the size of the .DAT file to find the true record size
  1451.          */
  1452.  
  1453.         {
  1454.             struct stat f;
  1455.             char temp[FMSIZE];
  1456.  
  1457.             strcpy (temp, net_info);         /* take nodelist path          */
  1458.             if(nodeListType == VERSION6)
  1459.             {
  1460.                 strcat (temp, dlist->nodelist_base);     /* add in the file name      */
  1461.                 strcat (temp, ".DAT");             /* add in the file name      */
  1462.                 if (!stat(temp, &f))
  1463.                     dlist->record_size = f.st_size /
  1464.                             (dlist->index_filesize / sizeof(struct _ndi));
  1465.                 else
  1466.                     dlist->record_size = 0;
  1467.             }
  1468.             else    /* BTNC */
  1469.             {
  1470.                 strcat(temp, btnc_dat);
  1471.                 if(!stat(temp, &f))
  1472.                     dlist->record_size = f.st_size /
  1473.                             (dlist->index_filesize / sizeof(INDEX_BNL));
  1474.                 else
  1475.                     dlist->record_size = 0;
  1476.             }
  1477.         }
  1478.     }
  1479.  
  1480.     if ((int)opus_addr->Zone == -1)
  1481.         return (nextZone (dlist));
  1482.     else if ((alias[0].ad.Zone == 0) || no_zones)
  1483.         opus_addr->Zone = 0;
  1484.  
  1485.     /*
  1486.      * Notes: This can be changed to binary searches once the nodelists
  1487.      *          are sorted
  1488.      */
  1489.  
  1490.     /* Search for our Zone... assumes zones are sorted */
  1491.  
  1492.     zoneCount = 0;
  1493.     while( (zoneCount < dlist->nZones) && (dlist->zoneList[zoneCount].zone <= opus_addr->Zone))
  1494.     {
  1495.         if( (opus_addr->Zone == 0) || (dlist->zoneList[zoneCount].zone == opus_addr->Zone))
  1496.         {
  1497.             /* Search for our Net */
  1498.             /* The nets are sorted so we can do a binary search */
  1499.  
  1500.             /* Binary search */
  1501.  
  1502.             size_t first = dlist->zoneList[zoneCount].netIndex;
  1503.             size_t last = first + dlist->zoneList[zoneCount].netCount;
  1504.  
  1505.             while(first != last)
  1506.             {
  1507.                 size_t netIndex = (first + last) / 2;
  1508.                 int diff = dlist->netsList[netIndex].net - opus_addr->Net;
  1509. #ifdef DEBUG
  1510.                 if(debugging_log)
  1511.                     status_line(">Binary Search: first=%d,mid=%d,last=%d,diff=%d",
  1512.                         (int)first,(int)netIndex,(int)last,diff);
  1513. #endif
  1514.                 if(diff == 0)
  1515.                 {
  1516.                     /*
  1517.                      * Handle the unusual case of there being more than
  1518.                      * one entry for a net.
  1519.                      *
  1520.                      * Backtrack to 1st occurence of this net
  1521.                      */
  1522. #ifdef DEBUG
  1523.                     if(debugging_log)
  1524.                         status_line(">Binary Search: found net %d", opus_addr->Net);
  1525. #endif
  1526.  
  1527.                     while(netIndex && (dlist->netsList[netIndex-1].net == opus_addr->Net))
  1528.                         netIndex--;
  1529.                     while(dlist->netsList[netIndex].net == opus_addr->Net)
  1530.                     {
  1531.  
  1532.                         /* Search for our node */
  1533.  
  1534.                         size_t nodeIndex = dlist->netsList[netIndex].nodeIndex;
  1535.                         size_t nodeCount = dlist->netsList[netIndex].nodeCount;
  1536.  
  1537.                         while(nodeCount--)
  1538.                         {
  1539.                             if(dlist->nodesList[nodeIndex].node == opus_addr->Node)
  1540.                             {
  1541.  
  1542. #ifdef DEBUG
  1543.                                 if(debugging_log)
  1544.                                     status_line(">Binary Search: found node %d.%d", opus_addr->Node, opus_addr->Point);
  1545. #endif
  1546.                             /* We found the node... check for points */
  1547.  
  1548. #ifndef NOPOINTS
  1549.                                 if(opus_addr->Point)
  1550.                                 {
  1551. #ifdef DEBUG
  1552.                                     if(debugging_log)
  1553.                                         status_line(">Searching point %d", opus_addr->Point);
  1554. #endif
  1555.                                     if(dlist->pointBossList &&
  1556.                                        (dlist->nodesList[++nodeIndex].node == opus_addr->Node))
  1557.                                     {
  1558.                                         POINTBOSSLIST *pblist = dlist->pointBossList;
  1559.                                         long i;
  1560.  
  1561. #ifdef DEBUG
  1562.                                         if(debugging_log)
  1563.                                             status_line(">nPoints = %d", dlist->nPoints);
  1564. #endif
  1565.                                         i = dlist->nPoints;
  1566.                                         while(i--)
  1567.                                         {
  1568.                                             if( (pblist->zone == opus_addr->Zone)
  1569.                                              && (pblist->net  == opus_addr->Net)
  1570.                                              && (pblist->node == opus_addr->Node) )
  1571.                                             {
  1572.                                                 POINTLIST *plist = &dlist->pointsList[pblist->pointIndex];
  1573.                                                 long count = pblist->pointCount;
  1574.  
  1575. #ifdef DEBUG
  1576.                                                 if(debugging_log)
  1577.                                                     status_line(">Found boss with %d points", count);
  1578. #endif
  1579.                                                 while(count--)
  1580.                                                 {
  1581.                                                     if(plist->point == opus_addr->Point)
  1582.                                                     {
  1583. #ifdef DEBUG
  1584.                                                         if(debugging_log)
  1585.                                                             status_line(">Found point %d", opus_addr->Point);
  1586. #endif
  1587.                                                         found_zone = opus_addr->Zone;     /* Keep track of found zone */
  1588.                                                         found_net  = opus_addr->Net;     /* Keep track of found net  */
  1589.  
  1590.                                                         return getNodeListInfo(dlist, nodeIndex, opus_addr);
  1591.                                                     }
  1592.                                                     nodeIndex++;
  1593.                                                     plist++;
  1594.                                                 }
  1595.  
  1596.                                                 break;
  1597.                                             }
  1598.                                             pblist++;
  1599.                                         }
  1600.                                     }
  1601.  
  1602.                                     /* There are no points, or point was not found */
  1603.  
  1604.                                     return 0;
  1605.                                 }
  1606. #endif
  1607.  
  1608.                                 /* A straight node... return the info */
  1609.  
  1610.                                 found_zone = opus_addr->Zone;     /* Keep track of found zone */
  1611.                                 found_net  = opus_addr->Net;     /* Keep track of found net  */
  1612.  
  1613.                                 return getNodeListInfo(dlist, nodeIndex, opus_addr);
  1614.                             }
  1615.  
  1616.                             nodeIndex++;
  1617.                         }
  1618.                         netIndex++;
  1619.                     }
  1620.                     break;    /* Node not found in this net/zone */
  1621.                 }
  1622.                 else if(diff < 0)
  1623.                     first = netIndex + 1;
  1624.                 else /* if(diff > 0) */
  1625.                     last = netIndex;
  1626.             }
  1627. #if 0
  1628.             if(opus_addr->Zone != 0)
  1629.                 break;
  1630. #endif
  1631.         }
  1632.         zoneCount++;
  1633.     }
  1634.  
  1635.     /* Node was not in nodelist! */
  1636.  
  1637.     return FALSE;
  1638. }
  1639.  
  1640.  
  1641. /*----------------------------------------------------
  1642.  * I moved this here from misc.c
  1643.  */
  1644.  
  1645. long cost_of_call (long s, long e)
  1646. {
  1647.     long a;
  1648.  
  1649.     if (usecallslots)
  1650.         return (0L);
  1651.         
  1652.     a = e - s;
  1653.     a = (a + 59) / 60;
  1654.    
  1655.    return (a * newnodedes.RealCost);
  1656. }
  1657.  
  1658. /*---------------------------------------------------------------------------*/
  1659. /* NODEPROC                                                                  */
  1660. /* Find nodelist entry and set baud to nodelist baud for dialing out         */
  1661. /*---------------------------------------------------------------------------*/
  1662.  
  1663. int nodeproc (char *nodeaddr)
  1664. {
  1665.    ADDR opus_addr;
  1666.    char *c;
  1667.  
  1668.    c = skip_blanks (nodeaddr);                     /* get rid of the blanks      */
  1669.    if (!find_address (c, &opus_addr))
  1670.       {
  1671.       return (0);
  1672.       }
  1673.    if (!nodefind (&opus_addr, 1))  /* if we can't find the node */
  1674.       return (0);                                 /* go away now               */
  1675.    status_line (msgtxt[M_PROCESSING_NODE], Pretty_Addr_Str (&opus_addr), newnodedes.SystemName);
  1676.    if (!CARRIER)                                 /* if no carrier yet,          */
  1677.       {
  1678.       if (autobaud)
  1679.          (void) set_baud (max_baud.rate_value, 1);
  1680.                                                  /* Set to our highest baud rate */
  1681.       else
  1682.          (void) set_baud ((300 * newnodedes.BaudRate), 1);         /* set baud to nodelist
  1683.                                                                  * baud */
  1684.       }
  1685.    return (1);                                     /* return success to caller  */
  1686. }
  1687.  
  1688.  
  1689. /*---------------------------------------------------------------------------*/
  1690. /* NODEFIND                                                                  */
  1691. /* Find nodelist entry for use by other routines (password, nodeproc)         */
  1692. /* If found, result will be in "newnodedes".                                 */
  1693. /*                                                                             */
  1694. /* If the passed zone is -1 then the next zone is returned                     */
  1695. /*                                                                             */
  1696. /* This is now passed a 4D address and thus must fiddle about with fakenets  */
  1697. /*---------------------------------------------------------------------------*/
  1698.  
  1699. int nodefind (ADDR *bink_addr, int prtflag)
  1700. {
  1701.     int i, j, k;
  1702.     int have_boss_data = 0;
  1703.     int need_boss_data = 0;
  1704.     ADDRESS *ad;
  1705.     ADDR newad;        /* Address of converting for fakenet */
  1706.     PROTMODE mode;
  1707.  
  1708.     char *bestPassword = NULL;
  1709.     char *bestPrefix = NULL;
  1710.     char *bestPhone = NULL;
  1711.     char bestCallSlot = '\0';
  1712.     ADDRESS *bestAlias = NULL;
  1713.  
  1714.  
  1715. #ifdef DEBUG
  1716.     if(debugging_log)
  1717.         status_line(">nodefind(%s)", Pretty_Addr_Str(bink_addr));
  1718. #endif
  1719.  
  1720.     if((int)bink_addr->Zone == -1)
  1721.         return nodeLookup(bink_addr, FALSE);
  1722.  
  1723.     if(checkNodeCache(bink_addr))
  1724.         return TRUE;
  1725.  
  1726.  
  1727.     newnodedes.NetNumber = newnodedes.NodeNumber = found_zone = found_net = 0;
  1728.     
  1729.     strcpy (newnodedes.SystemName, "Unknown BinkleyTerm System");    /* System Name defaults */
  1730.     strcpy (newnodedes.MiscInfo, "Somewhere out There");             /* As does City */
  1731.     strcpy (newnodedes.PhoneNumber, "");
  1732.  
  1733.     mode = MODE_DEFAULT;
  1734.  
  1735.     CurrentOKFile = DEFAULT.rq_OKFile;     /* Set the default f.req paths */
  1736.     CurrentFILES = DEFAULT.rq_FILES;
  1737.     CurrentAbout = DEFAULT.rq_About;
  1738.     CurrentReqTemplate = DEFAULT.rq_Template;
  1739.     CurrentNetFiles = DEFAULT.sc_Inbound;
  1740.     CurrentReqLim = DEFAULT.rq_Limit;
  1741.     CurrentByteLim = DEFAULT.byte_Limit;
  1742.     CurrentTimeLim = DEFAULT.time_Limit;
  1743.  
  1744.     /* Set up the assumed address based on curr_domain/found_zone/found_net */
  1745.  
  1746.     assumed = k = 0;                          /* Default to zone of first */
  1747.     for (j = 0; j < num_addrs; j++)
  1748.     {
  1749.  
  1750.     /*
  1751.      * If this alias's domain is the curr_domain
  1752.      *      OR
  1753.      * Curr_domain is NULL and this domain is the default
  1754.      *      OR
  1755.      * If this alias doesnt have a domain and curr_domain is default
  1756.      *
  1757.      * This can be simplified by setting all domains to default in initialisation!
  1758.      */
  1759.  
  1760.         if((alias[j].ad.Domain == bink_addr->Domain) ||
  1761.               (!bink_addr->Domain && (alias[j].ad.Domain == alias[0].ad.Domain)) ||
  1762.               (!alias[j].ad.Domain && (bink_addr->Domain == alias[0].ad.Domain)))
  1763.         {
  1764.             if (k == 0)                /* Matched Domain */
  1765.             {
  1766.                 assumed = j;
  1767.                 ++k;
  1768.             }
  1769.  
  1770.             if(alias[j].ad.Zone == bink_addr->Zone)
  1771.             {
  1772.                 if (k == 1)
  1773.                 {
  1774.                    assumed = j;
  1775.                    ++k;
  1776.                 }
  1777.  
  1778.                 if(alias[j].ad.Net == bink_addr->Net)
  1779.                 {
  1780.                     if(k == 2)
  1781.                     {
  1782.                         assumed = j;
  1783.                         ++k;
  1784.                     }
  1785.                     if(alias[j].ad.Node == bink_addr->Node)
  1786.                     {
  1787.                        assumed = j;
  1788.                        break;
  1789.                     } /* node */
  1790.                 } /* net */
  1791.             } /* zone */
  1792.         } /* domain */
  1793.     } /* alias */
  1794.  
  1795.     /* Search the adkeys for a password and force assumed node! */
  1796.  
  1797.     {
  1798.       ADKEY *key = adkeys;
  1799.  
  1800.       while(key)
  1801.       {
  1802.         if( (key->wild.net || (key->ad.Net == bink_addr->Net)) &&
  1803.             (key->wild.node || (key->ad.Node == bink_addr->Node)) &&
  1804.             (key->wild.zone || (key->ad.Zone == bink_addr->Zone)) &&
  1805.             (key->wild.domain || !key->ad.Domain || !bink_addr->Domain || (key->ad.Domain == bink_addr->Domain)) &&
  1806.             (key->wild.point || (key->ad.Point == bink_addr->Point)) )
  1807.         {
  1808.             if(key->password)
  1809.                 have_boss_data = 1;
  1810.  
  1811.             /*
  1812.              * Remember password/phone/prefix for later
  1813.              */
  1814.  
  1815.             if(bestPassword == NULL)
  1816.                 bestPassword = key->password;
  1817.             if(bestPhone == NULL)
  1818.                 bestPhone = key->phone;
  1819.             if(bestPrefix == NULL)
  1820.                 bestPrefix = key->prefix;
  1821.             if(bestAlias == NULL)
  1822.                 bestAlias = key->alias;
  1823.             bestCallSlot = key->call_slot;
  1824.         }
  1825.         key = key->next;
  1826.        }
  1827.      }
  1828.  
  1829.     /* Convert alias to assumed */
  1830.  
  1831.     if(bestAlias != NULL)
  1832.     {
  1833.         j = 0;
  1834.         ad = alias;
  1835.         while(j < num_addrs)
  1836.         {
  1837.             if(bestAlias == ad)
  1838.             {
  1839.                 assumed = j;
  1840.                 break;
  1841.             }
  1842.             j++;
  1843.             ad++;
  1844.         }
  1845.     }
  1846.     ad = &alias[assumed];
  1847.  
  1848.     if(ad->phone || bestPhone)
  1849.         ++have_boss_data;
  1850.  
  1851.     /* Are we the boss or are we wanting the boss? and do we have enough info? */
  1852.  
  1853.     newad = *bink_addr;            /* Prepare the 3D address */
  1854.  
  1855.     if(!newad.Zone)
  1856.         newad.Zone = ad->ad.Zone;
  1857.  
  1858.     /* Look it up in the nodelist */
  1859.  
  1860.     i = nodeLookup(&newad, have_boss_data);
  1861.  
  1862.     /* If we're a point and this is our boss, use the fakenet */
  1863.  
  1864.     if(
  1865.         (bink_addr->Net == ad->ad.Net) &&
  1866.         (bink_addr->Node == ad->ad.Node) &&
  1867.         (bink_addr->Zone == ad->ad.Zone) &&
  1868.         (bink_addr->Domain == ad->ad.Domain))
  1869.     {
  1870.         /* If this is our boss */
  1871.  
  1872.         if(!bink_addr->Point)
  1873.             ++need_boss_data;
  1874.         else
  1875.         /* Patch up the address for fakenet if we're accessing a point not our own */
  1876.         {
  1877.             if(!i)    /* couldn't find point address.. try fakenet */
  1878.             {
  1879.                 newad.Net = ad->fakenet;
  1880.                 newad.Node = bink_addr->Point;
  1881.                 newad.Point = 0;
  1882.                 i = nodeLookup(&newad, have_boss_data);
  1883.             }
  1884.         }
  1885.     }
  1886.  
  1887.     if(bestPhone)
  1888.     {
  1889.         strncpy(newnodedes.PhoneNumber, bestPhone, 40);
  1890.         newnodedes.PhoneNumber[39] = '\0';
  1891.     }
  1892.     else if(need_boss_data && ad->phone)    /* Update phone number if set and calling boss */
  1893.     {
  1894.         strncpy(newnodedes.PhoneNumber, ad->phone, 40);
  1895.         newnodedes.PhoneNumber[39] = '\0';
  1896.     }
  1897.  
  1898.     if(bestPrefix)
  1899.         node_prefix = bestPrefix;
  1900.     else
  1901.         node_prefix = NULL;
  1902.  
  1903.     /* Overwrite the password */
  1904.  
  1905.     if(bestPassword)
  1906.     {
  1907.         memset(newnodedes.Password, 0, sizeof(newnodedes.Password));
  1908.         strncpy(newnodedes.Password, bestPassword, sizeof(newnodedes.Password));
  1909.     }
  1910.  
  1911.     if (usecallslots)
  1912.         newnodedes.RealCost = (word)bestCallSlot;
  1913.  
  1914.     if(!i && (have_boss_data != 2) && !bestPhone && !bestPassword)
  1915.     {
  1916.       if (prtflag)
  1917.          status_line (msgtxt[M_NO_ADDRESS], Pretty_Addr_Str (bink_addr));
  1918.  
  1919.       if (curmudgeon && CARRIER && ((int)bink_addr->Net != -1) && ((int)bink_addr->Node != -1) && (bink_addr->Node != 9999))
  1920.       {
  1921.          status_line (msgtxt[M_NUISANCE_CALLER]);
  1922.           hang_up ();
  1923.          DTR_ON ();                             /* OK, turn modem back on */
  1924.       }
  1925.  
  1926.     }
  1927.  
  1928.  
  1929.    /* If we found the entry, then we promote the file request
  1930.     * to the "KNOWN" class. If the password field is non-zero,
  1931.     * then promote to "PROT". It's OK to do that since the higher
  1932.     * level code will hang up before f.req's if the password does
  1933.     * not match.
  1934.     *
  1935.     */
  1936.  
  1937.     if (i || bestPhone || bestPassword)
  1938.     {
  1939. #ifdef DEBUG
  1940.         if(debugging_log)
  1941.             status_line(">nodefind(%s) password='%s'",
  1942.                 Pretty_Addr_Str(bink_addr), newnodedes.Password);
  1943. #endif
  1944.         if (newnodedes.Password[0])
  1945.         {
  1946.             mode = MODE_PROTECTED;
  1947.             CurrentOKFile = PROT.rq_OKFile;
  1948.             CurrentFILES = PROT.rq_FILES;
  1949.             CurrentAbout = PROT.rq_About;
  1950.             CurrentReqTemplate = PROT.rq_Template;
  1951.             CurrentNetFiles = PROT.sc_Inbound;
  1952.             CurrentReqLim = PROT.rq_Limit;
  1953.             CurrentByteLim = PROT.byte_Limit;
  1954.             CurrentTimeLim = PROT.time_Limit;
  1955.         }
  1956.         else if(i)
  1957.         {
  1958.             mode = MODE_KNOWN;
  1959.             CurrentOKFile = KNOWN.rq_OKFile;
  1960.             CurrentFILES = KNOWN.rq_FILES;
  1961.             CurrentAbout = KNOWN.rq_About;
  1962.             CurrentReqTemplate = KNOWN.rq_Template;
  1963.             CurrentNetFiles = KNOWN.sc_Inbound;
  1964.             CurrentReqLim = KNOWN.rq_Limit;
  1965.             CurrentByteLim = KNOWN.byte_Limit;
  1966.             CurrentTimeLim = KNOWN.time_Limit;
  1967.         }
  1968.         addNodeCache(bink_addr, mode);
  1969.  
  1970.     }
  1971.  
  1972.     if(i || !need_boss_data)    /* && !key) */
  1973.       return (i);
  1974.  
  1975.     /* No BOSS in the nodelist */
  1976.  
  1977.     if(have_boss_data != 2)
  1978.     {
  1979.       status_line (msgtxt[M_NO_BOSS]);
  1980.       return (0);
  1981.     }
  1982.  
  1983.     /* Fill in the information for our boss */
  1984.  
  1985.     newnodedes.NodeNumber = bink_addr->Node;      /* Node Number */
  1986.     newnodedes.NetNumber = bink_addr->Net;          /* Net Number  */
  1987.     newnodedes.Cost = newnodedes.RealCost = 0;     /* Assume boss is free */
  1988.     strcpy (newnodedes.SystemName, "Binkley's Boss");     /* System Name defaults */
  1989.     strcpy (newnodedes.MiscInfo, "Somewhere out There"); /* As does City */
  1990.     newnodedes.HubNode = 0;                         /* Don't know who is HUB */
  1991.     newnodedes.BaudRate = (char) (max_baud.rate_value / 300);
  1992.                                                  /* Assume boss speed = ours */
  1993.     newnodedes.ModemType = 0;                     /* Or modem type */
  1994.     newnodedes.NodeFlags = B_CM;                 /* Assume boss is CM */
  1995.     newnodedes.NodeFiller = 0;                     /* Zero out filler */
  1996.  
  1997.     addNodeCache(bink_addr, mode);
  1998.     return (1);
  1999. }
  2000.  
  2001.  
  2002.