/*
 *  MBMAIL.C - 10/03/92 The message file stuff, except for forwarding.
 */

#include "mb.h"
#ifdef MCH_AMIGA
extern char optflags[];
extern char tmpstr[];
extern short all_number;
extern short gotmail;
extern short debug;
short thebox = 0,kambbs = 0;
extern short interflag;
extern int srcmd_flag;     /* for SR */
struct lst_msg last_msg;
/* These have to go in here so that I don't have to compile mbfwd in
   with sysop
*/
int import,export;
FILE *eximfile;
/* continent designator for North America .. .NOAM or .NA */
char *continent = ".NOAM";
#endif

#define btmax 112   /* Max text in beacon line */
#define ln_hier 64

char  orgmsg[6], orgbbs[7], orgtime[5], orgdate[7];

char  *mbfile, *mbbfile, *msgdir, *bidfile, *stfile;
char bbidfile[] = "BID.TMP";


char  *ufwd;  /* Calls with unread msgs, for BT */
char  *bfwd;  /* Calls with unread msgs, for forwarding */

short ufwdm, ufwdn, bfwdm, bfwdn, bidnum;
short tstaleb, tstalen, tstaleu;
short tstale1, tstale2, tstale3;
short rstale1, rstale2, rstale3;
int hasbid, needbid, holdit;

char  *mm[num_mm];
char  wpcall[ln_call];
XBBS  *xbbs;
HOLD  *hold;

MAIL_HDR  *mfhs;
MSG_HDR   *tmmhs;

FILE *bfl;

#ifndef MCH_AMIGA
int mfl, mflb;
#else
int mfl = -1, mflb = -1;
#endif

msgfile(p, n)
char *p;
word n;
{
  sprintf(p, "%s%u", msgdir, n);
}

/*
 *  Open file to hold BIDs
 */

opnbid()
{
#ifndef MCH_AMIGA
  if ((bfl = fopen(bidfile, "a+")) is NULL) { nofile(bidfile); exit(1); }
#else
/* This does not need locking since it only opens and closes the file */
   if((bfl = fopen(bidfile, "a+")) is NULL) {
      nofile(bidfile);
      done(1);
   }
#endif
  fclose(bfl);
}

/*
 *  Write message header.
 */

wt_mmhs()
{
  if (port->mmhs->rn) write_rec (mfl, port->mmhs->rn, (char *)port->mmhs);
}


/*
 *  Get message title.
 */

get_title()
{
  while(!getdat());
  remnl(port->line);
  strncpy(port->mmhs->title, port->line, mhtitl);
}

/*
 *  Parse the [@ bbs] and [< from] fields of a command.
 */

atfrom(i)
int i;
{
  if (*port->fld[i] is '<') pcall(port->mmhs->from, port->fld[i + 1]);
  else if (*port->fld[i] is '@')
  {
    pcall(port->mmhs->bbs, port->fld[i +1]);
    if ((strchr(port->fld[i + 1], '.')) is NULL)
    { chkhier(); return; }
    port->mmhs->ext = 2;
    fill (port->mmhs->call, '\0', 124);
    strncpy(port->mmhs->call[0], port->fld[i + 1], ln_hier);
  }
}

/*
 *  Parse the fields of a send command.
 */

pfld()
{
#ifdef MCH_AMIGA
   short life = 0;         /* ARF ARF! */
   short ltmp;
/* for SR command. Any SR command with one or more arguments is
   an error
*/
   if(port->opt2 == 'R') {
      port->msg = mwhat;
      return(0);
   }
#endif
  hasbid = false;

  port->mmhs->type = port->opt2;
  pcall(port->mmhs->to, port->fld[1]);

  /*  If a message is to an individual and type is blank,
   *  automatically make it a private message, else make it a bulletin.
   */

  if (port->opt2 is ' ')
  if (iscall(port->mmhs->to)) port->mmhs->type = 'P';
     else port->mmhs->type = 'B';

  strncpy(port->mmhs->from, port->user->call, ln_call);
  fill(port->mmhs->bbs, ' ', ln_call);
  fill(port->mmhs->bid, ' ', ln_bid);
  fill(port->mmhs->fwdc, '\0', ln_call);
  port->mmhs->ext = 0;

#ifdef MCH_AMIGA
   /* Check the message type and do some fancy overriding where necessary */
   switch(port->mmhs->type) {

   case 'P':
/*    This fix (for old KAMs so that personal to non-calls get changed to
      be a bulletin) has been removed.
      The reason for removing it is to allow people to send personal
      messages to Internet addresses without having the BBS force the
      message to be a bulletin.

      if(!kambbs)break;
      if(!iscall(port->mmhs->to)) {
         port->mmhs->type = 'B';
      }
*/
      break;
   /* If type is blank then set it to Personal if the 'to' is a valid
      call, otherwise make it a bulletin
   */
   case ' ':

      if(iscall(port->mmhs->to)) {
         port->mmhs->type = 'P';
      }
      else {
         /* If the TO call is one letter long then someone is trying to send
            a THEBOX control message. Throw it away.
         */
         if((port->mmhs->to[1] == ' ') || (port->mmhs->to[1] == 0)) {
            outstr("No - I don't use control messages\n");
            needbid = 0;
            return(0);
         }
         port->mmhs->type = 'B';
      }
      break;
   /* THEBOX can send a 'S$' command. Set the type to Bulletin.
      THEBOX only accepts an 'S' command and ignores any option
      such as 'P', 'B' etc. If the message is TO a valid call
      then it is marked 'P'. If it is not 'P', it will mark it
      as 'B' if either there is no '@' field or if the '@' field
      is a valid call. If it is not 'B' but the FROM call is
      valid then it marks the message as '$'. If the TO field
      is only one character long then the message is marked 'C'.
      Failing all this the message is marked 'H' and is held.
   */
   case '$':
      port->mmhs->type = 'B';
      break;
   /* THEBOX can also send 'SC' which is some form of control message
      that doesn't mean anything to us. Reject it.
   */
   case 'C':
      outstr("No - I don't use control messages\n");
      needbid = 0;
      return(0);
   }
   /* The switch may have changed the type so we have to change the
      opt2 as well. They are almost the same thing.
   */
   port->opt2 = port->mmhs->type;
   /* Force Personal messages to require a BID .... for MID code */
   if(port->mmhs->type == 'P')needbid = 1;

   /* THEBOX can send us a message lifetime indicator at the end of an 'S'
      command. Save the number for later use but remove the field so the
      remaining code will see the bid at the end (if it is there).
   */
   life = -1;
   if(*port->fld[port->flds-1] is '#') {
      ltmp = atoi(&port->fld[port->flds-1][1]);
      if((ltmp > 0) && (ltmp < 256))life = ltmp;
      port->flds--;
   }
   /* If this is a bulletin and the lifetime isn't set then default it.
   */
   if((port->mmhs->type == 'B') && (life == -1))
      life = tstaleb;
#endif

  if (port->flds > 3) atfrom(port->flds - 2);
  if (port->flds > 5) atfrom(port->flds - 4);

#ifdef MCH_AMIGA
   /* routine added to mbuser to see if we have the user 'to' in our
      user record file. If so, then use our @bbs rather than the one
      in the message. We presume that if that user's name is on file
      here and we also have an @bbs for him, then it is likely to
      be just as accurate, or better, than the one in the message.
      In particular, this is useful for setting the @bbs field when
      a user leaves it out of an 'S' command.
   */
   replace_bbs();


#endif

  if (port->flds > 2)
  if(*port->fld[port->flds-1] is '$')
  {
/* MCH_AMIGA */
    if (*(port->fld[port->flds - 1] + 1)/* isnt NULL*/)
    {
    strncpy(port->mmhs->bid, port->fld[port->flds - 1] + 1, ln_bid);
    hasbid = true;
    }
    if (port->flds > 4) atfrom(port->flds - 3);
    if (port->flds > 6) atfrom(port->flds - 5);
  }

  initmsg(true);  

#ifdef MCH_AMIGA
/* Store the message lifetime which will be set to the '#' field of
   a received message if it exists. Otherwise it will be the lifetime
   default for a bulletin or zero.
*/
   if(life)port->mmhs->lifetime = life;

   /* Check the reject.btn file to see if this message should be
      rejected.
   */
   if(test_reject()) {
      outstr("No - Rejected\n");
      needbid = 0;
      return(0);
   }
   /* Checks for unknown @BBS field and leaves it in tmpstr[0] if so */
   /* Must not use tmpstr between here and the warning message */
   ltmp = test_bbs();
#endif

  if(!s_mart) {
#ifdef MCH_AMIGA
/* Part of the 'SR' command */
   if(last_msg.type)prt_subj();
/* WATCH OUT .... I've bracketed this else across these two #ifdefs */
   else {
      if(ltmp) {
         outstr("WARNING: The @BBS field '");
         outstr(tmpstr);
         outstr("' is not known at this BBS\n");
         outstr("         Your message may not be delivered ... continue\n");
      }

#endif
    if (port->user->options & (u_bbs | u_expert)) outstr("Sj:\n");
    else prtx(mm[0]);
#ifdef MCH_AMIGA
   }
/* Part of SR command - don't call get_title */
   if(last_msg.type == 0)
#endif
    get_title();
#ifndef MCH_AMIGA
    return;
#else
    return(1);
#endif
  }
  else {  
#ifdef MCH_AMIGA
      /* Check for unwanted bulletins.
         If this is a bulletin or it has a BID then see if we
         want this bulletin.
         If the @bbs has a corresponding
         msgs/bbs.dis then accept it, otherwise No tnx
      */
      if(optflags[0] && (port->mmhs->type == 'B')) {
         if(tmpstr[0] == 0) {
            outstr("No - Don't want it tnx\n");
            needbid = 0;
            return(0);
         }
      }
#endif
    if (hasbid) {
      checkbid();
      if (!needbid) {
   outstr("NO\n");
   sprintf(port->mmhs->title, "<<%6.6s - %s>>",
        port->user->call, port->fld[port->flds-1]);
   wt_mmhs();
#ifndef MCH_AMIGA
   return;
#else
        return(0);
#endif
      }
      prtx("OK\n");
      get_title();
#ifndef MCH_AMIGA
      return;
#else
      return(1);
#endif
    }
    else {
      prtx("OK\n");
      get_title();
      needbid = true;     /* will check and may assign one later */
#ifndef MCH_AMIGA
      return;
#else
      return(1);
#endif
    }
  }
#ifdef MCH_AMIGA
/* Not sure it can get here ... but just in case */
      return(1);
#endif
}

