/*
 *  MBCMD.C - 9/20/92 - Command parser and dispatch.
 */

#include "mb.h"

docmd()
{
  typedef struct
  {
    char  n1, n2;    /* The two command letters        */
    byte  args;      /* Number of arguments required   */
    word  mode;      /* Bitmask of allowed port modes  */
    int   (*fp)();   /* Pointer to function return int */
  } CMDDEF;

  register CMDDEF *cp;
  register int status;

/*
 *  The functions that do the commands.
 */

#ifdef MCH_AMIGA
   extern char fbb_direction;
   extern int donefunc();
   extern int flipdebug();
   extern int kill_list();
   extern int srpmsg();
   extern int opchange();
#endif
#ifndef MCH_AMIGA
  extern int find_call();
  extern int w_lock();
#endif
#ifdef MCH_SYSOP
  extern int all_fwd();
  extern int go_arexx();
  extern rexx_done();
#endif
  extern int klmult();
  extern int klmsg();
  extern int lstmsg();
  extern int rdmult();
  extern int rdmsg();
  extern int sndmlt();
  extern int sndmsg();
#ifndef MCH_SYSOP
  extern int fwdcmd();
#endif
  extern int done();
  extern int help();
  extern int klmsgm();
  extern int mkrem();
  extern int mksys();
  extern int makmlt();
  extern int makmsg();
  extern int dupmsg();
  extern int filmsg();
  extern int setunt();
  extern int edmsg();
  extern int edtfc();
  extern int copfil();
  extern int renfil();
  extern int kilfil();
  extern int uloadl();
  extern int uloadr();
  extern int dloads();
  extern int dloadi();
  extern int dloadl();
  extern int dloadr();
  extern int bye();
  extern int lterm();
  extern int setime();
  extern int chguser();
  extern int chgparam();
  extern int utalk();
  extern int rdmsgm();
  extern int duser();
  extern int dwuser();
  extern int edport();
  extern int eduser();
  extern int edusera();
  extern int puser();
  extern int sfwd();
  extern int newfwd();
  extern int prthrd();
  extern int prtdir();
  extern int prtver();
  extern int dosys();

/*
 *  Command char 1, char 2, # args, modes allowed, function
 */

static CMDDEF cmds[] =
{

  '!', ' ', 2, local,          dosys,
  '!', ' ', 3, local,          dosys,
  '!', ' ', 4, local,          dosys,
  '!', ' ', 5, local,          dosys,
#ifndef MCH_SYSOP
  '@', ' ', 1, remote,         mksys,
  '@', ' ', 1, sysop,          mkrem,
#endif
  '?', ' ', 1, all,            help,
  '?', ' ', 2, all,            help,

#ifndef MCH_AMIGA
  'A', 'H', 1, ops,            w_lock,
#endif
#ifdef MCH_SYSOP
  'A', '*', 1, ops,            all_fwd,
#endif

  'B', ' ', 1, all,            bye,

#ifndef MCH_AMIGA
  'C', ' ', 3, ops,            setime,
  'C', 'B', 2, all,            find_call,
#endif
  'C', 'M', 3, ops,            dupmsg,
  'C', 'M', 5, ops,            dupmsg,
  'C', 'M', 7, ops,            dupmsg,

#ifndef MCH_AMIGA
  'C', '*', 1, remote,         utncv,
  'C', '*', 2, remote,         ctncv,
  'C', '*', 4, remote,         ctncv,
#endif

#ifdef MCH_AMIGA
  'D', 'B', 1, ops,            flipdebug,
#endif
  'D', 'L', 1, ops,            duser,
  'D', 'L', 2, ops,            duser,
  'D', 'M', 1, ops,            duser,
  'D', 'M', 2, ops,            duser,
  'D', 'S', 1, ops,            duser,
  'D', 'S', 2, ops,            duser,
  'D', 'U', 1, ops,            duser,
  'D', 'U', 2, ops,            duser,
  'D', 'W', 1, ops,            dwuser,
  'D', 'W', 2, ops,            dwuser,
  'D', 'X', 1, ops,            duser,
  'D', 'X', 2, ops,            duser,
  'D', '*', 2, local,          dloadl,
  'D', '*', 2, remote,         dloadr,
  'D', '*', 2, sysop,          dloads,

  'E', ' ', 2, ops,            edmsg,
  'E', 'P', 2, ops,            edport,
  'E', 'S', 1, ops,            chgparam,
  'E', 'T', 2, all,            edtfc,
  'E', 'U', 1, ops,            edusera,
  'E', 'U', 2, ops,            eduser,

#ifndef MCH_SYSOP
  'F', '>', 1, remote,         fwdcmd,
#endif
  'F', '*', 3, ops,            filmsg,
  'F', '*', 4, ops,            filmsg,

  'G', 'M', 1, ops,            setunt,
#ifdef MCH_SYSOP
  'G', 'O', 1, all,            go_arexx,
#endif
  'G', 'R', 1, ops,            setunt,
  'G', 'R', 2, ops,            setunt,
  'G', 'U', 1, ops,            setunt,

  'H', ' ', 1, all,            help,
  'H', ' ', 2, all,            help,

  'I', ' ', 1, all,            dloadi,
#ifndef MCH_SYSOP
  'J', '*', 1, all,            prthrd,
#endif

  'K', ' ', 2, all,            klmsg,
  'K', ' ', 3, ops,            klmult,
  'K', ' ', 4, ops,            klmult,
  'K', ' ', 5, ops,            klmult,
  'K', 'A', 2, ops,            klmsg,
  'K', 'A', 3, ops,            klmult,
  'K', 'A', 4, ops,            klmult,
  'K', 'A', 5, ops,            klmult,
  'K', 'A', 6, ops,            klmult,
  'K', 'F', 1, ops,            klmsgm,
  'K', 'F', 2, ops,            klmsgm,
#ifdef MCH_AMIGA
  'K', 'L', 3, local,          kill_list,
#endif
  'K', 'M', 1, all,            klmsgm,
  'K', 'O', 1, ops,            klmsgm,
  'K', 'O', 2, ops,            klmsgm,
  'K', 'T', 2, all,            klmsg,
  'K', 'Y', 1, ops,            klmsgm,
  'K', 'Y', 2, ops,            klmsgm,

  'L', '*', 1, all,            lstmsg,
  'L', '*', 2, all,            lstmsg,
  'L', '*', 3, all,            lstmsg,
  'L', '*', 4, all,            lstmsg,

  'M', 'M', 3, ops,            makmlt,
  'M', 'M', 4, ops,            makmlt,
  'M', '*', 3, ops,            makmsg,
  'M', '*', 4, ops,            makmsg,
  'M', '*', 5, ops,            makmsg,
  'M', '*', 6, ops,            makmsg,
  'M', '*', 7, ops,            makmsg,
  'M', '*', 8, ops,            makmsg,

  'N', ' ', 2, all,            chguser,
  'N', ' ', 3, ops,            renfil,
  'N', 'E', 1, all,            chguser,
  'N', 'H', 2, all,            chguser,
  'N', 'P', 1, all,            chguser,
  'N', 'Q', 2, all,            chguser,
  'N', 'Q', 3, all,            chguser,
  'N', 'Z', 2, all,            chguser,

#ifdef MCH_AMIGA
  'O', 'P', 2, local,          opchange,
#endif

  'P', ' ', 2, all,            puser,

#ifndef MCH_AMIGA
  'Q', ' ', 1, local,          done,
#else
  'Q', ' ', 1, local,          donefunc,
#ifdef MCH_SYSOP
  'Q', '*', 1, local,          rexx_done,
#endif
#endif

  'R', ' ', 2, all,            rdmsg,
  'R', ' ', 3, all,            rdmult,
  'R', ' ', 4, all,            rdmult,
  'R', ' ', 5, all,            rdmult,
  'R', ' ', 6, all,            rdmult,
  'R', 'H', 2, all,            rdmsg,
  'R', 'H', 3, all,            rdmult,
  'R', 'H', 4, all,            rdmult,
  'R', 'H', 5, all,            rdmult,
  'R', 'H', 6, all,            rdmult,
  'R', 'M', 1, all,            rdmsgm,

  'S', 'M', 2, ops,            sndmlt,
  'S', 'M', 3, ops,            sndmlt,
#ifdef MCH_AMIGA
/* Send Reply command
  all it does it say the command has been removed until it works properly.
*/
  'S', 'R', 1, all,            srpmsg,
#endif
  'S', '!', 2, all,            sndmlt,
  'S', '*', 2, all,            sndmsg,
  'S', '*', 3, all,            sndmsg,
  'S', '*', 4, all,            sndmsg,
  'S', '*', 5, all,            sndmsg,
  'S', '*', 6, all,            sndmsg,
  'S', '*', 7, all,            sndmsg,
#ifdef MCH_AMIGA
  'S', '*', 8, all,            sndmsg,
#endif

#ifndef MCH_SYSOP
  'T', ' ', 1, remote,         utalk,
  'T', '*', 1, local,          lterm,
  'T', '*', 2, local,          lterm,

  'U', '*', 2, ops,            uloadl,
  'U', '*', 2, remote,         uloadr,
#endif

  'V', ' ', 1, all,            prtver,
  'V', ' ', 3, ops,            copfil,

  'W', '*', 1, all,            prtdir,
  'W', '*', 2, all,            prtdir,

#ifndef MCH_SYSOP
  'X', '*', 1, ops,            sfwd,
  'X', '*', 2, ops,            sfwd,
  'X', '*', 3, ops,            sfwd,

  'Y', 'F', 1, ops,            newfwd,
  'Y', 'F', 2, ops,            newfwd,
#endif

  'Z', '*', 2, ops,            kilfil,

  '\0', ' ', 0, 0, 0, 0
};

  port->cmdcnt++;
  pgst(NULL);
#ifdef MCH_AMIGA
/* If the line begins with ## then it is probably a disconnect message
   from a distant ka-node or a retry out message. So might as well
   say bye
*/
   if((port->opt1 == '#') && (port->opt2 == '#')) {
      bye();
      return;
   }
/* and if the line begines with a semicolon then treat it as a comment
   (for the I in the SID)
*/
   if(port->opt1 == ';')return;
#endif

  if (strlen(port->fld[0]) < 3)
    for (cp = cmds; cp->n1; cp++)
    if (port->mode & cp->mode)
    if (port->opt1 is cp->n1)
    if ((port->opt2 is cp->n2) or (cp->n2 is '*'))
#ifndef MCH_AMIGA
    if (port->flds is cp->args) { status = (*cp->fp)(); return; }
#else
/* If the last message was not a read command then clear the message
   type so that if the user then does a 'SR' command, it will fail
*/
   if(port->flds is cp->args) {
      status = (*cp->fp)();
#ifdef MCH_SYSOP
      reply_to_rexx();
#endif
      if(port->opt1 != 'R')last_msg.type = 0;
      return;
    }
#endif

#ifndef MCH_AMIGA
  if ((port->opt1 is '[') and (port->cmdcnt is 1)) { isbid(); return;}
#else
   if((port->opt1 is '[') and (port->cmdcnt is 1)) {
      isbid();
      if(s_mart & fbbok) {
         port->flags setbit p_dofwd;
         port->mode = remote;
         fbb_direction = 1;
         fwdcmd();
         port->flags clrbit p_dofwd;
         bye();
      }
      return;
  }
#endif
#ifdef MCH_SYSOP
  reply_to_rexx();
#endif
  port->msg = mwhat;
  port->errors++;
}

