/*  Keep a copy of the original mbfwd in case I don't get anywhere
 *  MBFWD.C - 6/28/91 - Autoforwarding.
 *
 *  The target port mode is set to idle if not connected,
 *  set to remote if connected. It is set to disconnect or timeout
 *  by getdat(), but this is checked and fixed up in getln().
 *
 *  All port input is through getln().
 *  All file input is through nxtin().
 */

#include "mb.h"

#ifdef MCH_AMIGA
unsigned short all_number = 0;
extern char fbb_direction;
extern short debug;
extern char tmpstr[];
extern char passchr,hfstream,vhfstream;
FILE *tmp_file;  /*FIX 9*/
extern short thebox,kambbs;
extern char hostport;
#define deepmax    5     /* Max nesting depth of indirection in fwd.mb */
#else
#define deepmax    8     /* Max nesting depth of indirection in fwd.mb */
#endif

#define fw_one     0x0001  /* Forward to only one MailBox, given in fcall*/
#define fw_anytime 0x0002  /* Ignore the times in the "G" item           */
#define fw_abort   0x0004  /* Abort forwarding as soon as possible       */
#define fw_tried   0x0008  /* Attempted to forward to this MailBox       */
#define fw_tiout   0x0010  /* Forward timeout flag                       */
#define fw_forced  0x0020  /* Forced forward flag                        */
#define fw_pass    0x0040  /* Bypass forward sub file                    */
#define fw_idle    0x0080  /* Manual forward to idle                     */
#define fw_ecall   0x0100  /* Forced forward ecall                       */

char  *script;           /* Pointer to where the connect script is     */

word  fopts;             /* Options, see defines above.                */
char  fwdtyp;
char  *fwdfile;          /* The file name of fwd.mb root file          */
FILE  *ifl[deepmax];     /* File variables for fwd.mb                  */
short deep;              /* Current depth within fwd.mb                */
char  path[80];          /* "G" item saved here, for logging           */
char  fcall[10];         /* Call of the MailBox to forward to          */

/*
 *  YF command: change the name of the forwarding root file.
 */

newfwd()
{
   if(*port->fld[1]) {
#ifdef MCH_AMIGA
/* FIX 9 */
/* complain if specified fwdfile can't be found */
      if((tmp_file = fopen(port->fld[1],"r")) == NULL) {
         sprintf(tmp->scr,"can't find %s\n",port->fld[1]);
         outstr(tmp->scr);
      }
      else {
         fclose(tmp_file);
#endif
         free(fwdfile);
         fwdfile = strdup(port->fld[1]);
#ifdef MCH_AMIGA
         titles();
      }
#endif
   }
   sprintf(tmp->scr, "is %s\n", fwdfile);
   outstr(tmp->scr);
}

/*
 *  YF forward command: change the name of the forwarding root file.
 */

newffwd()
{
   if(*cport->fld[1]) {
      free(fwdfile);
      fwdfile = strdup(cport->fld[1]);
   }
#ifndef MCH_AMIGA
   printf("<File is %s>\n", fwdfile);
#else
   titles();
#endif
}

/*
 *  Add a call to the list of BBS that have messages to be forwarded to them.
 */

addbfwd(cp)
char *cp;
{
   register short i;
   register char *lp;

   for(i = 0, lp = bfwd; i < bfwdn; i++, lp += ln_call)
      if(matchn(cp, lp, ln_call))
         return;

   if(bfwdn < bfwdm) {
      strncpy(lp, cp, ln_call);
      bfwdn++;
   }
}

/*
 *  Add a call to the list of users that have unread messges.
 */

addufwd(cp)
char *cp;
{
   register short i;
   register char *lp;

   for(i = 0, lp = ufwd; i < ufwdn; i++, lp += ln_call)
      if(matchn(cp, lp, ln_call))
         return;

   if(ufwdn < ufwdm) {
      strncpy(lp, cp, ln_call);
      ufwdn++;
   }
}

/*
 *  Check if a call has a message to be forwarded to it.
 */

findfwd(cp, lp, n)
char *cp, *lp;
short n;
{
   register short i;

   for(i = 0; i < n; i++, lp += ln_call)
      if(wcm(cp, lp))
         return true;
   return false;
}

/*
 *  Add the info from one message header to the lists of calls
 *  of stations that have messages to be forwarded to them.
 *
 *  ufwd - Calls to put in beacon line.
 *  bfwd - Calls that have message TO or AT.
 */