/*
 *  Create the header line.
 */

makehdr()
{
  register char st,ef,ht;
#ifdef MCH_AMIGA
   register char *p;
#endif

  st = 'N';
  ht = ' ';

/*#ifndef MCH_AMIGA*/
  if (port->mode & ops)
  {
    if (port->mmhs->stat & m_stale) st = 'O';
    if (port->mmhs->stat & m_bull) st = '$';
    if (port->mmhs->stat & m_hold)
    {
      st = 'H';
      if(port->mmhs->htype) ht = port->mmhs->htype;
    }
  }
/*#endif*/
  if (port->mmhs->stat & m_fwd)   st = 'F';
  if (port->mmhs->stat & m_read)  st = 'Y';
  if (port->mmhs->stat & m_kill)  st = 'K';
  if (port->mmhs->stat & m_busy)  st = 'B';
#ifdef MCH_AMIGA
/* Show the sysop the true state of the messages. Doing this first means
   all the other states e.g. 'Y' override these
*/
  if (port->mode & ops)
  {
    if (port->mmhs->stat & m_stale) st = 'O';
    if (port->mmhs->stat & m_bull) st = '$';
    if (port->mmhs->stat & m_hold) st = 'H';
  }
#endif
  if (port->mmhs->ext is 2) ef = '*'; else ef = ' ';
#ifndef MCH_AMIGA
  sprintf(tmp->scr,"%5u %c%c%c%5u %6.6s %6.6s %6.6s%c%3u %4.4s/%4.4s %s\n",
    port->mmhs->number, port->mmhs->type, st, ht, port->mmhs->size,
    port->mmhs->to,port->mmhs->from,port->mmhs->bbs,ef,port->mmhs->read,
    port->mmhs->date + 2, port->mmhs->time, port->mmhs->title);
#else
/* Don't let the title exceed the line length */
   sprintf(tmpstr,"%-27.27s",port->mmhs->title);
   for(p=tmpstr;*p;p++);
   p--;
   while((p > tmpstr) && (*p == ' '))p--;
   p++;
   *p = 0;
  sprintf(tmp->scr,"%5u %c%c%c%5u %6.6s %6.6s %6.6s%c%3u %4.4s/%4.4s %s\n",
    port->mmhs->number, port->mmhs->type, st, ht, port->mmhs->size,
    port->mmhs->to,port->mmhs->from,port->mmhs->bbs,ef,port->mmhs->read,
    port->mmhs->date + 2, port->mmhs->time, tmpstr);
#endif

  if ((port->opt2 is 'K') and (port->mode & ops))
  {
    if (!port->mmhs->fport) port->mmhs->fport = ' ';
    sprintf(tmp->scr+37, ">%6.6s %c->%6.6s %s\n",port->mmhs->fwdd,
       port->mmhs->fport, port->mmhs->fwdc, port->mmhs->title);
  }
}

/*
 * Write mail.dat header into text file
 */

makehdr2()
{
  register char st, c;
  int msfl;
  char flags[mmesn];
  fill (flags, ' ',mmesn);
  fill (tmp->scr, '\0', 256);
  tmp->scr[254] = '\r'; tmp->scr[255] = '\n';
#ifdef MCH_AMIGA
/* Save the lifetime in the header so that mbrestm can recover it */
   tmp->scr[252] = port->mmhs->lifetime;
#endif
  if (port->mmhs->ext is 1)
  {
    for (c=0; c < port->mmhs->count; c++)
    flags[c] = port->mmhs->flag[c] + '0';
  }
  st = 'N';
  if (port->mmhs->stat & m_busy)  st = 'B';
  if (port->mmhs->stat & m_stale) st = 'O';
  if (port->mmhs->stat & m_fwd)   st = 'F';
  if (port->mmhs->stat & m_bull)  st = '$';
  if (port->mmhs->stat & m_hold)  st = 'H';
  if (port->mmhs->stat & m_read)  st = 'Y';
  if (port->mmhs->stat & m_kill)  st = 'K';
  sprintf(tmp->scr,
      "%5u %c%c %5u %6.6s %6.6s %6.6s %6.6s %4.4s %-12.12s %5u\r\n",
    port->mmhs->number, port->mmhs->type, st, port->mmhs->size,
    port->mmhs->to, port->mmhs->from, port->mmhs->bbs,
    port->mmhs->date, port->mmhs->time, port->mmhs->bid, port->mmhs->read);
  if (port->mmhs->ext is 2)
       sprintf(tmp->scr+68, "%c %s\r\n%s\r\n", port->mmhs->ext +'0',
       port->mmhs->call, port->mmhs->title);
  else sprintf(tmp->scr+68, "%c %13.13s   \r\n%s\r\n", port->mmhs->ext +'0',
       flags, port->mmhs->title);

  msgfile(port->cmd, port->mmhs->number);
  if ((msfl = open(port->cmd, O_WRONLY | O_BINARY)) < 0) return;
  write_rec(msfl, 0, (char *)tmp->scr);
  close(msfl);
}

/*
 *  Print a message header.
 */

char prthdr(tit, max_title)
int tit, max_title;
{
  char *a, *b;

  register short i;
  register short docc;

#ifndef MCH_AMIGA
  if (tit) prtx(mm[3]);
#else
/* If we print a title then start the line counter as well. */
  if (tit) {
      prtx(mm[3]);
      pgst(NULL);
      pgck();
  }
#endif
  makehdr();
  if (strlen(tmp->scr) > 79)
  {
    if (!max_title)
    {
      tmp->scr[79] = '\n';
      tmp->scr[80] = '\0';
    }
    else if (lstquit()) return ('Q');
  }
  outstr(tmp->scr);
  if (lstquit()) return ('Q');
  if((port->opt1 is 'L') and
  ((*port->fld[1] isnt ';') and
  (*port->fld[2] isnt ';') and (*port->fld[3] isnt ';')))
     return(' ');
  if(*port->mmhs->fwdc) if (port->mode & ops)
  {
    sprintf(port->line,
      "   <<%6.6s  F->%6.6s", port->mmhs->fwdd, port->mmhs->fwdc);
    outstr(port->line);
    if (!(port->mmhs->ext))
      {
   outchar('\n');
   if (lstquit()) return ('Q');
      }
  }
  if (port->mmhs->ext is 2)
  {
    outstr("    EF:");
    outstr(port->mmhs->call[0]);
    outchar('\n');
    if (lstquit()) return ('Q');
  }
  if (port->mmhs->ext is 1) if (port->mode & ops)
  {
    docc = false;
    for (i = 0; i < port->mmhs->count; i++) if (port->mmhs->flag[i])
     docc = true;

    if (docc)
    {
      outstr("    cc:");
      for (i = 0; i < port->mmhs->count; i++)
      {
   if (port->mmhs->flag[i]) outchar(' '); else outstr(" *");
   outnb(port->mmhs->call[i], ln_call);
      }
      outchar('\n');
      if (lstquit()) return ('Q');
    }
  }
  if (port->mode & ops) if (*port->mmhs->bid isnt ' ')
    {
    outstr("   BID: ");
    a = port->line;
    b = port->mmhs->bid;
    unbl(a, b, ln_bid);
    outstr(port->line);  outchar('\n');
    if (lstquit()) return ('Q');
  }
#ifdef MCH_AMIGA
   if((port->mode & ops) && (port->mmhs->type == 'B')) {
      sprintf(tmpstr,"   Life: %u\n",port->mmhs->lifetime);
      outstr(tmpstr);
      if(lstquit())return('Q');
   }
#endif
  return(' ');
}

lstquit()
{
  if ((pgck() is 'Q') or (chkdis())) return true;
  return false;
}

/*
 *  Read the message, look for the last bbs header.
 *  Set the @ field of the current message to the "at bbs" in that header.
 */

findat()
{
  register short i;

  fill(port->mmhs->bbs, ' ', ln_call);
  msgfile(port->line, port->mmhs->number);
  if ((port->fl = fopen(port->line, "r")) is NULL) { nofile(port->line); return; }
  fseek(port->fl, (long)RECSIZE, 0);
  while(fgets(port->line, linelen, port->fl) isnt NULL)
  {
    if (!parsehd(port->line)) break;
    pcall(port->mmhs->bbs, orgbbs);
  }
  fclose (port->fl);
  chkhier();
}

/*
 *  Parse a message header line.
 */

parsehd(in)
char *in;
{
  register char *p;
  register int count, n;

  if (!ishead(in)) return false;

  p = strchr(in, 'R');
  p++;

  if (*p is ':') p++;
  if (*p is ' ') p++;
  count = 6;
  n = 0;
  while (*p and count--)
  {
    if (!isdigit(*p)) break;
    orgdate[n++] = *p++;
  }
  orgdate[n] = '\0';

  if (*p is '/') p++;

  count = 4;
  n = 0;
  while (*p and count--)
  {
    if (!isdigit(*p)) break;
    orgtime[n++] = *p++;
  }
  orgtime[n] = '\0';

 
  if ((p = strchr(in, '@')) is NULL) return false;
  {
    p++;

/* skip colon or a space in @:call  OR @ call */

    while ((*p is ':')or(*p is ' ')) p++;
    count = ln_call;
    n = 0;
    while (*p and count--)
    {
      if (!isalnum(*p)) break;
      toupper(*p);
      orgbbs[n++] = *p++;
    }
    orgbbs[n] = '\0';
  }

  if (((p = strrchr(in, '#')) isnt NULL) and (*(p+1) is ':'))
  {
    p++;

    while ((*p is ':')or(*p is ' ')) p++;
    count = 5;
    n = 0;
    while (*p and count--)
    {
      if (!isalnum(*p)) break;
      orgmsg[n++] = *p++;
    }
    orgmsg[n] = '\0';
  }
  else
  {
    p = strchr(in, '@');
    p--; count = 5;
    while(count-- and *p isnt ' ') p--;
    p++;
    if (*p is '<') p++;
    count = 5;
    n = 0;
    while (*p and count--)
    {
      if (*p is '@') break;
      orgmsg[n++] = *p++;
    }
    orgmsg[n] = '\0';
  }
  return true;
}


