/*---------------------------------------------------------------------------*
 *
 *                               BinkleyTerm
 *
 *              (C) Copyright 1987-96, Bit Bucket Software Co.
 *     For license and contact information see /doc/orig_260/license.260.
 *
 *           This version was modified by the BinkleyTerm XE Team.
 *        For contact information see /doc/team.lst and /doc/join.us.
 *  For a complete list of changes see /doc/xe_user.doc and /doc/xe_hist.doc.
 *
 * Filename    : $Source: E:/cvs/btxe/src/old/nodeproc.old,v $
 * Revision    : $Revision: 1.1 $
 * Tagname     : $Name: XH6 $
 * Last updated: $Date: 1999/02/28 13:48:00 $
 * State       : $State: Exp $
 * Orig. Author: Vince Perriello
 *
 * Description : BinkleyTerm Nodelist processing module
 *
 *---------------------------------------------------------------------------*/

/* Include this file before any other includes or defines! */

#include "includes.h"

#if defined(QUICK_LIST) || defined(V6_LIST)  /*  TS 970128   */

static char far *LOCALFUNC get_size (unsigned int);
static int LOCALFUNC get_new_info (unsigned);

#endif /*  #if defined(QUICK_LIST) || defined(V6_LIST) */

static off_t index_filesize = (off_t) 0L;
static time_t index_filetime = (time_t) 0L;
static char index_filename[PATHLEN];

static char *curr_domain = NULL;

#if defined(V6_LIST) || defined(QUICK_LIST)

static unsigned int idx_size = 0;  /* number of entries  */

#endif

#ifdef V6_LIST

static int extra_bytes = 0;

#endif

int get_nodelist_name (ADDR *);

int
get_nodelist_name (ADDRP opus_addr)
{
  int i;

  if (opus_addr->Domain == NULL)
  {
    opus_addr->Domain = domain_name[0];
    for (i = 0; i < num_domain_kludge; i++)
    {
      if (opus_addr->Zone == domainkludge[i].zone)
      {
        opus_addr->Domain = domain_name[domainkludge[i].domain];
        break;
      }
    }
  }

  curr_domain = opus_addr->Domain;

#if defined(V6_LIST) || defined(QUICK_LIST)
  idx_size = 0;
#endif
#ifdef V6_LIST
  extra_bytes = 0;
#endif

  nodelist_base = nodelist_name;

  for (i = 0; domain_name[i] != NULL; i++)
  {
    if (domain_name[i] == opus_addr->Domain)
    {
      nodelist_base = domain_nodelist[i];
      if (nodelist_base == NULL)
        nodelist_base = nodelist_name;
      return 1;
    }
  }

  return (i && domain_name[i] == NULL) ? 0 : 1;
}

#if defined(QUICK_LIST) || defined(V6_LIST)  /*  TS 970128   */
static char far *LOCALFUNC
get_size (unsigned int n)
{
  /* If we get this far, then we have to use a straight far pointer */
  return (_fmalloc (n));
}
#endif /*  #if defined(QUICK_LIST) || defined(V6_LIST) */

/*---------------------------------------------------------------------------*/
/* CHECKLIST                                                                 */
/* See if nodelist has changed since we first tried to use it and if so,     */
/* dismiss old copy and get a new one                                        */
/*---------------------------------------------------------------------------*/

int
checklist ()
{
  struct stat idxstat;

  if (index_filesize == (off_t) 0L)
    return (0);

  (void) unix_stat (index_filename, &idxstat);

  if ((index_filesize == idxstat.st_size) && (index_filetime == idxstat.st_mtime))
    return (0);

  status_line (MSG_TXT (M_REFRESH_NODELIST));
  _ffree (node_index);
  node_index = (char far *) NULL;
  index_filesize = (off_t) 0L;
  return (1);
}

/*---------------------------------------------------------------------------*/
/* NODEPROC                                                                  */
/* Find nodelist entry and set baud to nodelist baud for dialing out         */
/*---------------------------------------------------------------------------*/