addfwd()
{
   register short i;
   char *p, hcall[6];

   if(!(port->mmhs->stat & (m_busy | m_kill | m_read | m_fwd | m_hold))) {
      if(*port->mmhs->bbs is ' ') {
         addufwd(port->mmhs->to);
         addbfwd(port->mmhs->to);
      }
      else {
         if(port->mmhs->ext is 1) {
             for(i = 0; i < port->mmhs->count; i++) if (port->mmhs->flag[i])
                addbfwd(port->mmhs->call[i]);
         }
         else {
            if(matchn(port->mmhs->bbs, cport->user->call, ln_call))
                addufwd(port->mmhs->to);
            else
                addbfwd(port->mmhs->bbs);
            if(port->mmhs->ext is 2) {
               p = port->mmhs->call[0];
               while((p = strchr(p, '.')) isnt NULL) {
                  p++;
                  fill(hcall, ' ', ln_call);
                  pcall(hcall, p);
                  addbfwd(hcall);
               }
            }
         }
      }
   }
}

/*
 *  Build the two lists of calls of stations that have
 *  messages to be forwarded to them.
 */

bldfwd()
{
   register word  h;

   ufwdn = 0;
   bfwdn = 0;
   read_rec(mfl, 0, (char *)mfhs);
#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
   for(h = mfhs->last; h; h--) {
      read_rec(mfl, h, (char *)port->mmhs);
      if(!(port->mmhs->stat & (m_busy|m_kill|m_read|m_fwd|m_hold)))
         addfwd();
#ifdef MCH_AMIGA
/* Find highest numbered message to ALL which isn't busy, killed or held */
      if(!(port->mmhs->stat & (m_busy | m_kill | m_hold)))
          if(matchn("ALL        ",port->mmhs->to,ln_call))
             if(port->mmhs->number > all_number) {
                all_number = port->mmhs->number;
             }
#endif
   }
}

/*
 *  Return true if the current time is within
 *  the time window for forwarding to this MailBox.
 */

chktime()
{
   register short c, en, st;

   if(fopts & fw_anytime) return true;
   curtim();
   st = 10 * (int)(cport->line[2] - '0') + (int)(cport->line[3] - '0');
   en = 10 * (int)(cport->line[4] - '0') + (int)(cport->line[5] - '0');
   c  = 10 * (int)(l_time[0] - '0') + (int)(l_time[1] - '0');
   if(st <= en)
      return ((c >= st) and (c <= en));
   return ((c >= st) or (c <= en));
}

/*
 *  Check if it is ok to forward using this list.
 *  Return a pointer to the port to use for forwarding, or NULL.
 */

PORTS *chkfwd()
{
   register PORTS *p;

   if(fopts & fw_one)
      if(!match (fcall, cport->fld[1]))    { passlst(); return NULL; }
   if(!chktime())                          { passlst(); return NULL; }
   if((p = findport(cport->opt2)) is NULL) { passlst(); return NULL; }
   if(!(p->flags & p_dofwd))               { passlst(); return NULL; }
   if(fopts & fw_abort)                    { passlst(); return NULL; }
   p->mode = idle;
   return p;
}

/*
 *  Check if a disconnect happened.
 */

chkdis()
{
   if(instat())
      if(getdat())
         if(isdis(port->line)) {
            cmdtnc();
            port->mode = idle;
            return true;
         }
   if(port->flags & p_trans)
      if(!isdcd()) {
         cmdtnc();
         port->mode = idle;
         return true;
      }
   return false;
}

/*
 *  Read the next input line from FWD.MB,
 *  or from a file referenced from FWD.MB.
 *  Return NULL if no more lines to read.
 */

char *nxtin(p)
char *p;
{
   register char *st, i;

   while(deep >= 0) {
      i = 1;
      if((st = fgets(p, 80, ifl[deep])) is NULL) {
         fclose(ifl[deep]);
         deep--;
      }
      else {
         if(*p isnt '@') return st;
         if(fopts & fw_pass) return st;
         if(*(p+1) is ' ') {
            if(!chktime()) return st;
            i = 6;
         }
         if(deep < (deepmax - 1)) {
            strupr(p);
            remnl(p);
            deep++;
            if((ifl[deep] = fopen(p + i, "r")) is NULL) deep--;
         }
      }
   }
   return NULL;
}

/*
 *  Do some DOS commands.
 */