/*
 *  Find a message given it's number.
 */

findmsg(nr)
word nr;
{
  register word i;

#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
  for (i = mfhs->last; i; i--)
  {
    read_rec(mfl, i, (char *)port->mmhs);
    if (port->mmhs->number is nr) return true;
  }
  return false;
}

/*
 *  Create the distribution list, if required.
 */

dodis()
{
  register FILE *dfl;
#ifndef MCH_AMIGA
  if (port->mmhs->ext is 2) return;
  port->mmhs->ext = 0;
#else
/* The code has been modified so that if ->ext is non-zero then dodis()
   has already been called ( == 1) or doesn't need to be called ( == 2).
*/
  if (port->mmhs->ext) return;
#endif
  if (*port->mmhs->bbs is ' ') return;

  unbl(tmp->scr, port->mmhs->bbs, ln_call);

  strcpy(port->line, msgdir);
  strcat(port->line, tmp->scr);
  strcat(port->line, ".DIS");

  if ((dfl = fopen(port->line, "r")) is NULL) return;

  port->mmhs->ext = 1 ;

  for (port->mmhs->count = 0;
    (port->mmhs->count < mmesn) and (fgets(tmp->scr, scrmax, dfl) isnt NULL);
    port->mmhs->count++)
  {
    strupr(tmp->scr);
    pcall(port->mmhs->call[port->mmhs->count], tmp->scr);
#ifdef MCH_AMIGA
/* Blank lines are bad news! */
    if(port->mmhs->call[port->mmhs->count][0] == ' ') {
       port->mmhs->count--;
       continue;
    }
#endif
    if(matchn(port->mmhs->call[port->mmhs->count], port->user->call, ln_call))
    port->mmhs->flag[port->mmhs->count] = false;
    else port->mmhs->flag[port->mmhs->count] = true;
  }
  fclose(dfl);
}

/*
 *  Do we hold this message?
 */

ishold(c)
char *c;
{
  register HOLD *hp;

  for (hp = hold; hp isnt NULL; hp = hp->next)
  if (matchn(hp->call, c, ln_call)) return true;

  return false;
}

/*
 *  Create message utilities - initmsg and cremsg.
 *  Used by "send message", "make message from file",
 *  "kill msg" (service messages), "copy message".
 */

initmsg(h)
int h;
{
  if (s_flag & s_dv) begin_lock();
#ifdef MCH_AMIGA
   check_mail();
#else
  read_rec(mfl, 0, (char *)mfhs);
#endif

  port->mmhs->rn = mfhs->next++;
  port->mmhs->number = mfhs->next_msg++;
#ifdef MCH_AMIGA
   set_mail((long)mfhs->next);
#endif
  port->mmhs->stat = m_busy;
#ifndef MCH_AMIGA
  strncpy(port->mmhs->date, l_date, ln_date);
  strncpy(port->mmhs->time, l_time, ln_time);
#else
/* Use UTC for the file creation date. */
  strncpy(port->mmhs->date, z_date, ln_date);
  strncpy(port->mmhs->time, z_time, ln_time);
#endif
  port->mmhs->read = 0;
  port->mmhs->size = 0;
  if(port->mmhs->ext isnt 2) fill(port->mmhs->call, '\0', 124);
  if(h)sprintf(port->mmhs->title, "<<%6.6s -- disconnected>>",port->user->call);
  pcall(port->mmhs->fwdd, port->user->call, ln_call);

#ifdef MCH_AMIGA
   port->mmhs->lifetime = 0;
#endif
/*
 *  Clean up the file header.
 */

  if (!mfhs->first) mfhs->first = port->mmhs->rn;
  mfhs->last = port->mmhs->rn;
  mfhs->count++;
  write_rec(mfl, 0, (char *)mfhs);
  wt_mmhs();
  mfhs->next_msg--;
  if (s_flag & s_dv) end_lock();
#ifdef MCH_AMIGA
   unlock_mail();
   titles();
#endif
}

cremsg()
{
  register XBBS *xp;

  port->mmhs->stat   = 0;
#ifndef MCH_AMIGA
  strncpy(port->mmhs->date, l_date, ln_date);
  strncpy(port->mmhs->time, l_time, ln_time);
#else
/* Use UTC for the file creation date. */
  strncpy(port->mmhs->date, z_date, ln_date);
  strncpy(port->mmhs->time, z_time, ln_time);
#endif
  port->mmhs->read = 0;
  port->mmhs->size = filesize;

  for (xp = xbbs; xp isnt NULL; xp = xp->next)
  if (wcm(xp->from, port->mmhs->bbs))
  {
    strncpy(port->mmhs->bbs, xp->to, ln_call);
    if (port->mmhs->ext is 2) port->mmhs->ext = 0;
    if (wcm(xp->from, xp->to)) port->mmhs->stat setbit m_bull;
    break;
  }

  if (ishold(port->mmhs->to))
  {
    port->mmhs->stat = m_hold;
    port->mmhs->htype = 'T';
  }
  if (ishold(port->mmhs->from))
  {
    port->mmhs->stat = m_hold;
    port->mmhs->htype = 'F';
  }
  if (ishold(port->mmhs->bbs))
  {
    port->mmhs->stat = m_hold;
    port->mmhs->htype = 'B';
  }

  if (ishold("HUSER "))
  {
    if (!(port->user->options & (u_sysop|u_bbs)))
    if (port->mmhs->type is 'B')
    {
      port->mmhs->stat = m_hold;
      port->mmhs->htype = 'H';
    }
  }

  if (holdit) port->mmhs->stat = m_hold;

  if (*port->mmhs->bid isnt ' ')
  {
    checkbid();
    if (hasbid) if (!holdit) if (needbid)  putbid(true);
  }
  dodis();

  if ((port->mmhs->ext is 1) and (*port->mmhs->bid is ' '))
  {
    port->mmhs->stat = m_hold;
    port->mmhs->htype = 'N';
  }

#ifdef MCH_AMIGA
/* If there's only one call in the distribution list and that's who the
   bulletin was received from, then mark the bulletin as forwarded
*/
   if((port->mmhs->ext == 1) && (port->mmhs->count == 1)) {
      if(port->mmhs->flag[0] == false)
         port->mmhs->stat = m_fwd;
   }
#endif

  wt_mmhs();
  makehdr2();

  if (*port->fld[port->flds-1] isnt '$') port->fld[port->flds-1] = nullstr;

  sprintf(port->line, "%u %-.6s@%-.6s %s %s", port->mmhs->number,
   port->mmhs->to, port->mmhs->bbs, port->fld[port->flds-1], port->mmhs->title);

  log('M', port->opt1, port->opt2, port->line);
  mfhs->next_msg++;
#ifdef MCH_AMIGA
   titles();
#endif
}

/*
 *  Set up the beacon line.
 */

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

#ifdef MCH_AMIGA
   all_number = 0;
   gotmail = 0;
#endif

  bldfwd();
#ifndef MCH_AMIGA
  if (ufwdm > 1)
  {
    strcpy(port->line, "BT Mail for:");
    cp = ufwd;
    lp = port->line + strlen(port->line);
#else
/* ufwdm > 1 is a bug. ufwdm is the MAX # of permitted callsigns.
   It should be ufwdn > 0 which checks for actual number of callsigns.
   I have also moved the strcpy and the alltnc() outside the 'if' 
   so that the beacon text is changed if there is no mail. The problem
   that can occur is that if there is currently one call in the btext
   and then that mail is read, then there is now no call in the btext
   but the original code doesn't change the BText to a null.
*/
   strcpy(port->line, "BT Mail for:");
    cp = ufwd;
    lp = port->line + strlen(port->line);
   if(ufwdn > 0) {
      /* Does sysop have mail? */
      for(i=0;i<ufwdn;i++) {
         if(matchn(&ufwd[i*ln_call],cport->user->call,ln_call)) {
            gotmail++;
            break;
         }
      }
#endif
    while ((cp < ufwd + ln_call * ufwdn) and (lp < port->line + btmax))
    {
      *lp++ = ' ';
      for (i = 0; i < ln_call; i++, cp++) if (*cp isnt ' ') *lp++ = *cp;
    }
#ifndef MCH_AMIGA
    *lp++ = '\n';
    *lp = '\0';
    alltnc(port->line);
  }
#else
   }
   if(lp < port->line + btmax) {
   /* If there's room, add ALL(N) on the end */
      if(all_number) {
         sprintf(tmpstr," ALL(%d)",all_number);
         strcpy(lp,tmpstr);
         lp += strlen(tmpstr);
      }
   }
/* store LF at the end of the beacon command */
   *lp++ = '\n';
   *lp = '\0';
   alltnc(port->line);
   /* setfwd may find that sysop has mail so call titles just in case */
   titles();
#endif
}

/*
 *  General permission check: sysop or TO or FROM.
 */

permit()
{
  if (port->mmhs->stat & (m_kill | m_busy)) return false;
  if (matchn(port->user->call, port->mmhs->to, ln_call) and
     !(port->mmhs->stat & m_hold)) return true;
  if (matchn(port->user->call, port->mmhs->from, ln_call)) return true;
  return false;
}

/*
 *  Return true if user has kill permission for current message.
 */

kpermit()
{
  if (port->mmhs->stat & m_kill) return false;
  if (port->mode & ops) return true;
  if (permit()) return true;
  return ((port->mmhs->type is 'T') and (port->opt2 is 'T'));
}

/*
 *  Return true if user has list permission for current message.
 */

lpermit()
{
  if (port->user->options & u_sysop) return true;
  if (permit()) return true;
#ifdef MCH_AMIGA
/* Users should be able to list a bulletin that has been forwarded.
   I did it this way, rather than remove the m_fwd from the final
   return statement, to avoid any unknown side-effects
*/
   if((port->mmhs->type == 'B') && (port->mmhs->stat & m_fwd))return(true);
#endif
  return ((port->mmhs->type isnt 'P')
      and !(port->mmhs->stat & (m_fwd | m_kill | m_busy | m_hold)));
}