int
nodeproc (char *nodeaddr)
{
  ADDR opus_addr;
  char *c;

  c = skip_blanks (nodeaddr);   /* get rid of the blanks      */

  if (!find_address (c, &opus_addr))
    return (0);

  if (!nodefind (&opus_addr, 1))  /* if we can't find the node  */
    return (0);                 /* go away now                */

  if (!CARRIER)                 /* if no carrier yet,         */
  {
    if (autobaud)
    {
      /* Set to highest rate for autobaud */
      (void) set_baud (max_baud.rate_value, 1);
    }
    else
    {
      unsigned long baudrate;

      /* Otherwise use the nodelisted rate */
      /* if nothing "assumed"              */

      baudrate = (unsigned long) 300 *newnodedes.BaudRate;

      if ((baudrate == 300) && (assumebaud != 0))
        baudrate = assumebaud;
      (void) set_baud (baudrate, 1);
    }
  }

  return (1);                   /* return success to caller   */
}

/*---------------------------------------------------------------------------*/
/* NODEFIND                                                                  */
/* Find nodelist entry for use by other routines (password, nodeproc)        */
/* If found, result will be in "newnodedes".                                 */
// 0  = failure
// 1  = success
// -1 = curmudgeon ???
/*---------------------------------------------------------------------------*/