/*
 *  User wants to log out.
 *  Set the flag so they will be logged out.
 */

bye()
{
#ifdef MCH_SYSOP
   extern char *arexx_port;

  arexx_port = 0;
#endif
  pt_flag = 0;
  port->mode = logout;
}

/*
 *  User done being remote sysop.
 *  Make them normal user again.
 */

mkrem()
{
#ifndef MCH_SYSOP
  port->flags clrbit p_clrsys;
  port->mode = remote;
  if (!port->tmode)
  {
     cmdtnc();
     onetnc("cr on\n");
     onetnc("cp of\n");
     onetnc("se $0d\n");
     convtnc();
  }
#endif
}

/*
 *  User wants to be remote sysop.
 *  Let them, if they are allowed to.
 */

mksys()
{
#ifndef MCH_SYSOP
  if (!(port->priv & p_sysop) or !(port->user->options & u_sysop)or!(pass()))
    { port->msg = mwhat; return; }

  port->flags setbit p_clrsys;
  port->mode = sysop;
  if (!port->tmode)
  {
     cmdtnc();
     onetnc("cr of\n");
     onetnc("cp on\n");
     onetnc("se $7f\n");
     convtnc();
  }
#endif
}

#ifdef MCH_AMIGA
#endif
#ifndef NEWPASS
pass()
{
  int count,psn,lpsn;
  char temp[4], pword[5];
  for (count = 0, lpsn = 0; count < 4; count++)
    {
      while ((psn=(rand()/512))== lpsn);
      sprintf (temp, "%3u", psn+1);
      outstr(temp);
      pword[count] = *(keylst+psn);
      lpsn = psn;
    }
    outstr("\n");
    getdat();
    if (matchn(port->line, pword, 4)) return true;
    return false;
 }
#endif

/*
 *  Lock up the current window for no more than 180 seconds.
 */

#ifndef MCH_AMIGA
w_lock()
{
  long l;
  if (!(s_flag & s_dv)) return;
  outstr("\nWindow locked");
  while (true)
  {
    getcomd(); if (port->opt2 isnt 'H') break;
    switchw();
  }
  outstr("-unLOCKED\n");
  return;
}
#endif