/*
 *  Return true if user has read permission for current message.
 */

rpermit()
{
  if ( port->mode & ops) return true;
  if (permit()) return true;
  return (port->mmhs->type isnt 'P');
}

/*
 *  Clean the mail file.
 *  Force drain of buffers, update of directory item.
 */

clnmsg()
{
#ifdef MCH_AMIGA
   lock_mail();
#endif
  close(mfl);
  mfl = open(mbfile, O_RDWR | O_BINARY);
#ifdef MCH_AMIGA
   unlock_mail();
#endif
}

/*
 *  Close the mail file.
 */

clsmsg()
{
#ifdef MCH_AMIGA
   if(mfl >= 0)
#endif
  close (mfl);
}

/*
 *  Open the mail file.
 */

opnmsg()
{
  register char *tp;

/*
 *  Allocate space for the mail file records.
 */

  mfhs  =  (MAIL_HDR *) malloc(sizeof(MAIL_HDR));
  tmmhs =  (MSG_HDR *)  malloc(sizeof(MSG_HDR));

/*
 *  Allocate the "who has mail" lists.
 */

  ufwd = (char *) malloc (ln_call * ufwdm);
  bfwd = (char *) malloc (ln_call * bfwdm);
#ifndef MCH_AMIGA
  if (bfwd is NULL) errall();
#else
  if (bfwd is NULL) errall(1);
#endif

/*
 *  Open the file. If it does not exist, make one.
 */

#ifdef MCH_AMIGA
   lock_mail();
#endif
  if ((mfl = open(mbfile, O_RDWR | O_BINARY)) < 0)
  {
    if ((mfl = open(mbfile, O_CREAT | O_RDWR | O_BINARY, pmode)) < 0)
#ifndef MCH_AMIGA
      { nofile(mbfile); exit(1); }
#else
      {
         nofile(mbfile);
#ifdef MCH_AMIGA
         unlock_mail();
#endif
         done(1);
      }
#endif
    inithdr();
    mfhs->next_msg = 1;
#ifdef MCH_AMIGA
   titles();
#endif
    write_rec(mfl, 0, (char *)mfhs);
  }

/*
 *  Read the mail file header.
 */

  read_rec(mfl, 0, (char *)mfhs);

#ifdef MCH_AMIGA
   unlock_mail();
#endif
/*
 *  If wrong version mail file, quit now.
 */

  if (mfhs->version isnt mb_version)
  {
#ifndef MCH_AMIGA
    printf("Expected version %d, got version %d\n",
      mb_version, mfhs->version);
#else
    sprintf(tmpstr,"Expected version %d, got version %d\n",
      mb_version, mfhs->version);
    ttputs(tmpstr);
#endif
    nofile(mbfile);
#ifndef MCH_AMIGA
    exit(1);
#else
   done(1);
#endif
  }

}

/*
 *  Initialize the mail file header.
 */

inithdr()
{
#ifdef MCH_AMIGA
   set_mail(1L);
#endif
  mfhs->next    = 1;
  mfhs->first   = 0;
  mfhs->last    = 0;
  mfhs->version = mb_version;
  mfhs->free    = 0;
  mfhs->count   = 0;
  mfhs->unt_msg = 1;

#ifdef MCH_AMIGA
   titles();
#endif
  curtim();
  strncpy(mfhs->date, l_date, ln_date);
  strncpy(mfhs->time, l_time, ln_time);
  fill(mfhs->unu, '\0', mfhsunu);
}

/*
 *  Open mail file and read first record.
 */

readmsg()
{
#ifdef MCH_AMIGA
   lock_mail();
#endif
  mfl = open(mbfile, O_RDWR | O_BINARY);
  read_rec(mfl, 0, (char *)mfhs);
#ifdef MCH_AMIGA
   unlock_mail();
#endif
}

/*
 *  Does this station want us to send BIDs ?
 */

isbid()
{
  register char *f;

#ifdef MCH_AMIGA
/* strip the 8th bit from the SID just in case we are running transparent
   and they have the wrong parity
*/
   for(f=port->line;*f;f++)*f = *f & 0177;
#endif

/*  Is this a sid? It must have a '-' and end with a ']'  */

  if ((port->line[strlen(port->line) - 2] isnt ']' ) or
     ((f =  strrchr(port->line, '-')) is NULL))
     return;

#ifdef MCH_AMIGA
/* Look for THEBOX */
   if(matchn(&port->line[1],"THEBOX",6) ||
      matchn(&port->line[1],"DL5UY",5))
      thebox = 1;
/* Look for the newer KAM BBS which can handle BBS mail */
/* The KAM wouldn't need to be specifically recognized except that
   it only allows sending personal messages. So if someone sends
   a personal meesage to ALL @ ALLCAN it ought to be a bulletin.
   The program will change such personal messages to bulletins.
*/
   if(matchn(&port->line[1],"KAM",3)) kambbs = 1;
#endif
/*  Look for special characters in the last field.  */

  f++;
  for (; *f isnt ']';f++)
  switch(*f)
  {
     case 'H' : s_mart setbit hidok; break;
     case '$' : s_mart setbit bidok; break;

#ifdef MCH_AMIGA
     case 'F' : s_mart setbit fbbok; break;
     case 'B' : s_mart setbit cmpok; break;
     case 'M' : s_mart setbit midok; break;
#ifdef MCH_ZOO
/* I was trying to get C-BBS to use the zoo compression routines instead of
   the lzhuf from FBB. But with no success so far.
*/
     case 'Z' : s_mart setbit zoook; break;
#endif
#endif


  }
#ifdef MCH_AMIGA
   /* If both B and Z are set then Z overrides (Z is better) */
   if((s_mart & (cmpok|zoook)) == (cmpok|zoook)) {
      s_mart clrbit cmpok;
   }

   /* If FBB compression bit is set but FBB itself is not, then clear the
      compression
      If option #C is selected force the compression off anyway.
   */
   if((s_mart & (fbbok|cmpok)) == cmpok)s_mart clrbit cmpok;
   if(!optflags[2])s_mart clrbit cmpok;

#endif

}

/*
 *  Check to see whether we already have this BID.
 */

checkbid()
{
   FILE *out;
   char *a, *b;

   if(*port->mmhs->bid is ' ') {
      needbid = true;
      return;
   }
#ifdef MCH_AMIGA
   lock_bid();
#endif
   if((out = fopen(bidfile, "r")) is NULL) {
#ifdef MCH_AMIGA
      unlock_bid();
#endif
      nofile(bidfile); return; 
   }
   while(fgets(port->line, linelen, out) isnt NULL) {

    /* the first 4 characters are the date */

      strcpy(port->cmd, port->line + 4);
      a = port->cmd;
      remnl(a);

      a = port->line;
      b = port->mmhs->bid;
      unbl(a, b, ln_bid);

      if(match(port->cmd, port->line)) {
         needbid = false; 
         fclose(out);
#ifdef MCH_AMIGA
         unlock_bid();
#endif
         return;
      }
   }
   needbid = true;
   fclose(out);
#ifdef MCH_AMIGA
   unlock_bid();
#endif
}

putbid(y)
int y;
{
   FILE *out;
   char *a, *b;

#ifdef MCH_AMIGA
   lock_bid();
#endif
   if ((out = fopen(bidfile, "a")) is NULL)
   {
#ifdef MCH_AMIGA
   unlock_bid();
#endif
     port->msg = mcant; return;
   }
   a = port->cmd;
   if (y) b = port->mmhs->bid; else b = tmp->scr;
   unbl( a, b, ln_bid);
   sprintf (port->line, "%4.4s%s\n", port->mmhs->date+2, port->cmd);
   if (s_flag & s_dv) begin_lock();
   fputs(port->line, out);
   if (s_flag & s_dv) end_lock();
   fclose(out);
#ifdef MCH_AMIGA
   unlock_bid();
#endif
}


/****************************************
 *                                      *
 *  Code for the commands starts here   *
 *                                      *
 ****************************************/

/*
 *  GM or GR command: backup the mail file.
 */

untmsg()
{
  register word inhdr, me;
  if (port->opt2 isnt 'A') { if (sure()) return false; }
  if (!mfhs->count) { port->msg = mm[5]; return false; }
  prtx(mm[6]);

  close(mfl);         /*  Close current.  */

  unlink(mbbfile);    /*  Delete backup   */

/*
 *  Copy current to backup.
 */

  if (samedir(mbfile, mbbfile)) rename(mbfile, mbbfile);
  else copy(mbfile, mbbfile, false);

  unlink(mbfile);     /*  Delete current.  */

/*
 *  Open new current and backup.
 */

  mfl  = open(mbfile,  O_CREAT  | O_RDWR | O_BINARY, pmode);
  mflb = open(mbbfile, O_RDONLY | O_BINARY);

  read_rec(mflb, 0, (char *)mfhs);
  me = mfhs->last;
  inhdr = mfhs->first;
  inithdr();

  if (port->opt2 is 'R')
  {
    if (port->flds is 1) mfhs->next_msg = 1;
    else mfhs->next_msg = atoi(port->fld[1]);
  }


  while(inhdr <= me)        /*  For each message header ... */
  {
    read_rec(mflb, inhdr, (char *)port->mmhs); /* Read the header. */

/*
 *  Tell the sysop about this message.
 */

    sprintf(port->line, "%c %6u Size %6u # %6u Read %6u", port->mmhs->type,
      inhdr, port->mmhs->size, port->mmhs->number, port->mmhs->read);
    outstr(port->line);

    inhdr++;

    if (!(port->mmhs->stat & ( m_kill | m_busy)))
    {
       outstr("\n");

/*
 *  If renumbering messages, renumber this message.
 */

       if (port->opt2 is 'R')
       {
    msgfile(port->line, port->mmhs->number);
    msgfile(port->cmd,  mfhs->next_msg);
    rename(port->line, port->cmd);
    port->mmhs->number = mfhs->next_msg++;
       }

/*
 *  Write the header.
 */

       port->mmhs->rn = ++mfhs->count;
       wt_mmhs();
    }
    else arcmsg();
  }


/*
 *  Write the file header.
 */
  if (mfhs->count) mfhs->first = 1;
  mfhs->next = mfhs->count + 1;
#ifdef MCH_AMIGA
   set_mail((long)mfhs->next);
#endif
  mfhs->last = mfhs->count;
  mfhs->unt_msg = mfhs->next_msg;
  write_rec(mfl, 0, (char *)mfhs);
  close(mflb);
  clnmsg();
#ifdef MCH_AMIGA
   titles();
#endif
  return(true);
}