int
nodefind (ADDRP bink_addr, int prtflag)
{
  int i, j, k;
  int have_boss_data = 0;
  int need_boss_data = 0;
  AKA *aka;

  (void) checklist ();

  memset (&newnodedes, 0, sizeof (newnodedes));  /* r. hoerner */
  found_zone = found_net = 0;
  strcpy (lastfound_SysopName, "(unknown)");

  CURRENT = DEFAULT;            /* Set default paths, quotas  */

  if ((bink_addr->Net == boss_addr.Net)
      && (bink_addr->Node == boss_addr.Node)
      && (bink_addr->Zone == alias->Zone)
      && ((bink_addr->Domain == boss_addr.Domain)
          || (bink_addr->Domain == NULL)))
  {
    ++need_boss_data;
    if (BOSSphone && strlen (BOSSphone) > 2)
      ++have_boss_data;
    if (BOSSpwd && strlen (BOSSpwd) > 2)
      ++have_boss_data;
  }

  if (!bink_addr->Zone)
    bink_addr->Zone = alias->Zone;

  i = (*nodefunc) (bink_addr, have_boss_data);

  /* if i==0: maybe we have included the node in our "override" statement?
   * if the adress is invalid or no override statement exists for this node,
   * then leave "i" unchanged, else if phonenumber exists, then the node
   * exists. We'll check for a password directly in the password file (if
   * any)
   */
  i += GetAltPhone ((char *) &newnodedes.PhoneNumber, bink_addr);
  GetAltModemflag ((word *) & newnodedes.ModemType, bink_addr);
  GetAltFidoFlag ((word *) & newnodedes.NodeFlags, bink_addr);

  assumed = k = 0;              /* Default to zone of first   */

  /* if (!i)
   *   goto lookup_done;
   * lookup_done:
   */

  j = 0;
  aka = alias;
  while (aka != NULL)
  {
    if ((aka->Point != 0)
        && ((aka->Node != newnodedes.NodeNumber)
            || (aka->Net != found_net)
            || (aka->Zone != found_zone)))
    {
      /* Don't use our point address except to the boss! */
      goto continue_label;
    }

    if ((aka->Domain == curr_domain)
        || ((curr_domain == NULL) && (aka->Domain == my_addr.Domain))
        || ((aka->Domain == NULL) && (curr_domain == my_addr.Domain)))
    {
      if (k == 0)
      {
        assumed = j;
        ++k;
      }

      if (aka->Zone == found_zone)
      {
        if (k == 1)
        {
          assumed = j;
          ++k;
        }

        if (aka->Net == found_net)
        {
          assumed = j;
          break;
        }
      }
    }

  continue_label:
    j++;
    aka = aka->next;
  }

  /* Another point of your boss? */
  if (!i && need_boss_data && bink_addr->Point)
    return (i);                 /* Don't use your bosspw ! */

  if (!i && (have_boss_data != 2))
  {
    if (prtflag)
      status_line (MSG_TXT (M_NO_ADDRESS), Full_Addr_Str (bink_addr));

    if (curmudgeon && CARRIER &&
        (bink_addr->Net != 0xffff)
        && (bink_addr->Node != 0xffff)
        && (bink_addr->Node != 9999)
        && ((bink_addr->Zone != alias->Zone)
            || (bink_addr->Net != alias->Net)))
    {
      return (-1);
    }

  }

  if (bink_addr->Zone == (unsigned short) -1)
    return i;

  /* If we found the entry, then we promote the file request
   * to the "KNOWN" class. If the password field is non-zero,
   * then promote to "PROT". It's OK to do that since the higher
   * level code will hang up before f.req's if the password does
   * not match.
   *
   */

  if (i)
    CURRENT = (newnodedes.Password[0] ? PROT : KNOWN);

  if (!need_boss_data)
    return (i);

  /*
   *    We can get here one of two ways:
   *
   *    1) No nodelist data was found and this is the BOSS.
   *
   *    2) Nodelist lookup occurred, but this is the BOSS.
   *
   *    For case (1), have_boss_data MUST be 2 (meaning we have
   *    both a phone number and a password entry). If that is the
   *    case, fill in newnodedes with mostly zeroes, plugging in
   *    the BOSS net, node, phone number and password.
   *
   *    For case (2), just see if there is any substitution for
   *    BOSSphone and/or BOSSpwd, then exit.
   *
   */

  if (BOSSphone && strlen (BOSSphone) > 2)
    (void) strntcpy (newnodedes.PhoneNumber, BOSSphone, 40);

  if (BOSSpwd && strlen (BOSSpwd) > 2)
  {
    (void) memset (newnodedes.Password, 0, sizeof (newnodedes.Password));
    (void) strncpy (newnodedes.Password, BOSSpwd, 8);
  }

  if (i)
    return (1);

  /* No BOSS in the nodelist */
  if (have_boss_data != 2)
  {
    status_line (MSG_TXT (M_NO_BOSS));
    return (0);
  }

  newnodedes.NodeNumber = bink_addr->Node;  /* Node Number */
  newnodedes.NetNumber = bink_addr->Net;  /* Net Number  */
  newnodedes.Cost = newnodedes.RealCost = 0;  /* Assume boss is free  */

  /* Default System Name and City */
  (void) strcpy (newnodedes.SystemName, PRDCT_PRTY "'s Boss");
  (void) strcpy (newnodedes.MiscInfo, "Somewhere out There");

  (void) strcpy (lastfound_SysopName, newnodedes.SystemName);
  if (!nofancystrings)
    (void) fancy_str (lastfound_SysopName);
  newnodedes.HubNode = 0;       /* Don't know who's HUB */
  newnodedes.BaudRate = (char) (max_baud.rate_value / 300);

  /* Assume boss speed = ours */
  newnodedes.ModemType = 0;     /* Or modem type        */
  newnodedes.NodeFlags = B_CM;  /* Assume boss is CM    */
  newnodedes.NodeFiller = 0;    /* Zero out filler      */

  return (1);
}

#ifdef QUICK_LIST

