/*
 *  MBUTIL.C - 9/08/92 - Utility functions.
 */

#include "mb.h"
#ifndef MCH_AMIGA
#include "samapi.h"
#endif

#ifdef MCH_AMIGA
extern char tmpstr[];
extern short debug;
extern char *vstring;
#endif

static char *onoff[2] = { "off", "on" };

/*
 *  ! Command: Do DOS command ...
 */

dosys()
{
  strcpy(tmp->scr, port->line + 2);
  remnl(tmp->scr);
#ifndef MCH_AMIGA
  if (system(tmp->scr)) perror("Error");
#else
   /* Workaround MANX problem */
  if (do_system(&tmp->scr[0])) perror("Error");
#endif
}


/*
 *  Sort utility.
 *  base is the start of the array of items.
 *  n is the number of items.
 *  w is the item size.
 *  t is scratch space the size of one item.
 */

sort(base, n, w, t)
char *base;
int   n;
int   w;
char *t;
{
  register int i;
  register int j;
  register int g;
  char *p1, *p2;

  for (g = n/2; g; g /= 2)
  for (i = g; i < n; i++)
  for (j = i - g; j >= 0; j -= g)
  {
    p1 = base + (w * j);
    p2 = base + (w * (j + g));

    if (strncmp(p1, p2, w) <= 0) break;
    memcpy(t, p1, w);
    memcpy(p1, p2, w);
    memcpy(p2, t, w);
  }
}

/*
 *  Return number of days between two dates.
 */