/*
 *  Print headers of unread messages for this user.
 */

newmsg()
{
  if (findfwd(port->user->call, ufwd, ufwdn) or
      findfwd(port->user->call, bfwd, bfwdn))
  {
    prtx(mm[2]);
    port->opt2 = '\0';
    port->flds = 1;
    lstmsg();
  }
}

/*
 *  L command, list messages.
 */

lstmsg()
{
  register short done, ok;
  word h, found, more, start;
  int max_title;
#ifdef MCH_AMIGA
   int quote;
   quote = 0;
   interflag = 0;
#endif

  if(port->mode & ops) max_title = false;
  else max_title = true;

/*
 *  First set up arguments.
 */

  found = 0; more = 0; done = false;
#ifndef MCH_AMIGA
  if ((*port->fld[1] is ';')or(*port->fld[2] is ';')or(*port->fld[3] is ';'))
#else
/* The ';' must be the last thing on the line if it is there.
   The previous argument can be a quoted string to do a search of
   the title of those articles that otherwise qualify.
*/
   if(*port->fld[port->flds-1] is ';')
#endif
  { port->flds--; max_title = true; }

#ifdef MCH_AMIGA
/* If the last argument is a quoted string, remember where it is but
   pretend to remove it
*/
   if(*port->fld[port->flds-1] is '"') {
      quote = --port->flds;
   }
#endif

  switch(port->opt2)
  {
    case '@' :
    case '<' :
    case '>' : pcall(tcall, port->fld[1]); break;
    case 'S' : if (port->flds is 1) {port->msg = mwhat; return;}
    case '\0': break;
    case 'E' :
    case ' ' : if (port->flds is 1) more = port->user->msg_number;
    default  :
      if (port->flds > 1)
      {
   if (!num(port->fld[1])) { port->msg = mwhat; return; }
   more = atoi(port->fld[1]);
      }
      if (port->flds is 3)
      {
   if (!num(port->fld[2])) { port->msg = mwhat; return; }
   start = atoi(port->fld[2]);
      }
  }

/*
 *  Log it, unless is initial login check for msgs.
 */

  if (port->opt2)
  {
    sprintf(port->line, "%u", more);
    log('M', 'L', port->opt2, port->line);
  }

/*
 *  Paw through the messages and show what requested.
 */

#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
  for (h = mfhs->last; h and !done; h--)
  {
    read_rec(mfl, h, (char *)port->mmhs);
    if ((port->opt2 is 'L') or ((port->opt2 is 'E') and (port->flds is 2)))
      done = (found is more); else done = (port->mmhs->number < more);

    ok = !done;
    if (port->flds is 3) if (ok)
      ok = (port->mmhs->number <= start);
/*
 *  Does this user have read permission for this message?
 */

    if (ok) ok = lpermit();
    if (ok) if (port->mmhs->stat & m_kill)
    ok=((port->opt2 is 'K')or(port->opt2 is 'E')or(port->opt2 is 'S'));
    if (ok) if (port->mmhs->stat & m_busy) ok = (port->opt2 is 'E');

/*
 *  Is this message wanted?
 */

    if (ok) switch(port->opt2)
    {
      case '\0': ok = matchn(port->user->call, port->mmhs->to, ln_call); break;
      case 'E' : break;
      case 'K' : ok = (port->mmhs->stat & m_kill); break;
      case 'F' : ok = (port->mmhs->stat & m_fwd);  break;
      case 'H' : ok = (port->mmhs->stat & m_hold); break;
      case 'L' : break;
      case 'M' : ok = matchn(port->user->call, port->mmhs->to, ln_call);
      if (!ok) ok = matchn(port->user->call, port->mmhs->from, ln_call);
      break;

      case 'O' : ok = (port->mmhs->stat & m_stale); break;
#ifdef MCH_AMIGA
/* Fix up strlen in 2 calls to search() .*/
#endif
      case 'S' : ok = (search(strupr(port->mmhs->title), port->fld[1],
            (short)strlen(port->fld[1]))or search(port->mmhs->to,
            port->fld[1],(short) strlen(port->fld[1]))); break;
      case 'U' : ok = !((port->mmhs->type is 'B')or(port->mmhs->type is 'A')
             or (port->mmhs->stat & (m_fwd | m_read))); break;
      case 'Y' : ok = (port->mmhs->stat & m_read);  break;
#ifndef MCH_AMIGA
      case '@' : ok = matchn(tcall, port->mmhs->bbs, ln_call); break;
      case '<' : ok = matchn(tcall, port->mmhs->from, ln_call); break;
      case '>' : ok = matchn(tcall, port->mmhs->to, ln_call); break;
#else
/* Permit a wildcard in these three forms of the 'L' command */
/* wmatch is in dir.c */
      case '@' : ok = wmatch(port->mmhs->bbs ,tcall); break;
      case '<' : ok = wmatch(port->mmhs->from,tcall); break;
      case '>' : ok = wmatch(port->mmhs->to  ,tcall); break;
#endif
      default  : ok = ((port->mmhs->type is port->opt2) or
             (port->opt2 is ' '));
    }
#ifdef MCH_AMIGA
   if(ok && quote) {
      /*
         If there was a quoted string in the argument list,
         check to see if it occurs in the title. If not,
         then ignore it. (umatch is in dir.c)
      */
      if(!umatch(&port->mmhs->title[0],port->fld[quote]))ok = 0;
   }
   if(interflag && (port != cport)) {
      return;
   }
#endif
    if (ok) if (prthdr(!found++, max_title) is 'Q') return;
  }
  if (!found) port->msg = mfind;
  s_flag setbit s_update;
}

/*
 *  CM command: duplicate a message.
 */

dupmsg()
{
  word tmpsize;
  if (!findmsg(atoi(port->fld[2]))) { port->msg = mnmsg; return; }
  port->opt1 = 'S';

  prthdr(true, true);
  pcall(port->mmhs->to, port->fld[1]);
  fill(port->mmhs->bbs, ' ', ln_call);
  port->mmhs->ext = 0;

  if (port->flds > 3) atfrom(port->flds - 2);
  if (port->flds > 5) atfrom(port->flds - 4);
  tmpsize = port->mmhs->size;

#ifdef MCH_AMIGA
/* Override @bbs if the user is on file */
   replace_bbs();
#endif

  msgfile(port->cmd, port->mmhs->number);
  initmsg(false);
  msgfile(port->line, mfhs->next_msg);
  copy(port->cmd, port->line, false);
  filesize = tmpsize;
  cremsg();
}

/*
 *  F command: copy a message to a file.
 */

filmsg()
{
  register char *p;
  register short hdr, append, inhdr;
  register FILE *out;

  if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }

  hdr = true;
  append = false;
  inhdr = false;

  if (port->flds is 4) for (p = port->fld[3]; *p; p++) switch (*p)
  {
    case 'A' : append = true; break;
    case 'N' : hdr    = false; break;
    case 'I' : inhdr  = true; break;
    default: ;
  }

  if (port->opt2 is ' ') strcpy(port->line, port->fld[2]);
  else if (getdir(port->fld[2]) is NULL) { port->msg = mndir; return; }

  if (append) out = fopen (port->line, "a"); else
  {
    if ((out = fopen (port->line, "r")) isnt NULL)
      { fclose(out); port->msg = mexst; return; }
    out = fopen (port->line, "w");
  }

  if (out is NULL) { port->msg = mcant; return; }

  sprintf(tmp->scr, "%s %s", port->fld[1], port->line);
  log('M', 'D', port->opt2, tmp->scr);

  prthdr(true, true);

  if (hdr) fputs(tmp->scr, out);

  msgfile(port->cmd, port->mmhs->number);

  if ((port->fl = fopen(port->cmd, "r")) is NULL)
    { fclose(out); nofile(port->cmd); return; }
  fseek( port->fl, (long)RECSIZE, 0);
  while (fgets(tmp->scr, linelen, port->fl) isnt NULL)
  {
    if (!inhdr)
    {
      if (!parsehd(tmp->scr)) fputs(tmp->scr, out);
    }
    else
    fputs(tmp->scr, out);
  }
  fclose(port->fl);
  fclose(out);
}

/*
 *  Upload the message text file.
 */

uloadm(tname)
char *tname;
{
  register char *tp;
  register PORTS *p;
  short first, head;
  char *a, *b;
#ifdef MCH_AMIGA
   register int i;
   char orgcall[7];
#endif
  orgbbs[0] = '\0';

  p = port;
  if ((p->fl = fopen(tname, "w")) is NULL) { p->msg = mcant; return false; }
  fill(tmp->scr, '.', RECSIZE);
  tmp->scr[256] = '\0';
  fputs( tmp->scr, p->fl);

  first = true;
  head = true;
  filesize = 0;
  while (true)
  {
    while(!getdat());

/*
 *  If user disconnected, timed out, or forced off, zap the file.
 */

    if (p->mode & gone)
    {
      fclose(p->fl);
      return false;
    }

    if (head)
    {
      if (!parsehd(p->line)) head = false;
      else

/*  If this is a ping-pong message */
      if (s_param & s_ping)
      {
   a = p->cmd;
   b = cport->user->call;
   unbl(a, b, 6);
   if (matchn(orgbbs, p->cmd, ln_call))
   {
     holdit = true;
     port->mmhs->htype = 'P';
   }
      }
#ifdef MCH_AMIGA
/* Check each R: line in the bulletin header. If the BBS call is in our
   distribution list for this bulletin, then mark them as already having
   received the bulletin.
*/
      if(head && p->mmhs->ext == 1) {
         pcall(orgcall,orgbbs);
         for(i = 0;i < p->mmhs->count; i++) {
            if(p->mmhs->flag[i]) {
               if(matchn(orgcall,p->mmhs->call[i],ln_call)) {
                  p->mmhs->flag[i] = false;
                  break;
               }
            }
         }
      }
#endif
    }
/*
 *  If the first line is not a header (thus it is a human entering
 *  the message), make sure there is an initial blank line before
 *  the body of the message.
 */

    if (first)
    {
      first = false;
      if (*orgbbs is '\0') if (*p->line isnt '\n') fputs("\n", p->fl);
    }

/*
 *  Stuff the line into the file.
 */

    if (match(p->line, "/EX\n") or match(p->line,"/ex\n"))
    {
      fclose(p->fl);
      return true;
    }


    if ((tp = strchr(p->line, cpmeof)) is NULL)
    {
      filesize += strlen(p->line);
      fputs(p->line, p->fl);
    }
    else
    {
      if (tp isnt p->line)
      {
         *tp++ = '\n';
         *tp   = '\0';
         filesize += strlen(p->line);
         fputs(p->line, p->fl);
      }
      fclose(p->fl);
      return true;
    }
  }
}