dofdos()
{
   register PORTS *p;

   if((p = findport(cport->opt2)) is NULL) {
      passlst();
      return;
   }
#ifdef MCH_AMIGA
/* Don't do this if the port doesn't forward! */
   if((p->flags & p_dofwd) == 0) {
      passlst();
      return;
   }
#endif
   if(strlen(cport->fld[0]) > 3)
      if(!chktime()) {
         passlst();
         return;
      }
   if(fopts & fw_forced)
      if(!((fopts & fw_one) and (match(fcall, cport->fld[1])))) {
         passlst();
         return;
      }

/*
 *  Just in case, flush whatever might be currently open.
 */

   clnuser();
   clnmsg();
   clnlog();

   while(nxtin(cport->line) isnt NULL) {
      if(iseof(cport->line)) return;
      remnl(cport->line);
#ifndef MCH_AMIGA
      printf("\nRunning: %s\n", cport->line);
      if(system(cport->line)) perror("Error");
#else
      sprintf(tmpstr,"\nRunning: %s\n", cport->line);
      ttputs(tmpstr);
      /* MANX doesn't like above syntax ..
         gotta explicitly generate address
      */
      if(do_system(&cport->line[0])) perror("Error");
#endif
   }
}

/*
 *  The entry to fowarding.
 */

fwd()
{
   register PORTS *p;

/*
 *  If no fwd.mb file, then do nothing.
 */
printf("FWD dir=%d f='%6.6s' t='%6.6s'\n",fbb_direction,fcall,tcall);
   deep = 0;
   if ((ifl[deep] = fopen(fwdfile, "r")) is NULL) return;

   bldfwd();

   script = tmp->scr;
   *script = '\0';

   while(nxtin(cport->line) isnt NULL) {
#ifdef MCH_AMIGA
      kambbs = thebox = 0;

      if(!fbb_direction)s_mart = 0;
#else
      s_mart = 0;
#endif
      ioport(cport);
      strupr(cport->line);
      parse();
      fwdtyp = cport->opt1;
      switch(fwdtyp) {
      case 'E':
         passlst();
         script = tmp->scr;
         *script = '\0';
         break;
      case 'D':
      case 'F':
      case 'G':
      case 'H':
         if((p = chkfwd()) isnt NULL) {
            fopts clrbit fw_tried;
/*
 *  Save tail of list header for logging.
 */
            strcpy(path, cport->line + 6);
            remnl(path);
#ifndef MCH_AMIGA
            strcpy(fcall, cport->fld[1]);
#else
            pcall(fcall,cport->fld[1]);
#endif
            script = tmp->scr;
            if(!*script) {
               *script = 'C';
               strcpy(script + 1, cport->line + 6);
               *(script + strlen(script) + 1) = '\0';
            }
#ifndef MCH_AMIGA
            dofwd(p);
            dorev(p);
#else
            user_title(fcall);
            /* chkfwd() forces do_idle ... have to set it to remote for
               a BBS which has called us
            */
            if(fbb_direction)p->mode = remote;
            dofwd(p);
            if((s_mart & fbbok) == 0) {
               dorev(p);
            }
            user_title("");
#endif
            distnc();
            p->mode = idle;
            ioport(cport);
         }
         script = tmp->scr;
         *script = '\0';
         break;

      case 'P':
         dopar();
         break;

      case '!':
         dofdos();
         break;

      case 'Y':
#ifdef MCH_AMIGA
/* Only do the 'YF' at the end of the file if this is NOT the console
   port forwarding time
*/
         if((cport->flags & p_dofwd) == 0)
#endif
         if((cport->opt2 is 'F') and (chktime() ))
            newffwd();
         break;

      case 'C':
      case 'R':
      case 'S':
         strcpy(script, cport->line);
         script += (strlen(cport->line) + 1);
         *script = '\0';
         break;

      default:
         break;
      }
   }

/*
 *  Put us back on the port we were on when we got here.
 */

   ioport(cport);
#ifdef MCH_AMIGA
   kambbs = thebox = 0;
#endif
   s_mart = 0;
}

/*
 *  A and AI commands.
 */

#ifndef MCH_AMIGA
all_fwd()
{
   word pflg;
   port->opt1 = 'X';
   putcomd( port->opt1, port->opt2 );

   pflg = getp_flag();
   putc_flag (pflg);
   port->mode = logout;
}
#endif

/*
 *  X and XI commands.
 */