int
QuickLookup (ADDRP Quick_addr, int have_boss_data)
{
  register struct QuickNodeIdxRecord far *nodeidx;  /* index file   */
  struct QuickNodeListRecord nodedes;  /* desc. of node        */

  int foundnet = 0;             /* 'found the net' flag   */
  int found = 0;                /* 'found the node' flag  */
  int idxrec = 0;               /* record in QNL_IDX.BBS  */
  long nodeoff = 0L;            /* offset into QNL_DAT.BBS */
  char temp[PATHLEN];           /* we build filenames here */

  FILE *stream;
  USHORT i;
  struct stat f;

  newnodedes.NetNumber = newnodedes.NodeNumber = 0;
  strcpy (lastfound_SysopName, "(unknown)");

  if (node_index == NULL)
  {
    index_filesize = (off_t) 0L;  /* Cover error condition  */
    index_filename[0] = '\0';   /* "null-terminated string */
    (void) strcpy (index_filename, net_info);  /* take nodelist path */
    (void) strcat (index_filename, "QNL_IDX.BBS");  /* add file name  */

    /* MR 961120 orig: */
    // if ((stream = (HFILE) share_open (index_filename, O_RDONLY | O_BINARY, DENY_WRITE)) == -1)
    if ((stream = share_fopen (index_filename, read_binary, DENY_WRITE)) == NULL)
    {
      if (have_boss_data != 2)
        status_line (MSG_TXT (M_UNABLE_TO_OPEN), index_filename);
      return (0);               /* no file, no work to do */
    }

    (void) unix_stat (index_filename, &f);  /* get file statistics    */
    if (f.st_size > 65472L)     /* modulo max index size, */
      i = 65472;
    else
      i = (unsigned int) f.st_size;  /* size of index file,    */

    idx_size = i / sizeof (*nodeidx);  /* number of index entries */
    node_index = get_size (i);

    if (node_index == NULL)
    {
      status_line (MSG_TXT (M_NODELIST_MEM));
      (void) fclose (stream);
      return (0);
    }

    if (!fread (node_index, i, 1, stream))
    {
      status_line (MSG_TXT (M_NODELIST_READ_ERR));
      (void) fclose (stream);
      return (0);
    }

    (void) fclose (stream);

    index_filesize = f.st_size; /* Save params for later  */
    index_filetime = f.st_mtime;
  }

  nodeidx = (struct QuickNodeIdxRecord far *) node_index;

  for (i = 1; i <= idx_size; idxrec++, nodeidx++, i++)
  {
    if (((Quick_addr->Zone == nodeidx->QI_Zone) || (Quick_addr->Zone == 0))
        && (Quick_addr->Net == nodeidx->QI_Net))
    {
      foundnet = 1;             /* say we found the net   */
      if (((Quick_addr->Node == 0) && (nodeidx->QI_Node <= 0))
          || (nodeidx->QI_Node == Quick_addr->Node))  /* is it the node? */
      {
        found = 1;              /* say we found it        */
        break;                  /* get out                */
      }
    }
    else if (foundnet)          /* already past the net?  */
      break;                    /* Yes, we failed...      */
  }

  if (!found)
    return (0);

  nodeoff = (long) idxrec *(long) sizeof (nodedes);  /* file offset    */

  (void) strcpy (temp, net_info);  /* take nodelist path     */
  (void) strcat (temp, "QNL_DAT.BBS");  /* add in the file name   */
  if ((stream = share_fopen (temp, read_binary, DENY_WRITE)) == NULL)
  {
    status_line (MSG_TXT (M_UNABLE_TO_OPEN), temp);
    return (0);
  }

  if (fseek (stream, nodeoff, SEEK_SET))  /* try to point at record */
  {
    status_line (MSG_TXT (M_NODELIST_SEEK_ERR), temp);
    (void) fclose (stream);
    return (0);
  }

  if (!fread (&nodedes, sizeof (nodedes), 1, stream))
  {
    status_line (MSG_TXT (M_NODELIST_REC_ERR), temp);
    (void) fclose (stream);
    return (0);
  }

  (void) fclose (stream);

  /*
   * Copy data from nodedes into newnodedes.
   */

  newnodedes.NodeNumber = nodedes.QL_Node;  /* Node Number  */
  newnodedes.NetNumber = nodedes.QL_Net;  /* Net Number    */
  newnodedes.Cost = nodedes.QL_Cost;  /* Cost            */

  i = min (nodedes.QL_Name[0], 19);
  (void) strncpy (&newnodedes.SystemName[0], &nodedes.QL_Name[1], i);
  newnodedes.SystemName[i] = '\0';  /* System Name  */

  (void) strcpy (lastfound_SysopName, newnodedes.SystemName);
  if (!nofancystrings)
    (void) fancy_str (lastfound_SysopName);

  i = min (nodedes.QL_Phone[0], 39);
  (void) strncpy (&newnodedes.PhoneNumber[0], &nodedes.QL_Phone[1], i);
  newnodedes.PhoneNumber[i] = '\0';  /* Phone Number */

  i = min (nodedes.QL_City[0], 29);
  (void) strncpy (&newnodedes.MiscInfo[0], &nodedes.QL_City[1], i);
  newnodedes.MiscInfo[i] = '\0';

  /* This field is not necessarily null terminated */
  i = min (nodedes.QL_Password[0], 8);
  (void) strncpy (&newnodedes.Password[0], &nodedes.QL_Password[1], i);
  if (i < 8)
    newnodedes.Password[i] = '\0';

  /* Adam Hudson now gives us this, so we might as well use it */
  newnodedes.NodeFlags = nodedes.QL_Flags;

  /* Since we have the stuff we need! */
  newnodelist = 1;              /* We have all the info   */

  newnodedes.RealCost = nodedes.QL_Cost;  /* Cost                   */
  newnodedes.HubNode = 0;       /* Don't know who is Hub  */
  newnodedes.BaudRate = (char) (nodedes.QL_BaudRate / 300);  /* Baud   */
  newnodedes.ModemType = 0;     /* Don't know modem type  */
  newnodedes.NodeFiller = 0;    /* Filler should be zero  */
  found_zone = nodeidx->QI_Zone;  /* Retain the found zone  */
  found_net = nodeidx->QI_Net;  /* And the found net      */
  return (1);
}
#endif /* QUICK_LIST */