/*
 *  "Display the message text" utility.
 */

dloadm(sh)
short sh;
{
  short first;

  sprintf(port->line, "%u", port->mmhs->number);
  log('M', 'R', port->opt2, port->line);
  port->mmhs->read++;
  if (matchn(port->user->call, port->mmhs->to, ln_call))
    port->mmhs->stat setbit m_read;
  if (port->mmhs->ext is 1)
  if (matchn(port->user->call, port->mmhs->call[0], ln_call))
  {
    markdis(0);
    port->mmhs->stat clrbit m_hold;
  }
  wt_mmhs();
  makehdr2();
  prthdr(true, true);

  msgfile(port->line, port->mmhs->number);

  if ((port->fl = fopen(port->line, "r")) is NULL)
    { nofile(port->line); return; }

#ifdef MCH_AMIGA

/* Code to save the information that will allow the Send Reply command
   to construct a proper reply to this message. At the moment a reply
   is permitted only for personal messages addressed to the reader.
   (I'm not sure that this test is needed, but play it safe).
   REMOVED until I have the SR command working properly.
*/
#ifdef MCH_SR
   if(port->mmhs->type == 'P') {
                   /* matchn(port->user->call,port->mmhs->to,ln_call)) { */
      last_msg.type = 'P';
      unbl(last_msg.from,port->mmhs->from,ln_call);
      unbl(last_msg.bbs,port->mmhs->bbs,ln_call);
      strncpy(last_msg.title,port->mmhs->title,mhtitl);
   }
   else last_msg.type = 0;
#else
   last_msg.type = 0;
#endif

   /* Start the line counter */
   pgst(NULL);
#endif

  fseek( port->fl, (long)RECSIZE, 0 );
  pgck();   /* First line of header */
  pgck();   /* Second line of header */
  pgck();   /* Path line */
  if (port->mmhs->ext) pgck();
  if (*port->mmhs->bid isnt ' ') pgck();

  strcpy(tmp->scr, "  Path: ");
  first = true;

#ifdef MCH_AMIGA
   interflag = 0;
#endif

  while(fgets(port->line, linelen, port->fl) isnt NULL)
  {

#ifdef MCH_AMIGA
   if(interflag && (port != cport)) {
      break;
   }
#endif

    if (!sh)
    {
      sh = !parsehd(port->line);
      if (sh)
      {
   if (!first)
   {
     strcat(tmp->scr, "\n\n");
     outstr(tmp->scr);
     pgck();
     prtx("Date: $j/$k\n");  pgck();
     prtx("From: $P @ $a\n");  pgck();
     prtx("Message-Id: <$m@$a>\n");  pgck();
     prtx("To: $G @ ");
     if (*port->mmhs->bbs is ' ')  prtx("$O\n");
     else if (port->mmhs->ext is 2) prtx("$h\n");
     else prtx("$A\n");  pgck();
     prtx("Subject: $E\n\n");  pgck();
   }
      }
      else
      {
   if (!first) strcat(tmp->scr, "!");
   strcat(tmp->scr, orgbbs);   
   first = false;
      }
    }

    if (sh)
    {
#ifdef MCH_AMIGA
/* Use str_search to output the string and remove any offending chars */
      str_search(port->line);
#else
      outstr(port->line);
#endif
      if (lstquit()) { fclose(port->fl); return; }
    }
  }
  fclose (port->fl);
}

/*
 *  RM command: read my messages.
 */

rdmsgm()
{
  register short found;
  register word h;

  found = false;
#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
  for (h = mfhs->first; h and h <= mfhs->last; h++)
  {
    read_rec(mfl, h, (char *)port->mmhs);
    if ((!(port->mmhs->stat & (m_read|m_kill|m_fwd|m_hold|m_busy)) and
      (matchn(port->user->call, port->mmhs->to, ln_call))) or
      (!(port->mmhs->stat & (m_read|m_kill|m_fwd|m_busy)) and
      (port->mmhs->ext is 1) and
      matchn(port->user->call, port->mmhs->call[0], ln_call) and
      port->mmhs->flag[0]))
    {
      dloadm(port->mode & ops);
      found = true;
      if (pause() is 'Q') return;
    }
  }
  if (!found) port->msg = mfind;
}

/*
 *  R command: read one message.
 */

rdmsg()
{
  char sn[6];
  if ((strlen(port->fld[1]) > 5) or (!num(port->fld[1])))
  {
     port->msg = mwhat;
     return;
  }
  strcpy(sn, port->fld[1]);
  if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  if (!rpermit())                   { port->msg = mprot; return; }

  dloadm(port->opt2 is 'H');
  if ((port->mmhs->type is 'T')and(!(port->mmhs->stat&(m_busy|m_kill|m_fwd))))
  {
    outstr("\nAre you going to deliver this message (Y/N)?\n");
    while (!getdat());
    if(toupper(*port->line) is 'Y')
    {
      port->opt2 = 'T';
      strcpy(port->fld[1], sn);
      sprintf(port->line, "KT %s\n", sn);
      outstr(port->line);
      klmsg();
    }
  }
}

/*
 *  KF, KM, KO, KY, KK commands, kill multiple messages.
 */

klmsgm()
{
  register short ok;
  register short found;
  word h, next;
    if (port->flds is 2) pcall(tcall, port->fld[1]);

#ifdef MCH_AMIGA
   check_mail();
   unlock_mail();
#endif
    found = false;
    for (h = mfhs->first; h and h <= mfhs->last; h++)
    {
      read_rec(mfl, h, (char *)port->mmhs);

      ok = kpermit();
      if (ok) ok = !(port->mmhs->stat & m_hold);

      if (ok) if (port->flds is 2) ok = matchn(tcall, port->mmhs->to, ln_call);

      if (ok) switch(port->opt2)
      {
   case 'F' : ok = (port->mmhs->stat & m_fwd); break;
   case 'M' :
       ok = ((port->mmhs->stat & m_read) and
       matchn(port->user->call, port->mmhs->to, ln_call));
       break;
   case 'O' : ok = (port->mmhs->stat & m_stale); break;
   case 'Y' : ok = (port->mmhs->stat & m_read);  break;
      }

      if (ok)
      {
   sprintf(port->line, "%u", port->mmhs->number);
   log('M', 'K', port->opt2, port->line);
   prtx(mm[7]);
   found = true;
   port->mmhs->stat setbit m_kill;
   write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
   makehdr2();
      }
    }
#ifdef MCH_AMIGA
   titles();
#endif
    if (!found) port->msg = mfind;
}

klmult()
{
  mult(false);
}

rdmult()
{
  mult(true);
}

/*
 *  Handling multiple messages.
 */

mult(x)
int x;
{
  static char msgn[25];
  int i;

  strncpy(&msgn[0], port->fld[2], 5);
  strncpy(&msgn[6], port->fld[3], 5);
  strncpy(&msgn[12], port->fld[4], 5);
  strncpy(&msgn[18], port->fld[5], 5);
  if (x) rdmsg();
  else
  {
    outstr(port->fld[1]);
    klmsg();
  }
    prtx(port->msg);
  for ( i=0; msgn[i]; i += 6)
  {
    strcpy(port->fld[1], &msgn[i]);
#ifndef MCH_AMIGA
    if (x) rdmsg();
#else
    if(x) {
      if(pause() == 'Q')break;
       rdmsg();
    }
#endif
    else
    {
      outstr(port->fld[1]);
      klmsg();
    }
    prtx(port->msg);
    port->msg = NULL;
  }
}

/*
 *  K command, kill a message.
 */

klmsg()
{
  register short dosvc;
  unsigned int org_num;

  if (!num(port->fld[1]))           { port->msg = mwhat; return; }
  if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  if (port->mmhs->stat & m_kill)    { port->msg = mnmsg; return; }
  if (!kpermit())                   { port->msg = mprot; return; }

  log('M', 'K', port->opt2, port->fld[1]);

  dosvc = (port->opt2 is 'T') and
     (port->mmhs->type is 'T') and
     (s_param & s_svc);

  if (dosvc) org_num = atoi(port->fld[1]);

/*
 *  Marked the message as  Killed.
 */

  if(port->opt2 is 'A') port->mmhs->stat setbit m_noarc;
  port->mmhs->stat setbit m_kill;
  write_rec(mfl, port->mmhs->rn, (char *)port->mmhs);
  makehdr2();

/*
 *  If this is KT of T type message, and we do service messages,
 *  do the service message.
 */

  if (dosvc)
  {
    port->mmhs->ext = 0;
    findat();
    port->opt1 = 'S';
    strncpy(port->mmhs->to, port->mmhs->from, ln_call);
    strncpy(port->mmhs->from, cport->user->call, ln_call);
    port->mmhs->type = 'P';
    fill(port->mmhs->bid, ' ', ln_bid);
    initmsg(false);
    msgfile(port->line, mfhs->next_msg);
    port->fl = fopen(port->line, "w");
    fseek(port->fl, (long)RECSIZE, 0);
    fprintf(port->fl, "Msg %5u taken from %6.6s by %6.6s at %4.4s on %6.6s\n",
      org_num, cport->user->call, port->user->call, l_time, l_date);
    fclose(port->fl);

    filesize = 56;
    cremsg();
  }
  port->msg = mdone;
#ifdef MCH_AMIGA
   titles();
#endif
}