ddiff(fr, to, flag)
char fr[], to[];
int flag;
{
  register int d=0;
  static short dpm[13] =
  { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

  if(flag)
    d = 365 * (10 * (to[0] - fr[0]) + to[1] - fr[1]);

  d += (dpm[10 * (to[2] - '0') + to[3] - '0'] -
   dpm[10 * (fr[2] - '0') + fr[3] - '0']);

  d += 10 * (to[4] - fr[4]) + to[5] - fr[5];

  return d;
}


/*
 *  Wild card match of callsigns with ? and * in first arg.
 */

wcm(s1, s2)
char *s1, *s2;
{
  register short l;

  if (*s1 is '*') if (matchn(s2, cport->user->call, ln_call)) return false;

  for (l = 0; l < ln_call; l++, s1++, s2++)
  {
    switch(*s1)
    {
       case '*' : return true;
       case '!' : if (!isdigit(*s2)) return false;
       case '?' : break;

       default  : if (*s1 isnt *s2) return false;
    }
  }
  return true;
}

/*
 *  Save remote sysop command, for later execution.
 */

savecmd()
{
  strcpy(scmd, port->line);
  s_param setbit s_cmd;
  port->msg = mdone;
}

/*
 *  EP command: change port parameters.
 */

edport()
{
  register PORTS *p;
  register int i;

  if ((p = findport(*port->fld[1])) is NULL) { port->msg = mnport; return; }

  sprintf(tmp->scr, "Change parameters for port %c, %s\n\n", p->id, p->name);
  outstr(tmp->scr);

  while (true)
  {
    outstr("Bbs Down Up Gate Illegal Monitor Remote Xparent 1 2 3 Time Cdigi Fwd Error\n");

    sprintf(tmp->scr,"%c   %c    %c  %c    %c       %c       %c      %c       %c %c %c %-3d   %d    %-2d  %d\n",
     (p->priv & p_bbs)/p_bbs +'0',
     (p->priv & p_dnload)/p_dnload +'0', (p->priv & p_upload)/p_upload +'0',
     (p->priv & p_gate)/p_gate +'0', (p->priv & p_ilcal)/p_ilcal +'0',
     (p->priv & p_mon)/p_mon +'0', (p->priv & p_sysop)/p_sysop +'0',
     p->tmode +'0',p->ecmon +'0', p->ecuser +'0', p->eccmds +'0',
     p->ctime, p->ndigi, p->fwdmin, p->errmax);
    outstr(tmp->scr);

    getcmd();
    if (port->mode & gone) return;
    i = atoi(port->fld[1]);
    switch(port->opt1)
    {
      case 'B' : p->priv flipbit p_bbs;     break;
      case 'C' : p->ndigi = i;              break;
      case 'D' : p->priv flipbit p_dnload;  break;
      case 'E' : p->errmax = i;             break;
      case 'F' : p->fwdmin = i;             break;
      case 'G' : p->priv flipbit p_gate;    break;
      case 'I' : p->priv flipbit p_ilcal;   break;
      case 'M' : p->priv flipbit p_mon;     break;
      case 'R' : p->priv flipbit p_sysop;   break;
      case 'T' : p->ctime = i;              break;
      case 'U' : p->priv flipbit p_upload;  break;
      case 'X' : p->tmode  = 1 - p->tmode;  break;
      case '1' : p->ecmon  = 1 - p->ecmon;  break;
      case '2' : p->ecuser = 1 - p->ecuser; break;
      case '3' : p->eccmds = 1 - p->eccmds; break;
      default  : if (!port->opt1) return;
    }
  }
}

/*
 *  ES command: change system parameters.
 */

chgparam()
{
  register int i;

  while (true)
  {
    outstr("Bell Kill F&B-kill Svc-msg\n");
    sprintf(tmp->scr, "%c    %c    %c        %c\n",
      (s_param & s_page)/s_page+'0', (s_param & s_kill)/s_kill+'0',
      (s_param & s_fkill)/s_fkill+'0', (s_param & s_svc)/s_svc+'0');
    outstr(tmp->scr);

    getcmd();
    if (port->mode & gone) return;
    switch(port->opt1)
    {
      case 'B' : s_param flipbit s_page;  break;
      case 'F' : s_param flipbit s_fkill; break;
      case 'K' : s_param flipbit s_kill;  break;
      case 'S' : s_param flipbit s_svc;   break;
      default  : if(!port->opt1) return;
    }
  }
}

/*
 *  Screen paging.
 */

char *pausemsg;
static char *pghdr = NULL;
static short lnmax;
static short lncnt;

/*
 *  If local console, pause until user types a character.
 *  Return the character.
 *  If not local console, just return a blank.
 */

#ifndef MCH_AMIGA
char pause()
{
  register char t;

  if (port->user->state & u_pause) return ' ';
  if (!pt_flag and ((port->mode is local) or (port->opt1 is 'L')))
  {
    prtx(pausemsg);
    if (port->mode isnt local)
    {
      outchar('\n');
      while (!getdat());
      t = *port->line;
    }
    else
    {
      t = inchar();
      outchar ('\n');
    }
    return toupper(t);
  }
  return ' ';
}
#endif

/*
 *  Start screen paging.
 */

pgst(cp)
char *cp;
{
#ifndef MCH_AMIGA
  if ((pghdr = cp) is NULL) lnmax = 23; else lnmax = 22;
  lncnt = lnmax;
#else
   lnmax = lncnt = 22;
#endif
}

/*
 *  Pause if full screen.
 */

char pgck()
{
  if (--lncnt) return ' ';
  lncnt = lnmax;
  return pause();
}

/*
 *  Display header if at top of screen.
 */

pghd()
{
  if (lncnt is lnmax) if (pghdr isnt NULL) outstr(pghdr);
}

/*
 *  Pause if required at last line.
 */

pgdn()
{
  if (lncnt isnt lnmax) pause();
}

/*
 *  Display "no such file" message, and file name.
 */

nofile(c)
char *c;
{
  prtx(mnfile); outstr(c); outchar('\n');
}

/*
 *  Memory allocation problem, just plain quit.
 */

#ifndef MCH_AMIGA
errall()
{
  outstr("Not enough memory\n");
  exit (0);
#else
errall(i)
int i;
{
  printf("Not enough memory - %d\n",i);
  done(1);
#endif
}

/*
 *  Is this a callsign?
 */

iscall(c)
char *c;
{
  register short i, ld, nd;

  nd = 0;
  for (i = 0; (i < ln_call) and (*c isnt ' '); i++, c++)
  {
    if (ld = isdigit(*c)) nd++;
  }
  return ((i > 3) and ((nd is 1) or (nd is 2)) and !ld);
}

/*
 *  Print list of ports and port names.
 */

shports()
{
  register PORTS *p;

  sprintf(port->line, "Use %c and port ID:\n", port->opt1);
  outstr(port->line);
  for (p = porthd; p isnt NULL; p = p->next)
  {
    sprintf(port->line, "%c%c  %s\n", port->opt1, p->id, p->name);
    outstr(port->line);
  }
}

/*
 *  Return pointer to port with id pid, or NULL.
 */

PORTS *findport(pid)
char pid;
{
  register PORTS *p;

  for (p = porthd; p isnt NULL; p = p->next) if (p->id is pid) return p;
  return NULL;
}

/*
 *  Is it?
 */

iseof(cp)
char *cp;
{
  return match(cp, "*** EOF\n");
}

/*
 *  Remove new line  and control characters from end of string.
 */

remnl(p)
char *p;
{
  for (; *p; p++)
  {
    if (*p is '\n') { *p = '\0'; return; }
    if (*p < ' ') *p = ' ';
  }
}

/*
 *  Parse a callsign.
 *  Blank pad the output field, remove trailing ssid from call.
 *  Return the SSID.
*/

pcall(c, p)
char *c;
char *p;
{
  register short i;

/*
 *  Blank fill the target buffer.
 */

  fill (c, ' ', ln_call);

/*
 *  Ignore leading spaces.
 */

  while (*p and (*p is ' ')) p++;

/*
 *  Copy the call from the string into the call buffer.
 */

  for (i = ln_call; i and *p; i--)
  {
    if (*p <= ' ') return 0;
#ifdef MCH_AMIGA
/* handle strange things from the KAM */
    if(*p == '/')return 0;
#endif
    if (*p is '-') return atoi(++p);
    if (*p is '.') return 0;
#ifndef MCH_AMIGA
    *c++ = *p++;
#else
    *c++ = toupper(*p++);
#endif
  }
  if (*p++ is '-') return atoi(p); else return 0;
}

/*
 *  Is the string a number?
 */

num(p)
char *p;
{
  for (; *p; p++) if (!isdigit(*p)) return false;
  return true;
}

/*
 *  "Output, no blanks".
 */

outnb(p, n)
char *p;
short n;
{
  while (n--) switch (*p)
  {
    case ' ' :
    case '\n' :
    case '\0' : return;
    default: outchar(*p++);
  }
}

/*
 *  Print a number right justified in a fixed width field.
 */

outnr(i, n)
int   i;  /* The number to print */
short n;  /* Field width */
{
  char num[7];

  sprintf (num, "%-6u", i);
  outnb (num, n);
}

/*
 *  Display software version.
 */

prtver()
{
  outstr(ver);
}

/*
 *  Print multi-line message.
 */

prtm(m)
MLM *m;
{
  register MLM *p;

  for (p = m; p isnt NULL; p = p->next) prtx(p->text);
}

/*
 *  Print a string, expanding the "$" fields.
 */

#ifndef MCH_AMIGA
prtx(p)
char *p;
{

  for (; *p; p++)
  {
    if (*p isnt '$') outchar(*p);
    else switch (*(++p))
    {
      case 'A' : outnb(port->mmhs->bbs, ln_call); break;
      case 'B' : outchar(port->mmhs->type); break;
      case 'C' : outnr(mfhs->next_msg, 5); break;
      case 'D' : outstr(l_date); break;
      case 'E' : outstr(port->mmhs->title); break;
      case 'F' : outstr(port->lport->name); break;
      case 'G' : outnb(port->mmhs->to, ln_call); break;
      case 'H' : p++; break;
      case 'I' : outnb(port->user->handle, ln_handle); break;
      case 'J' : outnb(port->mmhs->date, ln_date); break;
      case 'K' : outnb(port->mmhs->time, ln_time); break;
      case 'L' : outnr(mfhs->next_msg - 1, 5); break;
      case 'M' : outnr(port->mmhs->number, 5); break;
      case 'N' : outnr(mfhs->count, 4); break;
      case 'O' : outnb(cport->user->call, ln_call); break;
      case 'P' : outnb(port->mmhs->from, ln_call); break;
      case 'Q' : outstr(qth); break;
      case 'R' : outnb(port->rcall, ln_call); break;
      case 'S' : outnb(port->lport->user->call, ln_call); break;
      case 'T' : outnb(l_time, ln_time); break;
      case 'U' : outnb(port->user->call, ln_call); break;
      case 'V' : outstr(ver); break;
      case 'W' : outnb(port->lport->user->handle, ln_handle); break;
      case 'X' : outnb(port->user->date, ln_date); break;
      case 'Y' : outnb(port->user->time, ln_time); break;
      case 'Z' : outnr(port->user->msg_number, 5); break;
      case 'a' : outstr(orgbbs); break;
      case 'h' : outstr(port->mmhs->call); break;
      case 'j' : outstr(orgdate); break;
      case 'k' : outstr(orgtime); break;
      case 'm' : outstr(orgmsg); break;
#ifdef MCH_AMIGA
      case 'v' : outstr(vstring); break;
#endif
      default  : outchar(*p);
    }
  }
}
#else

/* Faster version of prtx. One char at a time is really painful! */
/* Make sure that if prtx changes in later versions this version is
   also changed!!!!!

   This routine uses tmpstr to build up the string. Therefore there can
   be no other use made of tmpstr (e.g. for debugging).

   There's also a mod for fbb so that if there's a LF in the string it is
   mapped into CR/LF and also the string is left in tmpstr and not written
   out to the TNC.

*/
extern char fbb_flag = 0;
unsigned char *op;
prtx(p)
unsigned char *p;
{
   register unsigned char *ip;
   register PORTS *pp;

   pp = port;

   op = (unsigned char *) &tmpstr[0];
   for(ip=p; *ip; ip++) {
      if(*ip isnt '$') {
         if(fbb_flag && (*ip == '\n'))*op++ = '\r';
         *op++ = *ip;
      }
      else switch (*(++ip)) {
      case 'A':
         /* For FBB WE MUST put out a BBS. So if there isn't one in the
            header then make it the bbs we are forwarding to
         */
         if(fbb_flag) {
            if(*pp->mmhs->bbs == ' ') {
               xoutnb(pp->user->call,ln_call);
               break;
            }
         }
         xoutnb(pp->mmhs->bbs, ln_call);
         break;
      case 'B' : *op++ = pp->mmhs->type; break;
      case 'C' : xoutnr(mfhs->next_msg, 5); break;
      case 'D' : xoutstr(l_date); break;
      case 'E' : xoutstr(pp->mmhs->title); break;
      case 'F' : xoutstr(pp->lport->name); break;
      case 'G' : xoutnb(pp->mmhs->to, ln_call); break;
      case 'H' : ip++; break;
      case 'I' : xoutnb(pp->user->handle, ln_handle); break;
      case 'J' : xoutnb(pp->mmhs->date, ln_date); break;
      case 'K' : xoutnb(pp->mmhs->time, ln_time); break;
      case 'L' : xoutnr(mfhs->next_msg - 1, 5); break;
      case 'M' : xoutnr(pp->mmhs->number, 5); break;
      case 'N' : xoutnr(mfhs->count, 4); break;
      case 'O' : xoutnb(cport->user->call, ln_call); break;
      case 'P' : xoutnb(pp->mmhs->from, ln_call); break;
      case 'Q' : xoutstr(qth); break;
      case 'R' : xoutnb(pp->rcall, ln_call); break;
      case 'S' : xoutnb(pp->lport->user->call, ln_call); break;
      case 'T' : xoutnb(l_time, ln_time); break;
      case 'U' : xoutnb(pp->user->call, ln_call); break;
      case 'V' : xoutstr(ver); break;
      case 'W' : xoutnb(pp->lport->user->handle, ln_handle); break;
      case 'X' : xoutnb(pp->user->date, ln_date); break;
      case 'Y' : xoutnb(pp->user->time, ln_time); break;
      case 'Z' : xoutnr(pp->user->msg_number, 5); break;
      case 'a' : xoutstr(orgbbs); break;
case 'b':        xoutnb(pp->mmhs->bid,ln_bid); break;
      case 'h' : xoutstr(pp->mmhs->call); break;
      case 'j' : xoutstr(orgdate); break;
      case 'k' : xoutstr(orgtime); break;
      case 'm' : xoutstr(orgmsg); break;
case 's':        xoutnr(pp->mmhs->size); break;
      case 'v' : xoutstr(vstring); break;
      default  : *op++ = *ip;
      }
   }
   *op = 0;
   if(!fbb_flag)outstr(&tmpstr[0]);
}

xoutstr(s)
unsigned char *s;
{
   while(*s)*op++ = *s++;
}


/*
 *  "Output, no blanks".
 */


xoutnb(p, n)
char *p;
short n;
{
  while (n--) switch (*p)
  {
    case ' ' :
    case '\n' :
    case '\0' : return;
    default: *op++ = *p++;
  }
}

/*
 *  Print a number right justified in a fixed width field.
 */

xoutnr(i, n)
int   i;  /* The number to print */
short n;  /* Field width */
{
  char num[7];

   sprintf(num,"%-6u",i);
   xoutnb (num, n);
}
#endif

/*
 *  Write random record.
 */

write_rec(fid, rec, buffer)
int fid;
int rec;
char buffer[];
{
#ifndef MCH_AMIGA
  long lseek();
#endif
  long offs;

  offs = (long)rec * (long)RECSIZE;
  lseek(fid, offs, 0);
  return (write(fid, buffer, RECSIZE) is RECSIZE);
}

/*
 *  Read random record.
 */

read_rec(fid, rec, buffer)
int fid;
int rec;
char buffer[];
{
#ifndef MCH_AMIGA
  long lseek();
#endif
  long offs;

  offs = (long)rec * (long)RECSIZE;
  lseek(fid, offs, 0);
  return (read(fid, buffer, RECSIZE) is RECSIZE);
}

/*
 *  Fill buffer with characters from the current input,
 *  until CR or buffer overflow. Terminate buffer with
 *  '\0', thus making it a string.
 *  Translate \r to \n.
 *  Ignore \n.
 *  Deal with backspace and things like that.
 *  Set flags for timeout and disconnect.
 */

#ifndef MCH_AMIGA
getdat()
{
  register char *cp;
  register PORTS *p;
  register char ch;

  p = port;

  if (p->flags & p_dotmr)
  {
    if ((p->mode & idle) and (p->dev is p_tnc)) settmr(&p->itime, 2);
    else settmr(&p->itime, p->ctime);
  }

  p->flags setbit p_dotmr;
  cp = p->line;

  while (true)
  {
    while(!instat())
    {
      if (p isnt cport)
      {
   ioport(cport);
   if (instat())
   {
     ch = inchar();

     if (ch is achar)
     {
       p->mode = forced;
       ioport(p);
       return true;
     }

     if (ch is tchar)
     {
       p->flags setbit p_opreq;
       ioport(p);
       return true;
     }

   }
   ioport(p);
      }
      if (p->flags & p_trans)
      if (!isdcd())
     {
     if (!(p->mode & idle)) p->mode = discon;
     return true;
     }

      if (!chktmr(p->itime))
      {
   *cp = '\0';
   if (!(p->mode & idle)) p->mode = timeout;
   return true;
      }
    }

    *cp = inchar();

/*
 *  Got a character, deal with it.
 */

    if ((cp is (p->line + linelen - 2)) or (*cp is '\r'))
    {
/*
 *  Got a whole line. Either buffer full, or character is CR.
 */
      if (*cp is '\r') *cp = '\n';
      cp++; *cp = '\0';

      if (p->flags & p_echo) outchar('\n');
      if (!(p->flags & p_trans))
      {
    if (isdis(p->line))
    {
      if (!(p->mode & idle)) p->mode = discon;
      return true;
    }
    if (isretry(p->line)) return false;

    if (isreq(p->line))
    {
      p->flags setbit p_req;
      pcall(p->rcall, p->line + 20);
      p->flags clrbit p_dotmr;
      return false;
    }
      }
      return true;
    }

/*
 *  Not end of line.
 *  Stuff the character in the buffer.
 *  Handle some control characters. Ignore some.
 */

    switch(*cp)
    {
      default   : if (p->flags & p_echo) outchar(*cp); cp++; break;
      case '\b' :
   if (cp > p->line) { cp--; if (p->flags & p_echo) outstr("\b \b"); }
   break;

      case '\n' : if (cp is p->line) { *cp = '\0'; return false; }
      case '\0' : ;   /* Ignore most ctl char */
      case ctl_c: ;   /* Ignore most ctl char */
      case ctl_v: ;   /* Ignore most ctl char */
    }
  }
}
#endif

/*
 *  Is the string a header line?
 */

ishead(p)
char *p;
{
  if (!*p or (*p is '\n')) return false;      /* end of headers */
  if (matchn(p, "R:" ,2)) return true;
  return false;
}

/*
 *  Parse a command line.
 *
 *  Input:   Line of text in port->line.
 *  Returns: Fields are placed in port->cmd.
 *           Fields are pointed to by port->fld[].
 *           port->flds is set to the number of fields found.
 *           Each field is null-terminated.
 *           Fields beyond maxflds are ignored.
 */

#ifndef MCH_AMIGA
parse()
{
  register short bl;
  register char *in, *out;

  for (port->flds = 0; port->flds < maxflds;)
    port->fld[port->flds++] = nullstr;

  in  = port->line;
  out = port->cmd;
  bl  = false;
  port->flds = 0;

  while (*in and (port->flds < maxflds) and (out < (port->cmd + cmdlen - 1)))
  {
    *out = toupper(*in);
    if (bl)
    {
      if ((*in <= ' ') or ((*in is '@') and (port->flds is 2)))
      {
   bl = false;
   *out = '\0';
   if (*in is '@')
   {
     out++;
     *out = '@';
     port->fld[port->flds++] = out++;
     *out = '\0';
   }
      }
      out++;
    }
    else
    {
      if (*in > ' ')
      {
   bl = true;
   port->fld[port->flds++] = out++;
   if ((*in is '@') and (*(in+1) > ' '))
   {
     bl = false;
     *out++ = '\0';
   }
      }
    }
    in++;
  }
  *out = '\0';

  port->opt1 = *port->fld[0];
  port->opt2 = *(port->fld[0] + 1);
  if (!port->opt2) port->opt2 = ' ';
}
#endif

/*
 *  Bundle getdat and parse.
 */

getcmd()
{
  while(!getdat());
  parse();
}

/*
 *  Fill some memory with a character.
 */

fill(adr, ch, len)
char *adr;
char ch;
int len;
{
  while (len--) *adr++ = ch;
}

/*
 *  Copy C string to LJSF string.
 */

ljsf(to, from, size)
char *to;
char *from;
int  size;
{
  fill(to, ' ', size);
  while (size--)
  {
#ifndef MCH_AMIGA
    if (*from < ' ') return;
#else
/* My code in the FBB routines requires that ljsf treats a blank as the end
   of the string (which it is)
*/
    if (*from <= ' ') return;
#endif
    *to++ = *from++;
  }
}

/*
 *  Copy LJSF string to C string.
 */

unbl(to, from, size)
char *to, *from;
int size;
{
  while (size--)
  {
    if (*from <= ' ') { *to = '\0'; return; }
    *to++ = *from++;
  }
  *to = '\0';
}

/*
 *  Are you sure? .....
 */
sure()
{
  outstr("Are you sure (Y/N)?\n");
  while (!getdat());
  if (toupper(*port->line) is 'Y') return false;
  return true;
}

/* Search string for match */

search(a,b,c)
char *a, *b;
int c;
{
  for( ; *a; a++)
    if (matchn(a, b, c)) return true;
  return false;
}
#ifndef MCH_AMIGA

/***********************************************************
 * findcall additions for Sam Lookup.
 * returns if error, Displays call if call found
 ***********************************************************/

int LocateSam(void);
int CallSam(int cmd, void far *cmdbuf, void far *rspbuf);
void display_call(datarec_t * d);


find_call()
{
  int err;
  cmdfindcall_t sam_in;   /* buffer for samapi find command */
  rspdatarec_t sam_out;   /* buffer for result of samapi find command */

  /*
   * make sure the resident code (SAMAPI.EXE) has been installed
   */

  if (LocateSam())
  {
     printf("*** SAMAPI not loaded\n");
     return;
  }

  /*
   * build command block and call SAMAPI, function SamFindCall
   */

  sam_in.packflags = 0;   /* 0 to unpack all data record fields */
  strncpy(sam_in.call, port->fld[1], 6);
  sam_in.call[6] = 0;
  if(s_flag & s_dv) begin_lock();
  err = CallSam(SamFindCall, &sam_in, &sam_out);
  if (s_flag & s_dv) end_lock();
  /*
   * check for unusual error, something other than not found
   */

  if (err != 0 and err != SerrNotFound)
  {
     sprintf(port->line, "*** SAMAPI error %d\n", err);
     outstr(port->line);
     return;
  }

  /*
   * check for just not found
   */

  if (err is SerrNotFound)
  {
     outstr("*** Call not found\n");
     return;
  }

  /*
   * got a match, display the call data
   */

  display_call(&sam_out.d);
  log('U', 'C', 'B', port->fld[1]);
  return;
}

/********************************************************
 * display_call
 *
 * input is pointer to data record, returns nothing
 ********************************************************/

void display_call(datarec_t * d)
{
  sprintf(port->line, "%s ", d->FirstName);
  outstr(port->line);
  if (d->MidInitial[0] != ' ')
  {
    sprintf(port->line, "%s ", d->MidInitial);
    outstr(port->line);
  }
  sprintf(port->line, "%s  %s  %s\n", d->LastName, d->Call, d->Class);
  outstr(port->line);
  sprintf(port->line, "%s (%s)\n", d->Address, d->Dob);
  outstr(port->line);
  sprintf(port->line,"%s, %s %s\n", d->City, d->State, d->Zip);
  outstr(port->line);
}
#endif