sfwd()
{
   register PORTS *p;

/*
 *  If remote sysop did the command, just remember it for later.
 */

   if(port->mode & sysop) {
      savecmd();
      return;
   }

/*
 *  Set up parameters for fwd()
 */

   fopts = fw_forced;
   for(p = porthd; p isnt NULL; p = p->next) {
      p->ec = p->ecuser;
      p->flags setbit p_dofwd;
   }

   if(cport->flds > 1) {
      fopts setbit fw_one;
      strncpy (fcall, cport->fld[1], ln_callp);
   }
   if(cport->flds is 3) {
      fopts setbit fw_ecall;
      pcall(tcall, cport->fld[2]);
   }

   if((cport->opt2 is 'I')or(cport->opt2 is 'B'))
      fopts setbit fw_anytime;
   if(cport->opt2 is 'B')
      fopts setbit fw_idle;
#ifdef MCH_AMIGA
/* Tell fbb that we called */
   fbb_direction = 0;
#endif
   fwd();

/*
 *  Reset the port flags.
 */

   for(p = porthd; p isnt NULL; p = p->next)  {
      p->ec = p->ecmon;
      p->flags clrbit p_dofwd;
   }
   if(fopts & fw_idle) bye();

}

/*
 *  Automatic forwarding.
 *  Called once each minute when the MailBox is idle.
 */

afwd(curmin)
int curmin;
{
   register PORTS *p;
   register short anyfwd;

#ifdef MCH_AMIGA
/* FIX 14 The setunt routine can be called with the TNC as the port
          and in that case it will send all output from an automatic
          untangle to the TNC as well as the console.
*/
   register PORTS *saveport;

   saveport = port;

/* Tell fbb that we called */
   fbb_direction = 0;
#endif

/*
 *  Mark the ports that should forward at this minute.
 */

   fopts = 0;
   anyfwd = false;
   for(p = porthd; p isnt NULL; p = p->next)
      if(p->fwdmin is curmin) {

#ifdef MCH_AMIGA
/* Console only forwards from the process running port A */
         if((p->id == 'Z') && (hostport != 'A'))continue;
#endif

         p->flags setbit p_dofwd;
         p->ec = p->ecuser;
         anyfwd = true;
      }

/*
 *  If any ports forward at this minute, do the forwarding.
 */

   if(anyfwd) {
      setbusy();
      alloff();   /* Turn off connects and monitoring */
      if(s_flag & s_dv) begin_lock();
      readmsg();
      readusr();

/*
 *  Write out mon and calls heard files
 */
      clsmon();

/*
 *  Once a day, do wp and stale
 */
      if(!matchn(ufhs->wpdate, l_date, ln_date)) {
         port->opt1 = '\0';
         port->flds = 1;
         if(s_flag & s_dv) end_lock();
#ifdef MCH_AMIGA
         lock_user();
#endif
         dwuser();
         if(s_flag & s_dv) begin_lock();
         stale();
         strncpy(ufhs->wpdate, l_date, ln_date);
         write_rec(ufl, 0, (char *)ufhs);
#ifdef MCH_AMIGA
         unlock_user();
#endif
      }
      if(s_flag & s_dv) end_lock();

/*
 * Check and see if the mailfile should be compressed
 */
      if(s_param & s_unt)
      if(!matchn(mfhs->date, l_date, ln_date))
      if(unt_hr <= (10 *(l_time[0] - '0') + (l_time[1] - '0')))
      {
#ifdef MCH_AMIGA
         ioport(cport);
#endif
         port->opt2 = 'A';
         setunt();
#ifdef MCH_AMIGA
         ioport(saveport);
#endif
      }

      fwd();
      clnlog();
      setfwd();
      clsmsg();
      clsusr();
      allon();    /* Turn on monitoring and connects */
      clrbusy();
   }

/*
 *  Reset the port flags.
 */

   for(p = porthd; p isnt NULL; p = p->next) {
      p->ec = p->ecmon;
      p->flags clrbit p_dofwd;
   }
}

/*
 *  Reverse forwarding.
 *  Accept messages from the remote MailBox after forwarding to it.
 */