#ifdef  V6_LIST                 /*  TS 970128   */
int
opusfind (ADDRP opus_addr, int have_boss_data)
{
  register struct _ndi far *nodeidx;  /* index file             */
  int found = 0;                /* 'found the node' flag  */
  int found_boss = 0;           /* 'found the boss' flag  */
  int nodeoff = 0;              /* offset in nodelist.sys */
  char temp[PATHLEN];           /* we build filenames here */
  unsigned long full_idx_size;
  FILE *stream;
  USHORT i;
  struct stat f;
  unsigned short current_zone = 0;

  newnodedes.NetNumber = newnodedes.NodeNumber = 0;
  strcpy (lastfound_SysopName, "(unknown)");

  if (nodelist_base == NULL)
    nodelist_base = nodelist_name;

  if ((node_index == NULL)
      || ((curr_domain != opus_addr->Domain) && ((opus_addr->Domain != NULL) || (curr_domain != my_addr.Domain))))
  {
    if (node_index != NULL)
    {
      _ffree (node_index);
    }

    if (!get_nodelist_name (opus_addr))
      return 0;
    index_filesize = (off_t) 0L;  /* Cover the error case   */
    index_filename[0] = '\0';   /* "null-terminated string */
    (void) strcpy (index_filename, net_info);  /* take nodelist path */
    (void) strcat (index_filename, nodelist_base);  /* add file name  */
    (void) strcat (index_filename, ".IDX");  /* add in the file ext    */

    if ((stream = share_fopen (index_filename, read_binary, DENY_WRITE)) == NULL)
    {
      i = 0;                    /* Need this later        */
      if (have_boss_data != 2)
        status_line (MSG_TXT (M_UNABLE_TO_OPEN), index_filename);
      return (0);               /* no file, no work to do */
    }

    (void) unix_stat (index_filename, &f);  /* get file statistics    */

    if (f.st_size > 65472L)     /* modulo max index size, */
      i = (USHORT) 65472U;
    else
      i = (USHORT) f.st_size;   /* size of index file,    */

    idx_size = i / sizeof (struct _ndi);  /* number of index entries */
    full_idx_size = f.st_size / sizeof (struct _ndi);

    node_index = get_size (i);
    if (node_index == NULL)
    {
      status_line (MSG_TXT (M_NODELIST_MEM));
      (void) fclose (stream);
      return (0);
    }

    if (!fread (node_index, i, 1, stream))
    {
      status_line (MSG_TXT (M_NODELIST_READ_ERR));
      (void) fclose (stream);
      return (0);
    }

    (void) fclose (stream);

    index_filesize = f.st_size; /* Save params for later  */
    index_filetime = f.st_mtime;

    /*
     * Now take into account that the .DAT file can be bigger than we
     * really expect it to be.  Just take the number of records, and
     * divide into the size of the .DAT file to find the true record size
     */
    if (newnodelist)
    {
      temp[0] = '\0';           /* "null-terminated string */
      (void) strcpy (temp, net_info);  /* take nodelist path     */
      (void) strcat (temp, nodelist_base);  /* add in the file name   */
      (void) strcat (temp, ".DAT");  /* add in the file name   */
      if (!unix_stat (temp, &f))
      {
        extra_bytes = ((int) (f.st_size / full_idx_size))
          - sizeof (newnodedes);
      }
    }
  }

  nodeidx = (struct _ndi far *) node_index;

  if ((!newnodelist) || (alias->Zone == 0))
  {
    opus_addr->Zone = 0;
  }

  for (i = 1; i <= idx_size; nodeoff++, nodeidx++, i++)
  {
    if (nodeidx->node == -2)
      current_zone = nodeidx->net;

    if (opus_addr->Zone > 0 && current_zone != opus_addr->Zone)
      continue;

    if ((unsigned) nodeidx->net == opus_addr->Net)  /* if match on net, */
    {
      if (((opus_addr->Node == 0) && (nodeidx->node <= 0))
          || ((unsigned) nodeidx->node == opus_addr->Node))
      {
        if (opus_addr->Point == 0)
        {
          found = 1;            /* Say we found Node  */
          break;
        }
        found_boss = 1;         /* say we found Boss  */
        continue;
      }
    }

    if (nodeidx->net != -1)
    {
      found_boss = 0;
      continue;
    }

    if ((found_boss == 1) && ((unsigned) nodeidx->node == opus_addr->Point))
    {
      found = 1;
      break;
    }
  }

  if (!found)
    return (0);

  found_zone = current_zone;    /* Retain the found zone  */
  found_net = nodeidx->net;     /* Keep track of found net */

  if (newnodelist)
    i = (USHORT) (get_new_info (nodeoff));

  return (i);
}
#endif /*  #ifdef V6_LIST  */