/*
 *  S command: send a message.
 */

sndmsg()
{
  char *a, *b;

  holdit = false;   /* initialize it to something */
#ifndef MCH_AMIGA
  pfld();
#else
   if(srcmd_flag == 0)last_msg.type = 0;
/* If there's an error in the command then return */
   if(pfld() == 0) {
#ifdef MCH_AMIGA
      /* If pfld() fails then skip to end of this message */
      if(import) {
         while(fgets(port->line,250,eximfile)) {
            if(match(port->line, "/EX\n") || match(port->line,"/ex\n"))
               return;
         }
         *port->line = 0;
      }
#endif
      return;
   }

/* Initialize ->ext to zero so that dodis() will detect that sndmsg has
   already done it and then cremsg won't redo it. This is so that the
   uloadm routine can use parsehd() to see if an incoming bulletin has
   already been seen by other BBS in the distribution list and then we
   won't have to send it to them.
   The only other call to dodis() previously sets ->ext to zero.
*/
   if(port->mmhs->ext != 2)port->mmhs->ext = 0;
   dodis();
#endif

  if (!isalnum(*port->mmhs->to))
  {
    holdit = true;
    port->mmhs->htype = 'C';
  }
  if (port->mode & gone) return;

  if (s_mart) {
    if (!needbid) return;
  }
  else {
    if (port->user->options & (u_bbs | u_expert))
    outstr("Msg:\n");
    else prtx(mm[1]);
  }

  msgfile(port->cmd, mfhs->next_msg);
  if (!uloadm(port->cmd)) return;

/*
 *  If this is a Bulletin and has no BID, 
 *  parse the headers and give it one.
 */
#ifndef MCH_AMIGA
  if (!iscall(port->mmhs->to))
  if (port->mmhs->type is 'B')
  {
#else
/* Add BID or a MID to any kind of message */
  if(*port->mmhs->bid == ' ') {
   unbl(port->line, cport->user->call, ln_call);
#endif
   a = port->line;
   b = cport->user->call;
   unbl(a, b, 6);

/* Default the BID as to coming from this BBS with our msg number. */

   sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);

/* Now check the parsed headers if it came from another BBS. */

   if (*orgbbs isnt '\0') sprintf(tmp->scr, "%s_%s", orgmsg, orgbbs);

   if (!hasbid)
   {
      strncpy(port->mmhs->bid, tmp->scr, ln_bid);
      hasbid = true;
   }
   else if (!matchn(port->mmhs->bid, tmp->scr, ln_bid)) putbid(false);

   if (port->user->options & u_hold)
   {
     holdit = true;
     port->mmhs->htype = 'U';
   }
  }
  checkbid(); 
  if (!needbid)
  {
    holdit = true;
    port->mmhs->htype = 'D';
  }
  cremsg();
}

/*
 *  SM command, send a message to a distribution list.
 */

sndmlt()
{
  register FILE *fl;
  char fn[80];
  register short first = true;
  word tmpsize;
  
  holdit = false;
  fill(port->mmhs->bid, ' ', ln_bid);

  if ((fl = fopen(port->fld[1], "r")) is NULL)
    { nofile(port->fld[1]); return; }

  prtx(mm[0]);
  get_title();
  if (port->mode & gone) { fclose(fl); return; }

  if (port->flds is 3) if (*port->fld[port->flds-1] is '$')
  {
/* MCH_AMIGA */
    if (*(port->fld[port->flds-1] + 1) /*isnt NULL*/)
    {
      strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
      hasbid = true;
    }
  }

  prtx(mm[1]);

  strncpy(port->mmhs->from, port->user->call, ln_call);
  port->mmhs->ext = 0;
  initmsg(false);
  msgfile(fn, mfhs->next_msg);
  if (!uloadm(fn)) { fclose(fl); return; }
  tmpsize = filesize;

  while (fgets(port->line, linelen, fl) isnt NULL)
  {
    parse();
    if (!first)
    {
      port->mmhs->ext = 0;
      initmsg(false);
      msgfile(port->line, mfhs->next_msg);
      copy(fn, port->line, false);
    }
    port->mmhs->type = port->opt2;
    pcall(port->mmhs->to, port->fld[1]);
    fill(port->mmhs->bbs, ' ', ln_call);

    if(port->flds > 3) atfrom(2);
    if(port->flds > 5) atfrom(4);
    filesize = tmpsize;
#ifdef MCH_AMIGA
   replace_bbs();
/* Put a BID or MID on this file if needed */
   if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
      unbl(port->line, cport->user->call, ln_call);

      /* Default the BID as to coming from this BBS with our msg number. */

      sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
      strncpy(port->mmhs->bid, tmp->scr, ln_bid);
      hasbid = true;
   }
#endif
    cremsg();
    first = false;
  }
  fclose(fl);
}

/*
 *  M command, make a message from a file.
 */

makmsg()
{
#ifdef MCH_AMIGA
   char *a,*b;
#endif
  if ((port->fl = fopen(port->fld[2], "r")) is NULL)
    { nofile(port->fld[2]); return; }
  fclose(port->fl);
#ifndef MCH_AMIGA
  pfld();
#else
/* If there's an error in the command then return */
   if(pfld() == 0)return;
#endif
  if (port->mode & gone) return;
#ifdef MCH_AMIGA
/* Put a BID or MID on this file if needed */
   if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
      unbl(port->line, cport->user->call, ln_call);

      /* Default the BID as coming from this BBS with our msg number. */

      sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
      strncpy(port->mmhs->bid, tmp->scr, ln_bid);
      hasbid = true;
   }
#endif
  msgfile(port->line, mfhs->next_msg);
  copy(port->fld[2], port->line, true);
  cremsg();
}

/*
 *  MM command, make multiple messages from a file.
 */

makmlt()
{
  register FILE *dfl;
  char tnm[80];

  holdit = false;
  fill(port->mmhs->bid, ' ', ln_bid);

  if ((port->fl = fopen(port->fld[2], "r")) is NULL)
    { nofile(port->fld[2]); return; }
  fclose(port->fl);

  if ((dfl = fopen(port->fld[1], "r")) is NULL)
    { nofile(port->fld[1]); return; }

  strcpy(tnm, port->fld[2]);
 
  if (port->flds is 4) if (*port->fld[port->flds-1] is '$')
  {
/* MCH_AMIGA */
    if (*(port->fld[port->flds - 1] + 1)/* isnt NULL*/)
    {
      strncpy(port->mmhs->bid, port->fld[port->flds-1] + 1, ln_bid);
      hasbid = true;
    }
  }
 
  prtx(mm[0]);
  get_title();
  if (port->mode & gone) { fclose(dfl); return; }

  while (fgets(port->line, linelen, dfl) isnt NULL)
  {
    parse();
    port->mmhs->type = port->opt2;
    pcall(port->mmhs->to, port->fld[1]);
    strncpy(port->mmhs->from, port->user->call, ln_call);
    fill(port->mmhs->bbs, ' ', ln_call);
    port->mmhs->ext = 0;

    if (port->flds > 3) atfrom(2);
    if (port->flds > 5) atfrom(4);
#ifdef MCH_AMIGA
/* Put a BID or MID on this file if needed */
   if( (port->mmhs->type is 'B') || (port->mmhs->type == 'P'))  {
      unbl(port->line, cport->user->call, ln_call);

      /* Default the BID as to coming from this BBS with our msg number. */

      sprintf(tmp->scr, "%-u_%-s", mfhs->next_msg, port->line);
      strncpy(port->mmhs->bid, tmp->scr, ln_bid);
      hasbid = true;
   }
    replace_bbs();
#endif
    initmsg(false);
    msgfile(port->line, mfhs->next_msg);
    copy(tnm, port->line, true);
    cremsg();
  }
  fclose(dfl);
}

/*
 *  Mark stale messages.
 */

stale()
{
  register word i;
  register int ks;
  register short ts;

  for (i = mfhs->first; i and i <= mfhs->last; i++)
  {
    read_rec(mfl, i, (char *)port->mmhs);

    switch(port->mmhs->type)
    {
      case 'T': ts = tstalen; ks = (s_flag & s_nkill); break;
      case 'P': ts = tstaleu; ks = (s_flag & s_ukill); break;
      default :
      {
   ts = tstaleb; ks = (s_flag & s_bkill);          /* Max time period */
#ifdef MCH_AMIGA
   /* If this is a bulletin and the lifetime is less than the default
      then use the lifetime
   */
    if(port->mmhs->type is 'B') {
       if(port->mmhs->lifetime && (port->mmhs->lifetime < ts)) {
          ts = port->mmhs->lifetime;
       }
    }
#endif
   if (!(port->mmhs->stat & m_bull))
   {
     if (ddiff(port->mmhs->date, l_date, true) > tstale1)  /* 1st time period */
       if (port->mmhs->read < rstale1) ts = 0;
     if (ddiff(port->mmhs->date, l_date, true) > tstale2)  /* 2nd time period */
       if (port->mmhs->read < rstale2) ts = 0;
     if (ddiff(port->mmhs->date, l_date, true) > tstale3)  /* 3rd time period */
       if (port->mmhs->read < rstale3) ts = 0;
   }
      }
    }

    if (!(port->mmhs->stat & m_stale))
    if (ddiff(port->mmhs->date, l_date, true) > ts)
    {
      if (ks and !(port->mmhs->stat & m_hold)) port->mmhs->stat setbit m_kill;
      else port->mmhs->stat setbit m_stale;
      write_rec(mfl, i, (char *)port->mmhs);
    }
  }
}

/*
 *  DW command: make wp message from user file.
 */