dorev(p)
PORTS *p;
{
   char rcall[6];
   ioport(p);
printf("DOREV\n");
   if(fwdtyp is 'G') return;
   if(fwdtyp is 'D') return;

   if(p->mode & idle) {
      if(fwdtyp is 'F')
         return;
      if(fwdtyp is 'H')
         if(fopts & fw_tried)
            return;
      cmb();
      if(p->mode & idle) return;
   }

   pcall(rcall, path + 2);
   rduser(rcall, p->user);
   log('M', 'F', 'R', path);  /* Log start of reverse forward */
#ifdef MCH_AMIGA
   user_title(p->user->call);
   /* dorev can be called if dofwd does not find anything to send!
      Call fbbfwd before setting transparent mode ... it's done in
      fbbfwd.
   */
   if(s_mart & fbbok) {
      fbb_direction = 0;
      fbbfwd(0);
      return;
   }

#endif

   if(p->tmode) {
      cmdtnc();
      trantnc();
   }

   while(true) {
      outstr("F>\n");
      getln();
      if(p->mode & idle) return;
      parse();

      if(p->opt1 isnt 'S') return;
      sndmsg();
      if(p->mode & gone) return;
      addfwd();
   }
}

/*
 *  F> command: do reverse forward to logged user.
 */

fwdcmd()
{
   register PORTS *p;
   register short ok;

/*
 *  If no fwd.mb file, then do nothing.
 */

printf("FWDCMD dir=%d f='%6.6s' t='%6.6s'\n",fbb_direction,fcall,tcall);
   p = port;
   deep = 0;
   if((ifl[deep] = fopen(fwdfile, "r")) is NULL) {
      p->mode = forced;
      return;
   }

   ioport(cport);

/*
 *  Find the users E, F, G, or H list in the fwd.mb file.
 */

   ok = false;
   while(!ok and (nxtin(cport->line) isnt NULL)) {
      strupr(cport->line);
      parse();
      fwdtyp = cport->opt1;

      switch(fwdtyp) {
      case 'D':
      case 'E':
      case 'F':
      case 'G':
      case 'H':
         pcall(fcall, cport->fld[1]);
         ok = matchn(fcall, p->user->call, ln_call);

         if (!ok) passlst();
         break;

      case '!':
      case 'P':
         passlst();
         break;

      default  : ;   /* 'C', 'R', 'S', 'Y' */
      }
   }

   ioport(p);

   if(ok) {
      log ('M', 'F', 'S', nullstr);      /* Log start of forwarding */
      bldfwd();
      remnl(cport->line);
      strcpy( path, cport->line+6 );
      dofwd(p);
      log ('M', 'F', 'E', nullstr);      /* Log end of forwarding */
   }

   while(deep >= 0) {
      fclose(ifl[deep]);
      deep--;
   }
   if(p->mode is idle) return;
#ifndef MCH_AMIGA
   outstr("*** Done.\n");
#else
   /* It seems that some BBS do not like "Done" so we'll just drop out */
   distnc();
#endif
}

/*
 *  Pass a sublist in the forwarding file.
 */

passlst()
{
   fopts setbit fw_pass;
   while(true) {
      if(nxtin(cport->line) is NULL) {
         fopts clrbit fw_pass;
         return;
      }
      if(iseof(cport->line)) {
         fopts clrbit fw_pass;
         return;
      }
   }
}

/*
 *  Set tnc parameters.
 */

dopar()
{
   register PORTS *p;

   if((p = findport(cport->opt2)) is NULL) {
      passlst();
      return;
   }
#ifdef MCH_AMIGA
/* Don't do this if the port doesn't forward at this time */
   if((p->flags & p_dofwd) == 0) {
      passlst();
      return;
   }
#endif

   if(strlen(cport->fld[0]) > 3)
      if(!chktime()) {
         passlst();
         return;
      }

   ioport(p);
   while(nxtin(cport->line) isnt NULL) {
      if(iseof(cport->line)) {
         ioport(cport);
         return;
      }
      onetnc(cport->line);
   }
   ioport(cport);
}

/*
 *  Get a line from the current port.
 *  Handle disconnect, timeout, and ^F.
 */

getln()
{
   while(!getdat());
   if(port->mode & forced) fopts setbit fw_abort;
   if(port->mode & gone) {
      distnc();
      port->mode = idle;
   }
}

/*
 *  Eat the remote MailBox prompt.
 */

eat()
{
   register char c;
   if(fwdtyp is 'D') c = ':';
   else              c = '>';
   while(true) {
      getln();
      if(!(port->mode & remote)) return;
      if(port->line[0] is '[') isbid();
      if((port->mode & remote) and
                             (port->line[strlen(port->line) - 2] is c)) {
         return;
    }
  } 
}