#ifdef  V6_LIST                 /*  TS 971028   */
static int LOCALFUNC
get_new_info (unsigned recno)
{
  long nodeoff;                 /* Offset in NODELIST.DAT */
  char temp[PATHLEN];           /* we build filenames here */
  FILE *stream;

  strcpy (lastfound_SysopName, "(unknown)");
  /* actual file offset */
  nodeoff = (long) recno *((long) (sizeof (newnodedes) + extra_bytes));

  (void) strcpy (temp, net_info);  /* take nodelist path */
  (void) strcat (temp, nodelist_base);  /* add in the filename */
  (void) strcat (temp, ".DAT"); /* then the extension */
  if ((stream = share_fopen (temp, read_binary, DENY_WRITE)) == NULL)
  {
    status_line (MSG_TXT (M_UNABLE_TO_OPEN), temp);
    return (0);
  }

  if (fseek (stream, nodeoff, SEEK_SET))  /* point at record    */
  {
    status_line (MSG_TXT (M_NODELIST_SEEK_ERR), temp);
    (void) fclose (stream);
    return (0);
  }

  if (!fread (&newnodedes, sizeof (newnodedes), 1, stream))
  {
    status_line (MSG_TXT (M_NODELIST_REC_ERR), temp);
    (void) fclose (stream);
    return (0);
  }

  (void) fclose (stream);
  return (1);
}

#endif /*  #ifdef V6_LIST  */

/* $Id: nodeproc.old,v 1.1 1999/02/28 13:48:00 hjk Exp $ */