dwuser()
{
  register int i;
  register short first = true;
  short doall;

  if (*wpcall is ' ') return;

  doall = port->flds is 2;
  port->opt1 = 'S';
  port->opt2 = 'P';
  filesize = 0;
#ifdef MCH_AMIGA
   check_user();
   unlock_user();
#endif

  for (i = 1; i <= ufhs->count; i++)
  {
    read_rec(ufl, i, (char *)tuser);
    if ((tuser->state & u_home) and (tuser->state & u_zip))
    if (doall or !(tuser->state & u_sent))
    {
      if (first)
      {
   first = false;
   port->mmhs->type = 'P';
   strncpy(port->mmhs->to, "WP    ", ln_call);
   strncpy(port->mmhs->from, cport->user->call, ln_call);
   strncpy(port->mmhs->bbs, wpcall, ln_call);
   strcpy(port->mmhs->title, "WP Update");
   fill(port->mmhs->bid, ' ', ln_bid);
   port->mmhs->ext = 0;
   initmsg(false);
   msgfile(port->line, mfhs->next_msg);
   port->fl = fopen(port->line, "w");
   fseek(port->fl, (long)RECSIZE, 0);
      }

      filesize += 72;
      fprintf(port->fl, "On %6.6s %6.6s @ %6.6s zip %6.6s %-12.12s %-20.20s\n",
      tuser->date, tuser->call, tuser->home_bbs, tuser->zip,
      tuser->handle, tuser->qth);

      tuser->state setbit u_sent;
      if (s_flag & s_dv) begin_lock();
      write_rec(ufl, i, (char *)tuser);
      if (s_flag & s_dv)end_lock();
      if (i is port->user->rn) port->user->state setbit u_sent;
    }
  }

  if (!first)
  {
    fclose(port->fl);
    chkhier();
    cremsg();
  }
}

/*
 *  E command, edit a message header.
 */

edmsg()
{
  FILE *out;
  char *a, *b;
#ifdef MCH_AMIGA
   short life;
#endif

  if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  while (*port->fld[0] isnt '\0')
  {
    prthdr(true, true);
#ifdef MCH_AMIGA
    if(port->mmhs->type == 'B')
  outstr("t(Y)pe, (S)tatus, (T)o, (F)rom, (B)bs, t(I)tle, bi(D), (L)ifetime\n");
   else
#endif
    outstr("t(Y)pe, (S)tatus, (T)o, (F)rom, (B)bs, t(I)tle, bi(D)\n");
    getcmd();
    if (port->mode & gone) return;
    switch (*port->fld[0])
    {
#ifdef MCH_AMIGA
      case 'L' :
         if(port->mmhs->type == 'B') {
            life = atoi(port->fld[1]);
            if((life >= 0) && (life < 256))port->mmhs->lifetime = life;
         }
         /* This 'L' command confuses prthdr(). So unconfuse it */
         port->opt1 = ' ';
         break;
#endif
      case 'T' : pcall(port->mmhs->to, port->fld[1]); break;
      case 'F' : pcall(port->mmhs->from, port->fld[1]); break;
      case 'B' : edbbs(1); break;
      case 'I' : if (*port->fld[1])
       {
         remnl(port->line);
         strncpy(port->mmhs->title, port->line+2, mhtitl);
       }
       else *port->mmhs->title = '\0';
       break;
      case 'S' : switch(*port->fld[1])
       {
         case 'F' : port->mmhs->stat = m_fwd;   break;
         case 'H' : port->mmhs->stat = m_hold;  break;
         case 'N' : port->mmhs->stat = 0;       break;
         case 'O' : port->mmhs->stat = m_stale; break;
         case 'Y' : port->mmhs->stat = m_read;  break;
         case '$' : port->mmhs->stat setbit m_bull; break;
       }
       break;
      case 'Y' : if(*port->fld[1]) port->mmhs->type = *port->fld[1];
       else port->mmhs->type = ' '; break;

      case 'D' : if(*port->fld[1]) strncpy(port->mmhs->bid, port->fld[1], ln_bid);
       else fill(port->mmhs->bid, ' ', ln_bid);
       break;
    }
  }
  wt_mmhs();
  makehdr2();
  if (*port->mmhs->bid isnt ' ')
  {
    checkbid();
    if  (needbid)
    {
#ifdef MCH_AMIGA
      lock_bid();
#endif
      if ((out = fopen(bidfile,"a")) is NULL)
      {
#ifdef MCH_AMIGA
   unlock_bid();
#endif
   port->msg = mcant; return; 
      }

      a = port->cmd;
      b = port->mmhs->bid;
      unbl(a, b, ln_bid);      

      sprintf(port->line, "%4.4s%s\n", port->mmhs->date + 2, port->cmd);
      if (s_flag & s_dv) begin_lock();
      fputs(port->line, out);
      if (s_flag & s_dv) end_lock();
      fclose(out);
#ifdef MCH_AMIGA
   unlock_bid();
#endif
    }
  }
}

/*
 *  ET command, edit an NTS traffic message header.
 */

edtfc()
{
  register short ok;

  if (!findmsg(atoi(port->fld[1]))) { port->msg = mnmsg; return; }
  prthdr(true, true);

  ok = (port->mmhs->type is 'T');
  if (!ok) ok = ((port->mmhs->type is ' ') and matchn(port->mmhs->to, "NTS", 3));
  if (!ok) { port->msg = mm[12]; return; }

  prtx(mm[8]);
  getcmd();
  if (port->mode & gone) return;
  if (port->flds) pcall(port->mmhs->to, port->fld[0]);

  prtx(mm[9]);
  getcmd();
  if (port->mode & gone) return;
  edbbs(0);

  prtx(mm[10]);
  getcmd();
  if (port->mode & gone) return;
  if (port->flds)
  {
    remnl(port->line);
    strncpy(port->mmhs->title, port->line, mhtitl);
  }
  else if (*port->line is ' ') *port->mmhs->title = '\0';

  prtx(mm[11]);
  getcmd();
  if (port->mode & gone) return;
  if (port->flds) port->mmhs->type = *port->fld[0];
  else if (*port->line is ' ') port->mmhs->type = ' ';

  port->mmhs->stat = 0;
  prthdr(true, true);
  wt_mmhs();
  makehdr2();
  sprintf(port->line, "%u %-.6s %s",
    port->mmhs->number, port->mmhs->to, port->mmhs->title);
  log('M', 'E', port->opt2, port->line);
}

edbbs(f)
int f;
{
  fill(port->mmhs->call, '\0', 92);
  port->mmhs->ext = 0;
  fill(port->mmhs->bbs, ' ', ln_call);
  if(*port->fld[f])
  {
    pcall(port->mmhs->bbs, port->fld[f]);
    if (strchr(port->fld[f], '.') is NULL) dodis();
    else
    {
      port->mmhs->ext = 2;
      strncpy(port->mmhs->call[0], port->fld[f], ln_hier);
    }
    if (port->mmhs->ext is 0) chkhier();
  }
}

/*
 *  Check to see if bbs has match in STATES.MB file and add state code
 *  to hierarchical call.
 */

chkhier()
{
  FILE *hier;
  char hiercall[ln_call], bbs[ln_call+1], phier[ln_hier];
  char *p;
#ifdef MCH_AMIGA
   register char *q;
#endif

  if (*port->mmhs->bbs is ' ') return;
  if(( hier = fopen( stfile, "r")) is NULL) return;
  while( fgets( tmp->scr, linelen, hier) isnt NULL)
  {
    pcall(hiercall, tmp->scr);
    if( wcm(hiercall, port->mmhs->bbs))
    {
#ifndef MCH_AMIGA
      remnl(tmp->scr);
#endif
      p = strchr(tmp->scr, '.');
      unbl(bbs, port->mmhs->bbs, ln_call);
      unbl(phier, p, ln_hier);
#ifdef MCH_AMIGA
/* If the hierarchical portion has .USA or .CAN on the end then add .NOAM */
      for(q=phier;*q;q++);
      p = q;
      while((q > phier) && (*q != '.'))q--;
      if(matchn(".USA",q,4) || matchn(".CAN",q,4)) {
         strcpy(p,continent);
      }
#endif
      port->mmhs->ext = 2;
      fill( port->mmhs->call[0], '\0', 92);
      sprintf( port->mmhs->call[0], "%s%s", bbs, phier);
      fclose(hier);
      return;
    }
   }
   fclose(hier);
   return;
 }

/*
 * Compress the bidfile by removing old bids 
 */

cprs_bid()
{
  FILE *bfl, *bbfl;
  int x, yy, zz;
  char biddate[7];

  unlink(bbidfile);
  rename(bidfile, bbidfile);
  unlink(bidfile);

  if ((bfl = fopen(bidfile, "a")) is NULL)
  {
#ifndef MCH_AMIGA
    printf("Error opening %s\n", bidfile);
#else
    sprintf(tmpstr,"Error opening %s\n", bidfile);
    ttputs(tmpstr);
#endif
    return;
  }
  if ((bbfl = fopen(bbidfile, "r")) is NULL)
  {
    nofile(bbidfile);
    return;
  }

  yy=0; zz=0;
#ifndef MCH_AMIGA
  printf("Compressing bid file.......\n");
#else
/* NOTE that this routine is called at the same time as a GM is done and
   there is already a lock on the whole system when this function executes
   so there's no need to lock the BID semaphore.
*/
  ttputs("Compressing bid file.......\n");
#endif
  while (fgets(port->line, linelen, bbfl) isnt NULL)
  {
    fill (biddate, ' ', 6);
    strncpy (biddate + 2, port->line, 4);
    yy++;
    if ((x = ddiff(biddate, l_date, false)) < 0)
      x += 365;
    if (x < bidnum)
      {
   fputs (port->line, bfl);
   zz++;
      }
  }
#ifndef MCH_AMIGA
  printf("There were %d records, now %d remain\n",yy,zz);
  printf("Compression completed\n");
#else
  sprintf(tmpstr,"There were %d records, now %d remain\n",yy,zz);
  ttputs(tmpstr);
  ttputs("Compression completed\n");
   /* Get the BID semaphore and set the new length of file */
#endif
  
  fclose (bfl);
  fclose (bbfl);
}

#ifdef MCH_AMIGA
check_mail()
{
   extern long get_mail();
   lock_mail();
   if(mfhs->count != get_mail()) {
      close(mfl);
      mfl = open(mbfile, O_RDWR | O_BINARY);
      read_rec(mfl, 0, (char *)mfhs);
      titles();
   }
}
#endif