/*
 *  Connect to a remote Mailox.
 *  Port mode idle at entry.
 *  On return, port mode is remote if the connect worked, else idle.
 */

cmb()
{
   port->flags setbit p_dotmr;
   port->mode = remote;

/*
 * Execute the connect script.
 */
   while(*script) {
      switch(*script++) {
      case 'C':
         contnc(script);
         if(port->mode & idle) return;
         if(port->dev is p_tnc)
            do {
               getln();
               if(port->mode & idle) return;
            }
         while(!iscon(port->line));
         break;

      case 'S':
         outstr(script);
         break;

      case 'R':
         getln();
         if(port->mode & idle) return;
         strupr(port->line);
         if(*script isnt '!')
#ifndef MCH_AMIGA
            if(!search(port->line, script, strlen(script)-1))
#else
/* The new Manx 5.0 compiler uses a LONG for strlen AND for
   sizeof so must change things a bit
*/
            if(!search(port->line, script, (short)strlen(script)-1))
#endif
            {
               distnc();
               port->mode = idle;
               return;
            }
         break;

      default: ;
      }
      while(*script++);  /* Move to next script line */
   }

/*
 *  In theory, now connected to MailBox. Eat login messge.
 */

   eat();
   if(!(port->mode & remote)) return;
   if(s_mart) {
      outstr(vers);
#ifdef MCH_AMIGA
/* If we called them and they are an fbb system, don't call eat().
*/
      if(s_mart & fbbok) {
         return;
      }
#endif
      eat();
   }
}

/*
 *  Forward whatever messages go to this MailBox.
 */

dofwd(p)
PORTS *p;
{
   register char *st;
printf("DOFWD dir=%d f='%6.6s' t='%6.6s'\n",fbb_direction,fcall,tcall);
   filesize = 0;
   st = nxtin(cport->line);
   while(!iseof(cport->line) and (st isnt NULL)) {
      if(!(fopts & fw_ecall)) {
         ioport(cport);
         parse();
         if(cport->opt1 is '<')
            if(chktime())
               if(!(fopts & fw_anytime))
                  filesize = atoi(cport->fld[1]);
         pcall (tcall, cport->fld[0]);
      }
      ioport(p);
#ifndef MCH_AMIGA
      if(findfwd(tcall, bfwd, bfwdn)) {
#else
      if(((s_mart & fbbok) && fbb_direction)
                                         || findfwd(tcall, bfwd, bfwdn)) {
#endif
         fmsg();
         if(fopts & fw_tried)
            if(p->mode & idle) {
               p->mmhs->stat clrbit m_busy;
               wt_mmhs();
               passlst();
               return ;
            }
      }
      if (fopts & fw_ecall) fopts clrbit fw_ecall;
      else st = nxtin(cport->line);
   }
}

/*
 *  Send the message text.
 */

xmtmsg()
{
   register FILE *fl;
#ifdef MCH_AMIGA
   register char *cp,*pp;
#endif

   sprintf(port->line, "%s%u", msgdir, port->mmhs->number);
   if((fl = fopen(port->line, "r")) is NULL)
      nofile(port->line);
   else {
      fseek(fl, (long)RECSIZE, 0);
      while(fgets(tmp->scr, scrmax, fl) isnt NULL) {
         if(chkdis()) {
            fclose(fl);
            return false;
         }
#ifdef MCH_AMIGA
         for(cp = tmp->scr,pp = &tmpstr[0];*cp && (pp < &tmpstr[200]);cp++) {
            if(*cp == passchr)continue;
            /* insert the pass character for stream characters */
            if(passchr) {
               if((*cp == vhfstream) || (*cp == hfstream)) {
                  *pp++ = passchr;
               }
               *pp++ = *cp;
               continue;
            }
            if((*cp >= ' ') && (*cp <= 0176)) {
               *pp++ = *cp;
               continue;
            }
            /*
               Allow BEL BS HT LF VT FF and CR through.
               All others are omitted
            */
            if((*cp >= 7) && (*cp <= '\r')) {
               *pp++ = *cp;
               continue;
            }
         }
         *pp = 0;
         outstr(tmpstr);
#else
         outstr(tmp->scr);
#endif
      }
      fclose (fl);
   }
   if(fwdtyp is 'D') {
      outstr(".\n");
      outstr("y\n");
   }
   else {
      outchar(cpmeof);
      outchar('\n');
   }
   return true;
}

/*
 *  Forward all messages TO or AT tcall
 *  to the MailBox we are connected to.
 */

fmsg()
{
   char *a, *b, *c;
   char hcall[6];
   register PORTS *p;
   register word h;
   register short i, ok, extnr, hasit;
printf("FMSG - '%6.6s'\n",tcall);
   hasit = true;   /* just initialize it to something */

   p = port;
#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
   for(h = mfhs->last; h; h--) {
      if(s_flag & s_dv) begin_lock();
#ifndef MCH_AMIGA
/* Put all this in check_ok() so that fbb can sort out whether to send a
   message or not
*/
      read_rec(mfl, h, (char *)p->mmhs);

      ok = (!(p->mmhs->stat & (m_kill|m_read|m_fwd|m_hold|m_busy)));

      if(ok)
         if(filesize)
            ok = filesize > p->mmhs->size;
/*
 *  Decide whether to forward this one.
 */
      if(ok) {
#ifndef MCH_AMIGA
         if (p->mmhs->ext is 1)
#else
/* Fix bug. A bulletin should only be forwarded to the connected station
   IF and ONLY IF the connected station has not yet received it.
   This code sends it back to the calling station if one of the stations
   in the distribution list for the bulletin is also in the collection
   list for the connected station

   NOT SURE THIS IS RIGHT
*/
         if((p->mmhs->ext == 1) /* && matchn(fcall,tcall,ln_call)*/)
#endif
         {
            ok = false;
            for(i = 0; !ok and (i < p->mmhs->count); i++)
               if(p->mmhs->flag[i])
                  if(wcm(tcall, p->mmhs->call[i])) {
                     ok = true;
                     extnr = i;
                  }
         }
         else if(*p->mmhs->bbs isnt ' ') {
            ok = wcm(tcall, p->mmhs->bbs);
            if(!ok) if(p->mmhs->ext is 2) {
               c = p->mmhs->call[0];
               while(!ok and ((c=strchr(c, '.')) isnt NULL)) {
                  c++;
                  fill(hcall, ' ', ln_call);
                  pcall(hcall, c);
                  ok = wcm(tcall, hcall);
               }
            }
         }
         else
            ok = wcm(tcall, p->mmhs->to);
      }
#else
/* kludge a way to get extnr passed through. check_ok returns extnr if it
   is set (which implies ok and -1 if ok but extnr not set. Zero otherwise.
   extnr is only used  if ->ext == 1  which is only way it could be set
*/
      ok = check_ok(h);
      if(ok > 0)extnr = ok-1;

#endif

      if(ok) {
         p->mmhs->stat setbit m_busy;
         wt_mmhs();
      }
      if(s_flag & s_dv)
         end_lock();

/*
 *  If we DO forward this one, forward this one.
 */
      if(ok) {
         if(fopts & fw_tiout) {
            wait (p->ftime);
            fopts clrbit fw_tiout;
         }
         fopts setbit fw_tried;
         if(p->mode & idle) cmb();
         if(p->mode & idle) return;
#ifdef MCH_AMIGA
         if(s_mart & fbbok) {
         /* This is ugly .. have to release the first message to be sent so
            that fbbfwd can find it again. There's got to be a better way!
            But the forwarding routine doesn't do anything until it has
            found the first message to forward.
         */
            p->mmhs->stat clrbit m_busy;
            wt_mmhs();
            pcall(hcall, path + 2);
            rduser(hcall, p->user);
            fbbfwd(h);
            return;
         }
#endif
         if(*p->mmhs->bbs is ' ')
            prtx("S$B $G < $P");
         else
            if((s_mart&hidok)and(p->mmhs->ext is 2))
               prtx("S$B $G @ $h < $P");
            else
               prtx("S$B $G @ $A < $P");
#ifndef MCH_AMIGA
         if(s_mart&bidok) if (*p->mmhs->bid isnt ' ') {
#else
         if(s_mart&(bidok|midok)) if (*p->mmhs->bid isnt ' ') {
#endif
            outstr(" $");
            a = p->line;
            b = p->mmhs->bid;
            unbl(a, b, ln_bid);
            outstr(p->line);
         }
#ifdef MCH_AMIGA
/* If we are talking to THEBOX and this message has a lifetime, then
   send the lifetime
*/
         if(thebox && p->mmhs->lifetime) {
            sprintf(tmpstr," #%u",p->mmhs->lifetime);
            outstr(tmpstr);
         }
#endif
         outchar('\n');
         getln();
         if(p->mode & idle) return;
         if(s_mart) {
            if(*p->line < ' ') {
               getln();
               if(p->mode & idle) return;
            }
            switch(*p->line) {
            case 'O':
               hasit = false;
               outstr(p->mmhs->title);
               outchar('\n');
               break;
            case 'N':
               hasit = true;
               break;
            default:
               p->mmhs->stat clrbit m_busy;
               wt_mmhs();
               return;
            }
         }
         else {
            hasit = false;        /* you'll want to send msg */
            outstr(p->mmhs->title);
            outchar('\n');
            getln();
            if(p->mode & idle) return;
         }
         if(!hasit) {
            curtim();
            prtx(mm[4]);
            if(!xmtmsg()) {
               fopts setbit fw_tiout;
               return;
            }
         }
         eat();
         if(p->mode & idle) {
            fopts setbit fw_tiout;
            return;
         }
/*
 *  The message actually forwarded.
 *  Kill it, mark it, or whatever.
 */
         sprintf(p->line, "%u %s", p->mmhs->number, path);
         log ('M', 'F', ' ', p->line);
       
         markdis(extnr);

         p->mmhs->stat clrbit m_busy;
         if(p->mmhs->ext isnt 1) {
            pcall(p->mmhs->fwdc, fcall);
            p->mmhs->fport = p->id;
         }
         write_rec(mfl, p->mmhs->rn, (char *)p->mmhs);
         makehdr2();
      }
   }
#ifdef MCH_AMIGA
   /* Only get here if the loop didn't find a message to send. But still
      have to call fbbfwd to receive stuff from the other end
   */
   if(s_mart & fbbok) {
      fbbfwd(0);
   }
#endif
}
markdis(nr)
int nr;
{
  int i, kill, kok;
  kill = false;
  kok = false;
/*  If cc: list exists, mark this call as forwarded. */

  if (port->mmhs->ext is 1)
  {
     port->mmhs->flag[nr] = false;
     for (i = 0; i < port->mmhs->count; i++)
     if (port->mmhs->flag[i]) kok = true;
  }

  if (!kok)
  {
     if ((port->mmhs->type is 'B') or (port->mmhs->ext is 1))
     kill = s_param & s_fkill;
     else kill = s_param & s_kill;
  }

  if (kill) port->mmhs->stat setbit m_kill;
  else if (!kok) port->mmhs->stat setbit m_fwd;

}
#ifdef MCH_AMIGA
check_ok(h)
int h;
{
   register int ok,i,extnr;
   register char *c;
   register PORTS *p;
   char hcall[6];


   extnr = -1;
   p = port;
   read_rec(mfl, h, (char *)p->mmhs);
   ok = (!(p->mmhs->stat & (m_kill|m_read|m_fwd|m_hold|m_busy)));
   if (ok) if(filesize)  ok = filesize > p->mmhs->size;
/*
 *  Decide whether to forward this one.
 */
   if(ok) {
/* Fix bug. A bulletin should only be forwarded to the connected station
   IF and ONLY IF the connected station has not yet received it.
   The old code sent it back to the calling station if one of the stations
   in the distribution list for the bulletin was also in the collection
   list for the connected station
*/
      if((p->mmhs->ext == 1)/* && matchn(fcall,tcall,ln_call)*/) {
         ok = false;
         for (i = 0; !ok and (i < p->mmhs->count); i++)
            if (p->mmhs->flag[i])
               if(wcm(tcall, p->mmhs->call[i])) {
                  ok = true;
                  extnr = i;

               }
      }
      else if(*p->mmhs->bbs isnt ' ') {
         ok = wcm(tcall, p->mmhs->bbs);
         if(!ok)
            if(p->mmhs->ext is 2) {
               c = p->mmhs->call[0];
               while(!ok and ((c=strchr(c, '.')) isnt NULL)) {
                  c++;
                  fill(hcall, ' ', ln_call);
                  pcall(hcall, c);
                  ok = wcm(tcall, hcall);
               }
            }
      }
      else ok = wcm(tcall, p->mmhs->to);
   }
   if(extnr >= 0) {
/* Have to return one more than extnr because it can be zero */
      return(extnr+1);
   }
   if(ok) {
      return(-1);
   }
   return(0);
}
#endif
