/*ProfiPacket - packet radio terminal program
  Copyright (C) 1999  Alexander Feigl

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Author:

  Alexander Feigl
  Burachstraße 51

  D-88250 Weingarten

  Mail : Alexander.Feigl@gmx.de
*/


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* to do :

   - hangup when double number created ???

   */


#ifndef DISABLE_BBS

#define MAIL_PRIVATE
#define MAIL_FLUSHTIME 4


#include "GUIProtos.h"
#include "global.h"
#include "QSO.h"
#include "Mail.h"
#include "Preferences.h"
#include "Util.h"


#ifdef AmigaOS

#include <exec/memory.h>

#include <utility/date.h>

#include <dos/exall.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>


#ifdef __GNUC__

extern void *DOSBase;
extern void *SysBase;
extern void *UtilityBase;

#include <inline/dos.h>
#include <inline/exec.h>
#include <inline/utility.h>
#undef RawDoFmt
#endif /* __GNUC__ */

#endif /* AmigaOS */

struct MailBBSTable
 {
  unsigned long ForwardBBS[512];
 };


struct MailCached
 {

  unsigned long InCache;                  /*Number of records in cache*/
  unsigned long FlushTime;                /*Number of seconds to flush*/
  unsigned long CachedType[32];           /*Type of cached record :
                                            0=Base 1=BBSTable 2=Mail*/
  unsigned long CachedRecord[32];         /*Number of cached record*/
 };

static struct MailBase     *MailBase;
static struct List         MailHandles;
static struct MailBBSTable *MailBBSTable;
static  struct Mail         *MailNode;
static  BPTR                MailIndexFile;
static struct MailCached   *MailCached;

static int MAIL_SuperMatch(const unsigned char *string,const unsigned char *pattern);


static void MAIL_ClearMail(struct Mail *mail);

static int MAIL_ResetMailbox(void);

static int MAIL_SaveRecord(void *record);

static int MAIL_SaveRecordFlush(void);

static int MAIL_SaveRecordAllMails(void);

static void MAIL_FreeBBSData(void);

static int MAIL_LoadBBSData(void);

static int MAIL_SaveBBSData(void);

static int MAIL_LoadBBSDataArg(unsigned char **xptr,unsigned char *buf,
         int blen);

static int MAIL_AddHierarchy(unsigned char *bbs,unsigned char *hroute);

static int MAIL_AddUser(unsigned char *call,unsigned char *name,
                        unsigned char *qth,unsigned char *plz,
                        unsigned char *homebbs);

static int MAIL_AddForward(unsigned char *target,unsigned char *at,
                           unsigned char *hroute,unsigned char *box);

static int MAIL_AddNoForward(unsigned char *target,unsigned char *at,
                           unsigned char *hroute,unsigned char *box);

static struct BBSObject *MAIL_GetUserEntry(unsigned char *call);

static struct BBSObject *MAIL_GetHRouteEntry(unsigned char *call);

static struct BBSObject *MAIL_GetForwardEntry(const unsigned char *target,
                        const unsigned char *at,const unsigned char *hroute,
                        const struct BBSObject *bbos);

static int MAIL_TestNoForwardEntry(const unsigned char *target,
                        const unsigned char *at,const unsigned char *hroute,
                        const unsigned char *box);

static void MAIL_KillIncompletes(void);

static unsigned long MAIL_GetMailCapacity(void);

static void MAIL_MakeSpaceMails(unsigned long nmailsgive);

static int MAIL_CopyCallUpper(unsigned char *xdptr,const unsigned char *xsptr,
                          unsigned long len,unsigned long mode);

static void MAIL_ComposeRoute(unsigned char *at,unsigned char *hroute,unsigned char *route);


static void MAIL_InternalMoveMail(struct Mail *mail1,struct Mail *mail2);

static signed long MAIL_InternalKillMail(struct Mail *mail,unsigned long crashmode);

static void MAIL_MakeMailName(struct Mail *mail,unsigned char *fname);

static void MAIL_InternalGetDate(const struct Mail *mail,unsigned char *dest,
                                 unsigned long yearmode);

static struct Mail *MAIL_GetMailFromNumber(unsigned long number);

static void *MAIL_ParseForward(void *fstruct,void *xmail,unsigned char *rptr,
                        unsigned char *notforward);


int MAIL_Init(void)
{
 MailHandles.lh_Head=(void *) &MailHandles.lh_Tail;
 MailHandles.lh_Tail=NULL;
 MailHandles.lh_TailPred=(void *) &MailHandles;
 MailHandles.lh_Type=NT_UNKNOWN;


 {
  unsigned long i;
  for (i=0;i<9;++i) GlobalArraysP->mailmacroremember[i]=0;
 }
 if (Preferences.MaxMails==0) return(TRUE);  /*Disable BBS*/

 if (!MAIL_LoadBBSData())
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,504,16,NULL);
  }


 if ( (MailIndexFile=
       Open("data/bbs/bbs.idx",MODE_READWRITE))==NULL)
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,340,16,NULL);
   return(TRUE);
  }

 if ( (MailBBSTable=
       AllocVec(sizeof(struct MailBBSTable),MEMF_PUBLIC))==NULL)
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,343,16,NULL);
   return(TRUE);
  }

 if ( (MailBase=
       AllocVec(sizeof(struct MailBase),MEMF_PUBLIC))==NULL)
  {
   GUI_HandleRequest(0,343,16,NULL);
   MAIL_Cleanup();
   return(TRUE);
  }

 if ( (MailCached=
       AllocVec(sizeof(struct MailCached),MEMF_PUBLIC))==NULL)
  {
   GUI_HandleRequest(0,343,16,NULL);
   MAIL_Cleanup();
   return(TRUE);
  }

 MailCached->InCache=0;
 MailCached->FlushTime=0;

 if (Seek(MailIndexFile,0,OFFSET_BEGINNING)==-1)
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,340,16,NULL);
   return(TRUE);
  }

 if (!LockRecord(MailIndexFile,0,sizeof(struct MailBase),REC_SHARED,0))
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,340,16,NULL);
   return(TRUE);
  }

 if (Read(MailIndexFile,MailBase,sizeof(struct MailBase))!=
     sizeof(struct MailBase))
  {
   UnLockRecord(MailIndexFile,0,sizeof(struct MailBase));
   if (MAIL_ResetMailbox())
    {
     return(TRUE);
    }
   MAIL_Cleanup();
   GUI_HandleRequest(0,340,16,NULL);
   return(TRUE);
  }
 UnLockRecord(MailIndexFile,0,sizeof(struct MailBase));

 if (!CompareString("BBSINDEX",MailBase->IDString))
  {
   MAIL_Cleanup();
   GUI_HandleRequest(0,340,16,NULL);
   return(TRUE);
  }


 if ( (MailBase->SizeofMail!=sizeof(struct Mail)) ||
      (MailBase->IndexVersion!=1) ||
      (MailBase->NumberMails==0 ) ||
      ( (MailBase->BoxIdent[0]!='\0') && (!CompareString(Preferences.BoxIdent,MailBase->BoxIdent)) )
    )
  {
   if (GUI_HandleRequest(0,341,346,NULL))
    {
     return (MAIL_ResetMailbox());
    }
   return(TRUE);
  }


 if (!LockRecord(MailIndexFile,sizeof(struct MailBase),sizeof(struct MailBBSTable),REC_SHARED,0))
  {
   MAIL_Cleanup();
   return(TRUE);
  }

 if ( Read(MailIndexFile,MailBBSTable,sizeof(struct MailBBSTable))!=
      sizeof(struct MailBBSTable))
  {
   UnLockRecord(MailIndexFile,sizeof(struct MailBase),sizeof(struct MailBBSTable));
   GUI_HandleRequest(0,344,16,NULL);
   if (!MAIL_ResetMailbox())
    {
     MAIL_Cleanup();
     return(TRUE);
    }
   return(TRUE);
  }
 UnLockRecord(MailIndexFile,sizeof(struct MailBase),sizeof(struct MailBBSTable));

  {
   unsigned long nmails;
   nmails=MailBase->NumberMails;
   if (Preferences.MaxMails>nmails) nmails=Preferences.MaxMails;
   if ((MailNode=
        AllocVec(sizeof(struct Mail)*nmails,MEMF_PUBLIC))
       ==NULL)
    {
     MAIL_Cleanup();
     GUI_HandleRequest(0,340,16,NULL);
     return(TRUE);
    }
  }
  {
   unsigned long xoffset;
   unsigned long xlen;
   xoffset=sizeof(struct MailBase)+sizeof(struct MailBBSTable);
   xlen=sizeof(struct Mail)*MailBase->NumberMails;
   if (!LockRecord(MailIndexFile,xoffset,xlen,REC_SHARED,0))
    {
     MAIL_Cleanup();
     return(TRUE);
    }
   if (Read(MailIndexFile,MailNode,xlen)!=xlen)
    {
     UnLockRecord(MailIndexFile,xoffset,xlen);
     FreeVec(MailNode);
     MailNode=NULL;
     GUI_HandleRequest(0,344,16,NULL);
     if (!MAIL_ResetMailbox())
      {
       MAIL_Cleanup();
       return(TRUE);
      }
     return(TRUE);
    }
   UnLockRecord(MailIndexFile,xoffset,xlen);
  }


 if (MailBase->BoxIdent[0]=='\0')
  {
   CopyString(MailBase->BoxIdent,Preferences.BoxIdent);
   MAIL_SaveRecord(MailBase);
  }

 MAIL_KillIncompletes();
 MAIL_DailyHousekeeping();


 if (MailBase->NumberMails!=Preferences.MaxMails)
  {
   unsigned long oldsize;
   unsigned long newsize;

   oldsize=MailBase->NumberMails;
   newsize=Preferences.MaxMails;
   if (newsize<oldsize)
    {  /* cut mailbox database*/
     struct Mail *optr;
     struct Mail *nptr;
     unsigned long i;
     if (MAIL_GetMailCapacity()<(oldsize-newsize))
      {
       if (!GUI_HandleRequest(0,342,346,NULL))
        {
         MAIL_Cleanup();
         return (TRUE);
        }
       MAIL_MakeSpaceMails(oldsize-newsize);
       if (MAIL_GetMailCapacity()<(oldsize-newsize))
        {
         MAIL_Cleanup();
         return (FALSE); /* cannot flush enough mails */
        }
      }
     optr=MailNode+(oldsize-newsize);
     nptr=MailNode;
     for (i=0;i<newsize;++i,++optr,++nptr)
      {
       *nptr=*optr;
      }
     MailBase->NumberMails=newsize;
     SetFileSize(MailIndexFile,0,OFFSET_BEGINNING);
     MAIL_SaveRecord(MailBase);
     MAIL_SaveRecord(MailBBSTable);
     MAIL_SaveRecordAllMails();
    }

   if (newsize>oldsize)
    {  /* expand mailbox database */
     struct Mail *optr;
     struct Mail *nptr;
     unsigned long i;

     nptr=MailNode+newsize-1;
     optr=MailNode+oldsize-1;
     for (i=0;i<oldsize;++i,--optr,--nptr)
      {
       *nptr=*optr;
      }
     for (i=0;i<(newsize-oldsize);++i,--nptr)
      {
       MAIL_ClearMail(nptr);
      }
     MailBase->NumberMails=newsize;
     MAIL_SaveRecord(MailBase);
     MAIL_SaveRecordAllMails();
    }
   MAIL_Cleanup();
   return(MAIL_Init());

  }
 return(TRUE);
}



static void MAIL_ClearMail(struct Mail *mail)
 {
  unsigned char *mptr;
  unsigned long i;
  mptr=(unsigned char * ) mail;
  for (i=0;i<sizeof(struct Mail);++i) *(mptr++)='\0';
 }

static int MAIL_ResetMailbox(void)
{
 unsigned long i;
 struct Mail *cmail;

 if (MailNode!=NULL) return(FALSE);

 CopyString(MailBase->IDString,"BBSINDEX");
 MailBase->SizeofMail=sizeof(struct Mail);
 MailBase->NumberMails=Preferences.MaxMails;
 MailBase->LastBID=0;
 MailBase->IndexVersion=1;
 CopyString(MailBase->BoxIdent,Preferences.BoxIdent);
 MailBase->HousekeepDay=0;
 for (i=0;i<8;++i) MailBase->Padding[i]=0;
 for (i=0;i<512;++i) MailBBSTable->ForwardBBS[i]=0;

 if ((MailNode=
      AllocVec(sizeof(struct Mail)*MailBase->NumberMails,MEMF_PUBLIC))
     ==NULL)
  {
   return(FALSE);
  }

 cmail=MailNode;
 for (i=0;i<MailBase->NumberMails;++i,++cmail)
  {
   MAIL_ClearMail(cmail);
  }
 SetFileSize(MailIndexFile,0,OFFSET_BEGINNING);

 if (!MAIL_SaveRecord(MailBase)) return(FALSE);
 if (!MAIL_SaveRecord(MailBBSTable)) return(FALSE);

 cmail=MailNode;
 for (i=0;i<MailBase->NumberMails;++i,++cmail)
  {
   if (!MAIL_SaveRecord(cmail)) return(FALSE);
  }
 if (!MAIL_SaveRecordFlush()) return(FALSE);
 return(TRUE);
}


static int MAIL_SaveRecordAllMails(void)

 {
  unsigned long i,j,inc;
  if (MailCached==NULL) return(FALSE);
  inc=MailCached->InCache;
  for (i=0,j=0;i<inc;++i)
   {
    if (MailCached->CachedType[i]==2)
     {
      MailCached->InCache--;
     }
     else
     {
      ++j;
     }
   }


  for (i=0;i<MailCached->InCache;++i)
   {
    if ( (MailCached->CachedType[i]==3) )
     {
      MailCached->FlushTime=MAIL_FLUSHTIME;
      return(TRUE);
     }
   }

  if (MailCached->InCache==32) MAIL_SaveRecordFlush();

  if (MailCached->InCache==32) return(FALSE);

  MailCached->CachedType[MailCached->InCache]=3;
  MailCached->CachedRecord[MailCached->InCache]=0;
  MailCached->InCache++;
  MailCached->FlushTime=MAIL_FLUSHTIME;
  return(TRUE);
 }

static int MAIL_SaveRecordFlush(void)
{
 unsigned long i,j,inc;

 if (MailCached==NULL) return(0);
 inc=MailCached->InCache;
 for (i=0,j=0;i<inc;++i)
  {
   unsigned long offset,len;
   void *ptr;

   switch (MailCached->CachedType[i])
    {
     case 0:
       offset=0;
       len=sizeof(struct MailBase);
       ptr=MailBase;
       break;
     case 1:
       offset=sizeof(struct MailBase);
       len=sizeof(struct MailBBSTable);
       ptr=MailBBSTable;
       break;
     case 2:
       offset=sizeof(struct MailBase)+sizeof(struct MailBBSTable)+
        (sizeof(struct Mail)*MailCached->CachedRecord[i] );
       len=sizeof(struct Mail);
       ptr=MailNode+MailCached->CachedRecord[i];
       break;
     case 3:
       offset=sizeof(struct MailBase)+sizeof(struct MailBBSTable);
       len=sizeof(struct Mail)*MailBase->NumberMails;
       ptr=MailNode;
       break;
     default:
       offset=0;
       len=0;
       ptr=NULL;
    }

   if (ptr==NULL) continue;

   MailCached->CachedType[j]=MailCached->CachedType[i];
   MailCached->CachedRecord[j]=MailCached->CachedRecord[i];

   if (Seek(MailIndexFile,offset,OFFSET_BEGINNING)==-1)
    {
     ++j;
     continue;
    }


   if (!LockRecord(MailIndexFile,offset,len,REC_SHARED,0))
    {
     ++j;
     continue;
    }

   if (Write(MailIndexFile,ptr,len)!=len)
    {
     UnLockRecord(MailIndexFile,offset,len);
     ++j;
     continue;
    }

   UnLockRecord(MailIndexFile,offset,len);
   MailCached->InCache--;
  }

 return (MailCached->InCache==0);
}

static int MAIL_SaveRecord(void *record)
 {
  unsigned long recordtype;
  unsigned long recordnum;
  unsigned long i;

  recordtype=9999;
  recordnum=0;

  if (record==NULL) return(TRUE);
  if (record==MailBase)
   {
    recordtype=0;               /* bbs index*/
    recordnum=0;
   }
  if ( (MailBBSTable!=NULL) && (((struct MailBBSTable *) record)>=MailBBSTable) &&
       (((struct MailBBSTable *) record)<(MailBBSTable+1)) )
   {
    recordtype=1;               /* bbs bbs index*/
    recordnum=0;
   }
  if ( (MailNode!=NULL) && (((struct Mail * )record)>=MailNode) &&
       (((struct Mail *)record)<(MailNode+(MailBase->NumberMails))) )
   {
    struct Mail *trec;
    recordtype=2;
    trec=record;
    recordnum=trec-MailNode;
   }


  if (recordtype==9999) return(FALSE);

  if (MailCached==NULL) return(FALSE);

  for (i=0;i<MailCached->InCache;++i)
   {
    if ( (MailCached->CachedType[i]==recordtype) &&
         (MailCached->CachedRecord [i]==recordnum) )
     {
      MailCached->FlushTime=MAIL_FLUSHTIME;
      return(TRUE);
     }
   }

  if (MailCached->InCache==32) MAIL_SaveRecordFlush();

  if (MailCached->InCache==32) return(FALSE);

  MailCached->CachedType[MailCached->InCache]=recordtype;
  MailCached->CachedRecord[MailCached->InCache]=recordnum;
  MailCached->InCache++;
  MailCached->FlushTime=MAIL_FLUSHTIME;
  return(TRUE);

 }


void MAIL_Cleanup(void)
{

 if (MailNode!=NULL)  /* is a valid BBS */
  {
   while (!IsListEmpty(&MailHandles))
    {
     struct MailHandle *mh;
     struct Mail *mn;

     mn=NULL;
     mh=(struct MailHandle *) MailHandles.lh_Head;
     if (mh->FileHandle!=NULL)
      {
       Close(mh->FileHandle);
       mh->FileHandle=NULL;
      }
     if (mh->MailMode!=0)
      {
       mn=mh->MailNode;
      }
     Remove((void *) mh);
     FreeVec((void *) mh);
     if (mn!=NULL)
      {
       MAIL_InternalKillMail(mn,TRUE);
      }
    }


   if (MailCached!=NULL)
    {
     MAIL_SaveRecordFlush();
    }

  }

 if (MailIndexFile!=NULL)
  {
   Close(MailIndexFile);
   MailIndexFile=NULL;
  }

 if (MailCached!=NULL)
  {
   FreeVec(MailCached);
   MailCached=NULL;
  }

 if (MailBase!=NULL)
  {
   FreeVec(MailBase);
   MailBase=NULL;
  }
 if (MailBBSTable!=NULL)
  {
   FreeVec(MailBBSTable);
   MailBBSTable=NULL;
  }
 if (MailNode!=NULL)
  {
   FreeVec(MailNode);
   MailNode=NULL;
  }
 MAIL_FreeBBSData();
}


void MAIL_DoPoll(void)
 {
  if (MailCached!=NULL)
   {
    if ( (MailCached->InCache!=0) && (MailCached->FlushTime!=0))
     {
      MailCached->FlushTime--;
      if (MailCached->FlushTime==0)
       {
        MAIL_SaveRecordFlush();
        if (MailCached->InCache!=0)
         {
          MailCached->FlushTime=3600;
         }
       }

     }
   }

 }

static unsigned long MAIL_EncodeCall(const unsigned char *call)
 {
  unsigned long callcode;
  unsigned long callshift;
  unsigned long callnum;
  unsigned long calldigit;

  const unsigned char *cptr;

  callcode=0;
  callshift=1;
  callnum=0;
  cptr=call;
  while (1)

   {
    if (*cptr=='\0') return (callcode);
    if (*cptr=='-') return (callcode);
    callnum++;
    if (callnum>6) return(0);
    calldigit=100;
    if ( (*cptr>='A') && (*cptr<='Z') ) calldigit=*cptr-'A'+1;
    if ( (*cptr>='a') && (*cptr<='z') ) calldigit=*cptr-'a'+1;
    if ( (*cptr>='0') && (*cptr<='9') ) calldigit=*cptr-'0'+27;
    if (calldigit>=37) return(0);
    callcode+=calldigit*callshift;
    ++cptr;
    callshift*=37;
   }

 }

static void MAIL_DecodeCall(unsigned char *call,unsigned long callcode)
 {
  unsigned char *cptr;
  unsigned long callshift;
  unsigned long callnum;
  unsigned long calldigit;

  callshift=1;
  callnum=0;
  cptr=call;
  while (1)
   {
    callnum++;
    if (callnum>6)
     {
      *(cptr++)='\0';
      return;
     }

    calldigit= (callcode/callshift)%37;

    if (calldigit==0)
     {
      *(cptr++)='\0';
      return;
     }
    if ((calldigit>=0) && (calldigit<27)) *(cptr++)='A'+calldigit-1;
    if ((calldigit>=27)) *(cptr++)='0'+calldigit-27;
    callshift*=37;
   }
 }

static signed long MAIL_GetFBoxNumber(const unsigned char *call)
 {
  unsigned long callcode;
  unsigned long i;
  callcode=MAIL_EncodeCall(call);
  if (callcode==0) return(-1);
  if (MailBBSTable==NULL) return(-1);

  for (i=0;i<512;++i)
   {
    if (MailBBSTable->ForwardBBS[i]==callcode) return(i);
   }
  return(-1);
 }

static int MAIL_AddBoxCall(const unsigned char *call)
 {
  unsigned long callcode;
  unsigned long i;
  callcode=MAIL_EncodeCall(call);
  if (callcode==0) return(FALSE);
  if (MailBBSTable==NULL) return(FALSE);
  for (i=0;i<512;++i)
   {
    if (MailBBSTable->ForwardBBS[i]==callcode) return(TRUE);
   }
  for (i=0;i<512;++i)
   {
    if (MailBBSTable->ForwardBBS[i]==0)
     {
      MailBBSTable->ForwardBBS[i]=callcode;
      MAIL_SaveRecord(MailBBSTable);
      return(TRUE);
     }
   }
  return(FALSE);
 }

static int MAIL_SaveBBSData(void)
{
 BPTR bbsfile;
 unsigned char xline[384];
 unsigned char *xarray[16];
 struct BBSObject *bbo;

 if ((bbsfile=Open("data/bbs/database.bbs",MODE_NEWFILE))==NULL)
  {
   return(FALSE);
  }

 if (FPuts(bbsfile,"#Mailbox database - generated file")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }


 if (FPuts(bbsfile,"\n\n#Forward crons\n#B box path start stop inter bulletin\n\n")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }

 /* Output Forward crons */

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   unsigned char start[6];
   unsigned char stop[6];
   unsigned char inter[6];
   unsigned char personly[2];

   if (bbo->objecttype!=BBSObject_ForwardCron)
    {
     bbo=bbo->next;
     continue;
    }
   start[0]=0x30+bbo->BBSUnion.ForwardCron.StartHour/10;
   start[1]=0x30+bbo->BBSUnion.ForwardCron.StartHour%10;
   start[2]=0x30+bbo->BBSUnion.ForwardCron.StartMinute/10;
   start[3]=0x30+bbo->BBSUnion.ForwardCron.StartMinute%10;
   start[4]=0;
   stop[0]=0x30+bbo->BBSUnion.ForwardCron.StopHour/10;
   stop[1]=0x30+bbo->BBSUnion.ForwardCron.StopHour%10;
   stop[2]=0x30+bbo->BBSUnion.ForwardCron.StopMinute/10;
   stop[3]=0x30+bbo->BBSUnion.ForwardCron.StopMinute%10;
   stop[4]=0;

   inter[0]=0x30+(bbo->BBSUnion.ForwardCron.Interval/1000)%10;
   inter[1]=0x30+(bbo->BBSUnion.ForwardCron.Interval/100)%10;
   inter[2]=0x30+(bbo->BBSUnion.ForwardCron.Interval/10)%10;
   inter[3]=0x30+bbo->BBSUnion.ForwardCron.Interval%10;
   inter[4]=0;

   switch (bbo->BBSUnion.ForwardCron.PrivOnly)
    {
     case 1:
       personly[0]='N';
       break;
     case 2:
       personly[0]='R';
       break;
     case 3:
       personly[0]='D';
       break;
     default:
       personly[0]='Y';
    }
   personly[1]=0;

   xarray[0]=bbo->BBSUnion.ForwardCron.ForwardBox;
   xarray[1]=bbo->BBSUnion.ForwardCron.ForwardPath;
   xarray[2]=start;
   xarray[3]=stop;
   xarray[4]=(unsigned char *) bbo->BBSUnion.ForwardCron.Interval;
   xarray[5]=personly;
   RawDoFmt("B \"%s\" \"%s\" \"%s\" \"%s\" \"%04ld\" \"%s\"\n",
            xarray,PutRawDoFmt,xline);
   if (FPuts(bbsfile,xline)!=0)
    {
     Close(bbsfile);
     return(FALSE);
    }
   bbo=bbo->next;

  }

 if (FPuts(bbsfile,"\n\n#Forward routes\n#F target at hroute bbs\n\n")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }

 /* Output Forward entries */

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   if (bbo->objecttype!=BBSObject_ForwardEntry)
    {
     bbo=bbo->next;
     continue;
    }
   xarray[0]=bbo->BBSUnion.ForwardEntry.Target;
   xarray[1]=bbo->BBSUnion.ForwardEntry.AtDesignator;
   xarray[2]=bbo->BBSUnion.ForwardEntry.Hierarchy;
   xarray[3]=bbo->BBSUnion.ForwardEntry.ForwardBox;

   RawDoFmt("F \"%s\" \"%s\" \"%s\" \"%s\"\n",xarray,PutRawDoFmt,xline);
   if (FPuts(bbsfile,xline)!=0)
    {
     Close(bbsfile);
     return(FALSE);
    }
   bbo=bbo->next;
  }

 if (FPuts(bbsfile,"\n\n#No forward filter\n#N target at hroute box\n\n")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }

 /* Output NoForward entries */

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   if (bbo->objecttype!=BBSObject_DontForward)
    {
     bbo=bbo->next;
     continue;
    }
   xarray[0]=bbo->BBSUnion.DontForward.Target;
   xarray[1]=bbo->BBSUnion.DontForward.AtDesignator;
   xarray[2]=bbo->BBSUnion.DontForward.Hierarchy;
   xarray[3]=bbo->BBSUnion.DontForward.ForwardBox;

   RawDoFmt("N \"%s\" \"%s\" \"%s\" \"%s\"\n",xarray,PutRawDoFmt,xline);
   if (FPuts(bbsfile,xline)!=0)
    {
     Close(bbsfile);
     return(FALSE);
    }
   bbo=bbo->next;
  }


 if (FPuts(bbsfile,"\n\n#Hierarchy routes\n#H bbs hroute\n\n")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }

 /* Output H-Routes */

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   if (bbo->objecttype!=BBSObject_HRoute)
    {
     bbo=bbo->next;
     continue;
    }
   xarray[0]=bbo->BBSUnion.HRoute.BBS;
   xarray[1]=bbo->BBSUnion.HRoute.HRoute;
   RawDoFmt("H \"%s\" \"%s\"\n",xarray,PutRawDoFmt,xline);
   if (FPuts(bbsfile,xline)!=0)
    {
     Close(bbsfile);
     return(FALSE);
    }
   bbo=bbo->next;
  }


 if (FPuts(bbsfile,"\n\n#User entries\n#U call name qth plz homebbs\n\n")!=0)
  {
   Close(bbsfile);
   return(FALSE);
  }


 /* Output users */

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   if (bbo->objecttype!=BBSObject_User)
    {
     bbo=bbo->next;
     continue;
    }
   xarray[0]=bbo->BBSUnion.User.UserCall;
   xarray[1]=bbo->BBSUnion.User.Name;
   xarray[2]=bbo->BBSUnion.User.QTH;
   xarray[3]=bbo->BBSUnion.User.PLZ;
   xarray[4]=bbo->BBSUnion.User.HomeBBS;
   RawDoFmt("U \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \n",xarray,PutRawDoFmt,xline);
   if (FPuts(bbsfile,xline)!=0)
    {
     Close(bbsfile);
     return(FALSE);
    }
   bbo=bbo->next;
  }

 Close(bbsfile);
 return(TRUE);
}

static int MAIL_SuperMatch(const unsigned char *string,const unsigned char *pattern)
{
 const unsigned char *sptr,*pptr;

 if (*pattern=='!') return(!MAIL_SuperMatch(string,pattern+1));
 if ( (*pattern=='*') && (*(pattern+1)=='\0') ) return(TRUE);
 if (*pattern=='\0') return(FALSE);

 sptr=string;
 pptr=pattern;
 while (1)
  {
   if ( (*sptr=='\0') && (*pptr=='\0') ) return(TRUE);
   if ( (*pptr=='*') && (*(pptr+1)=='\0')) return (TRUE);

   if (*sptr=='\0') return(FALSE);
   if (*pptr=='\0') return(FALSE);
   switch (*pptr)
    {
     case '?':
      /* match all chars*/
      break;

     case '*':
      {
       while (1)
        {
         if (MAIL_SuperMatch(sptr,pptr+1)) return(TRUE);
         ++sptr;
         if (*sptr=='\0') return(FALSE);
        }
      }
      break;

     default:
      if ( *sptr!=*pptr) return(FALSE);
      break;
    }
   ++pptr;++sptr;
  }
}


static int MAIL_LoadBBSDataArg(unsigned char **xptr,unsigned char *buf,
         int blen)
{
 unsigned char *to;
 unsigned char *fm;
 int rlen;
 to=buf;
 rlen=blen;
 fm=*xptr;

 while (*fm==' ') ++fm;

 if (*fm!='\"') return(FALSE);
 ++fm;


 while (1)
  {
   if (rlen==0) return(FALSE);
   if (*fm=='\"') break;
   if (*fm=='\0') return(FALSE);
   *to++=*fm++;
   rlen--;
  }
 *to='\0';
 ++fm;
 *xptr=fm;
 return(TRUE);
}

static int MAIL_AddHierarchy(unsigned char *bbs,unsigned char *hroute)
{
 struct BBSObject *bbo;

 bbo=AllocVec(sizeof(*bbo),0);
 if (bbo==NULL) return(FALSE);
 bbo->next=BBSHook;
 bbo->objecttype=BBSObject_HRoute;
 CopyString(bbo->BBSUnion.HRoute.BBS,bbs);
 CopyString(bbo->BBSUnion.HRoute.HRoute,hroute);
 BBSHook=bbo;
 return(TRUE);
}

static int MAIL_AddUser(unsigned char *call,unsigned char *name,
                        unsigned char *qth,unsigned char *plz,
                        unsigned char *homebbs)
{
 struct BBSObject *bbo;
 bbo=AllocVec(sizeof(*bbo),0);
 if (bbo==NULL) return (FALSE);
 bbo->next=BBSHook;
 bbo->objecttype=BBSObject_User;
 CopyString(bbo->BBSUnion.User.UserCall,call);
 CopyString(bbo->BBSUnion.User.Name,name);
 CopyString(bbo->BBSUnion.User.QTH,qth);
 CopyString(bbo->BBSUnion.User.PLZ,plz);
 CopyString(bbo->BBSUnion.User.HomeBBS,homebbs);
 BBSHook=bbo;
 return(TRUE);
}

static int MAIL_AddForward(unsigned char *target,unsigned char *at,
                           unsigned char *hroute,unsigned char *box)
{
 struct BBSObject *bbo;
 bbo=AllocVec(sizeof(*bbo),0);
 if (bbo==NULL) return (FALSE);
 bbo->next=BBSHook;
 bbo->objecttype=BBSObject_ForwardEntry;
 CopyString(bbo->BBSUnion.ForwardEntry.Target,target);
 CopyString(bbo->BBSUnion.ForwardEntry.AtDesignator,at);
 CopyString(bbo->BBSUnion.ForwardEntry.Hierarchy,hroute);
 CopyString(bbo->BBSUnion.ForwardEntry.ForwardBox,box);
 BBSHook=bbo;
 return(TRUE);
}

static int MAIL_AddNoForward(unsigned char *target,unsigned char *at,
                           unsigned char *hroute,unsigned char *box)
{
 struct BBSObject *bbo;
 bbo=AllocVec(sizeof(*bbo),0);
 if (bbo==NULL) return (FALSE);
 bbo->next=BBSHook;
 bbo->objecttype=BBSObject_DontForward;
 CopyString(bbo->BBSUnion.DontForward.Target,target);
 CopyString(bbo->BBSUnion.DontForward.AtDesignator,at);
 CopyString(bbo->BBSUnion.DontForward.Hierarchy,hroute);
 CopyString(bbo->BBSUnion.DontForward.ForwardBox,box);
 BBSHook=bbo;
 return(TRUE);
}

static int MAIL_AddForwardCron(const unsigned char *box,
                               const unsigned char *path,
                               int starth,int startm,int stoph,int stopm,
                               int interval,int privonly,int tnc,int port)
 {
  struct BBSObject *bbo;
  bbo=AllocVec(sizeof(*bbo),0);
  if (bbo==NULL) return (FALSE);
  bbo->next=BBSHook;
  bbo->objecttype=BBSObject_ForwardCron;
  CopyString(bbo->BBSUnion.ForwardCron.ForwardBox,box);
  CopyString(bbo->BBSUnion.ForwardCron.ForwardPath,path);
  bbo->BBSUnion.ForwardCron.StartHour=starth;
  bbo->BBSUnion.ForwardCron.StartMinute=startm;
  bbo->BBSUnion.ForwardCron.StopHour=stoph;
  bbo->BBSUnion.ForwardCron.StopMinute=stopm;
  bbo->BBSUnion.ForwardCron.Interval=interval;
  bbo->BBSUnion.ForwardCron.PrivOnly=privonly;
  bbo->BBSUnion.ForwardCron.TNC=tnc;
  bbo->BBSUnion.ForwardCron.Port=port;
  BBSHook=bbo;
  return(TRUE);

 }


static int MAIL_ParseTime(const unsigned char *timestr,int *hour,int *min)
 {
  int i,h,m;

  for (i=0;i<3;++i)
   {
    if (timestr[i]>'9') return(0);
    if (timestr[i]<'0') return(0);
   }
  h= (timestr[0]&0xf)*10+(timestr[1]&0xf);
  m= (timestr[2]&0xf)*10+(timestr[3]&0xf);
  if (hour!=NULL)
   {
    if (m>59) return(0);
    if (h>23) return(0);
    *min=m;
    *hour=h;
    return(1);
   }
  if (m>59) return(0);
  *min=h*60+m;
  return(1);
 }

static int MAIL_LoadBBSData(void)
{
 BPTR bbsfile;
 unsigned char xline[384];
 unsigned char *xlptr;

 if ((bbsfile=Open("data/bbs/database.bbs",MODE_OLDFILE))==NULL)
  {
   return(TRUE);
  }


 while ( FGets(bbsfile,xline,380)!=NULL)
  {

   /* Strip CR*/
   xlptr=xline;
   while (*(xlptr++)!='\0');
   xlptr--;
   xlptr--;
   if (*xlptr=='\n') *(xlptr)='\0';

   /* Check for comment*/
   if ( *xline=='\0') continue;
   if ( *xline==';') continue;
   if ( *xline=='#') continue;

   if ( *(xline+1)!=' ')
    {
     Close(bbsfile);
     return(FALSE);
    }


   xlptr=xline+1;
   switch (*xline)
    {
     case 'H':    /* HRoute entry */
      {
       unsigned char BBS[16];
       unsigned char HRoute[64];
       if (!MAIL_LoadBBSDataArg(&xlptr,BBS,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,HRoute,64))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_AddHierarchy(BBS,HRoute))
        {
         Close(bbsfile);
         return(FALSE);
        }

       break;
      }
     case 'U':    /* User entry */
      {
       unsigned char UserCall[16];
       unsigned char Name[32];
       unsigned char QTH[32];
       unsigned char PLZ[16];
       unsigned char HomeBBS[16];
       if (!MAIL_LoadBBSDataArg(&xlptr,UserCall,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,Name,32))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,QTH,32))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,PLZ,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,HomeBBS,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_AddUser(UserCall,Name,QTH,PLZ,HomeBBS))
        {
         Close(bbsfile);
         return(FALSE);
        }
       break;
      }
     case 'F':    /* forward entry */
      {
       unsigned char Target[16];
       unsigned char AtDesignator[16];
       unsigned char Hierarchy[64];
       unsigned char ForwardBox[16];
       if (!MAIL_LoadBBSDataArg(&xlptr,Target,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,AtDesignator,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,Hierarchy,64))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,ForwardBox,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_AddForward(Target,AtDesignator,Hierarchy,ForwardBox))
        {
         Close(bbsfile);
         return(FALSE);
        }
       break;
      }
     case 'N':    /* No forward entry*/
      {
       unsigned char Target[16];
       unsigned char AtDesignator[16];
       unsigned char Hierarchy[64];
       unsigned char ForwardBox[16];

       if (!MAIL_LoadBBSDataArg(&xlptr,Target,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,AtDesignator,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,Hierarchy,64))
        {
         Close(bbsfile);
         return(FALSE);
        }

       if (!MAIL_LoadBBSDataArg(&xlptr,ForwardBox,16))
        {
         CopyString(ForwardBox,"*");
        }

       if (!MAIL_AddNoForward(Target,AtDesignator,Hierarchy,ForwardBox))
        {
         Close(bbsfile);
         return(FALSE);
        }
       break;



      }
     case 'B':
      {
       /* forward cron entry */

       unsigned char box[16];
       unsigned char path[64];
       int starth,startm,stoph,stopm,interval,privonly;
       unsigned char tempo[6];

       if (!MAIL_LoadBBSDataArg(&xlptr,box,16))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,path,64))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if ( (!MAIL_LoadBBSDataArg(&xlptr,tempo,5) ||
            (!MAIL_ParseTime(tempo,&starth,&startm))))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if ( (!MAIL_LoadBBSDataArg(&xlptr,tempo,5) ||
            (!MAIL_ParseTime(tempo,&stoph,&stopm))))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if ( (!MAIL_LoadBBSDataArg(&xlptr,tempo,5) ||
            (!MAIL_ParseTime(tempo,NULL,&interval))))
        {
         Close(bbsfile);
         return(FALSE);
        }
       if (!MAIL_LoadBBSDataArg(&xlptr,tempo,2))
        {
         Close(bbsfile);
         return(FALSE);
        }
       switch (tempo[0])
        {
         case 'Y':
           privonly=0;
           break;
         case 'N':
           privonly=1;
           break;
         case 'R':
           privonly=2;
           break;
         case 'D':
           privonly=3;
           break;
         default:
           Close(bbsfile);
           return(FALSE);
        }
       if (!MAIL_AddForwardCron(box,path,starth,startm,stoph,stopm,interval,privonly,0,0))
        {
         Close(bbsfile);
         return(FALSE);
        }

      }
    }
  }
 Close(bbsfile);

 return(TRUE);
}



static void MAIL_FreeBBSData(void)
{
 struct BBSObject *bbo,*bbo2;

 bbo=BBSHook;
 BBSHook=NULL;
 while (bbo!=NULL)
  {
   bbo2=bbo;
   bbo=bbo->next;
   FreeVec(bbo2);
  }
}


static struct BBSObject *MAIL_GetUserEntry(unsigned char *call)
{
 struct BBSObject *bbo,*bbo2;

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   unsigned char *sp,*dp;

   bbo2=bbo;
   bbo=bbo->next;
   if (bbo2->objecttype!=BBSObject_User) continue;
   sp=call;
   dp=bbo2->BBSUnion.User.UserCall;
   while ( *(sp++)==*(dp++) )
    {
     if (*(sp-1)=='\0') return(bbo2);
    }
  }
 return(NULL);
}

unsigned char *MAIL_GetUserName(unsigned char *call)
{
 struct BBSObject *bbo;
 bbo=MAIL_GetUserEntry(call);
 if (bbo==NULL) return(NULL);
 return (bbo->BBSUnion.User.Name);
}

unsigned char *MAIL_GetUserQTH(unsigned char *call)
{
 struct BBSObject *bbo;
 bbo=MAIL_GetUserEntry(call);
 if (bbo==NULL) return(NULL);
 return (bbo->BBSUnion.User.QTH);
}

unsigned char *MAIL_GetUserZIP(unsigned char *call)
{
 struct BBSObject *bbo;
 bbo=MAIL_GetUserEntry(call);
 if (bbo==NULL) return(NULL);
 return (bbo->BBSUnion.User.PLZ);
}

unsigned char *MAIL_GetUserBBS(unsigned char *call)
{
 struct BBSObject *bbo;
 bbo=MAIL_GetUserEntry(call);
 if (bbo==NULL) return(NULL);
 return (bbo->BBSUnion.User.HomeBBS);
}



static struct BBSObject *MAIL_GetHRouteEntry(unsigned char *call)
{
 struct BBSObject *bbo,*bbo2;

 bbo=BBSHook;
 while (bbo!=NULL)
  {
   unsigned char *sp,*dp;

   bbo2=bbo;
   bbo=bbo->next;
   if (bbo2->objecttype!=BBSObject_HRoute) continue;
   sp=call;
   dp=bbo2->BBSUnion.HRoute.BBS;
   while ( *(sp++)==*(dp++) )
    {
     if (*(sp-1)=='\0') return(bbo2);
    }
  }
 return(NULL);
}

static struct BBSObject *MAIL_GetCronEntry(const unsigned char *call)
{
 struct BBSObject *bbo,*bbo2,*bbo3;;

 bbo3=NULL;
 bbo=BBSHook;
 while (bbo!=NULL)
  {
   const unsigned char *sp;
   unsigned char *dp;

   bbo2=bbo;
   bbo=bbo->next;
   if (bbo2->objecttype!=BBSObject_ForwardCron) continue;
   sp=call;
   dp=bbo2->BBSUnion.ForwardCron.ForwardBox;
   while ( *(sp++)==*(dp++) )
    {
     if (*(sp-1)=='\0')
      {
       bbo3=bbo2;
       if (!UTIL_TestTimeRange(
             bbo2->BBSUnion.ForwardCron.StartHour,
             bbo2->BBSUnion.ForwardCron.StartMinute,
             bbo2->BBSUnion.ForwardCron.StopHour,
             bbo2->BBSUnion.ForwardCron.StopMinute)) break;

       return(bbo2);
      }
    }
  }
 return(bbo3);
}


unsigned char *MAIL_GetHRoute(unsigned char *bbs)
{
 struct BBSObject *bbo;
 bbo=MAIL_GetHRouteEntry(bbs);
 if (bbo==NULL) return(NULL);
 return (bbo->BBSUnion.HRoute.HRoute);

}

static struct BBSObject *MAIL_GetForwardEntry(const unsigned char *target,
                        const unsigned char *at,const unsigned char *hroute,
                        const struct BBSObject *bbos)
{
 struct BBSObject *bbo;
 bbo=BBSHook;
 if (bbos!=NULL) bbo=bbos->next;
 while (bbo!=NULL)
  {
   if ( (bbo->objecttype==BBSObject_ForwardEntry) &&
        (MAIL_SuperMatch(target,bbo->BBSUnion.ForwardEntry.Target)) &&
        (MAIL_SuperMatch(at,bbo->BBSUnion.ForwardEntry.AtDesignator)) &&
        (MAIL_SuperMatch(hroute,bbo->BBSUnion.ForwardEntry.Hierarchy)) )
    {
     return(bbo);
    }
   bbo=bbo->next;
  }
 return(NULL);
}


static int MAIL_TestNoForwardEntry(const unsigned char *target,
                        const unsigned char *at,const unsigned char *hroute,
                        const unsigned char *box)
{
 struct BBSObject *bbo;
 bbo=BBSHook;

 while (bbo!=NULL)
  {
   if ( (bbo->objecttype==BBSObject_DontForward) &&
        (MAIL_SuperMatch(target,bbo->BBSUnion.DontForward.Target)) &&
        (MAIL_SuperMatch(at,bbo->BBSUnion.DontForward.AtDesignator)) &&
        (MAIL_SuperMatch(hroute,bbo->BBSUnion.DontForward.Hierarchy)) &&
        (MAIL_SuperMatch(box,bbo->BBSUnion.DontForward.ForwardBox )) )
    {
     return(TRUE);
    }
   bbo=bbo->next;
  }
 return(FALSE);
}



static void *MAIL_ParseForward(void *fstruct,void *xmail,unsigned char *rptr,
                        unsigned char *notforward)
 {
  struct PFStruct
   {
    const unsigned char    *to;
    const unsigned char    *at;
    const unsigned char    *hroute;
    const unsigned char    *bid;
    struct BBSObject *bbo;
    unsigned long    inforward;
    unsigned char    fwdcalls[256][16];
   };

  struct PFStruct *pfs;

  pfs=fstruct;

  if (pfs==NULL)
   {
    pfs=AllocVec(sizeof(struct PFStruct),1);
    if (pfs==NULL) return(NULL);
    pfs->to=MAIL_GetMailTo(xmail);
    pfs->at=MAIL_GetMailAt(xmail);
    pfs->hroute=MAIL_GetMailHRoute(xmail);
    pfs->bid=MAIL_GetMailBid(xmail);

    pfs->inforward=0;
    pfs->bbo=NULL;
    if ( (pfs->at==NULL) || ((*(pfs->at))=='\0'))
     {
      FreeVec(pfs);
      return(NULL);
     }
   }


  if (pfs->inforward==256)
   {
    /* too much forward destinations */

    FreeVec(pfs);
    return(NULL);
   }

  /* check for next forward entry */

  while (1)

   {
    unsigned char *fbox;
    unsigned long i,already;

    pfs->bbo=MAIL_GetForwardEntry(pfs->to,pfs->at,pfs->hroute,pfs->bbo);
    if (pfs->bbo==NULL)
     {
      /* No more matching entries */
      FreeVec(pfs);
      return(NULL);
     }

    /* check for a locked forward */

    fbox=pfs->bbo->BBSUnion.ForwardEntry.ForwardBox;

    if ( MAIL_TestNoForwardEntry(pfs->to,pfs->at,pfs->hroute,fbox))
     {
      continue;
     }

    /* check for a exluded forward */

    if ( (notforward!=NULL) && (*notforward!='\0'))

     {
      if (CompareString(fbox,notforward))
       {
        continue;
       }
     }

    /* check for double forward routing */

    already=FALSE;
    for (i=0;i<pfs->inforward;++i)
     {
      if (CompareString(fbox,pfs->fwdcalls[i]))
       {
        /* Call is already forwarded */
        already=TRUE;
        break;
       }
     }
    if (already==TRUE) continue;

    /* add call to forwarded boxes */

    CopyString(pfs->fwdcalls[pfs->inforward],fbox);
    ++pfs->inforward;

    /* return box to client */

    CopyString(rptr,fbox);
    return(pfs);
   }
 }


void MAIL_ForwardMail(struct MailHandle *xmail)
{
 {
  void *fparse;
  unsigned char fbox[16];

  fparse=NULL;
  while (  (fparse=MAIL_ParseForward(fparse,xmail,fbox,xmail->MailNode->RxFrom) )!=NULL)
   {
    MAIL_AddForwardMail(fbox,MAIL_GetMailBid(xmail));
   }
 }
}



int MAIL_GetForwardDest(struct MailHandle *xmail,unsigned char *xline)
{
 struct Mail *cmail;
 unsigned char *xptr,*sptr;
 unsigned long xin,xlf,xnum;
 unsigned char fbox[16];
 unsigned long i,l,v;

 cmail=xmail->MailNode;


 xptr=xline;
 xin=0;
 xnum=0;
 xlf=FALSE;

 for (i=0;i<512;++i)
  {
   l=i/32;
   v=1<<(i%32);
   if (!(cmail->ForwardDest[l]&v)) continue;
   if ( (cmail->ForwardDone[l]&v)) continue;
   if (MailBBSTable==NULL) continue;
   MAIL_DecodeCall(fbox,MailBBSTable->ForwardBBS[i]);


   ++xnum;
   sptr=fbox;
   while ((*sptr!='\0'))
    {
     *(xptr++)=*(sptr++);
     ++xin;
    }
   if ( (xin>70) && (!xlf) )
    {
     xlf=TRUE;
     ++xin;
     *(xptr++)='\r';
    }
    else
    {
     *(xptr++)=' ';
     ++xin;
    }
   if (xin>140)
    {
     *(xptr++)='.';
     *(xptr++)='.';
     *(xptr++)='.';
     break;
    }
   }

 *(xptr++)='\r';
 *(xptr)='\0';
 return (xnum);
}

void MAIL_ChangeUser(unsigned char *call,unsigned char *name,
                     unsigned char *qth,unsigned char *zipcode,
                     unsigned char *homebbs,int savedb)
{
 struct BBSObject *bbo;

 if (homebbs[0]=='\0') return;

 if ((bbo=MAIL_GetUserEntry(call))==NULL)
  {
   MAIL_AddUser(call,name,qth,zipcode,homebbs);
  }
  else
  {
   CopyString(bbo->BBSUnion.User.Name,name);
   CopyString(bbo->BBSUnion.User.QTH,qth);
   CopyString(bbo->BBSUnion.User.PLZ,zipcode);
   CopyString(bbo->BBSUnion.User.HomeBBS,homebbs);
  }
 if (savedb) MAIL_SaveBBSData();
}

int MAIL_GetForwardBytes(unsigned char *box)
 {
  signed long fboxn;
  unsigned long fboxlong;
  unsigned long fboxbitv;
  struct Mail *cmail;
  unsigned long i;
  unsigned long bytes;

  fboxn=MAIL_GetFBoxNumber(box);
  if (fboxn==-1) return(0);
  fboxlong=fboxn/32;
  fboxbitv=1<<(fboxn%32);
  cmail=MailNode;
  bytes=0;
  if (cmail==NULL) return(0);
  for (i=0;i<MailBase->NumberMails;++i,++cmail)
   {
    if (cmail->Number==0) continue;
    if (!(cmail->ForwardDest[fboxlong]&fboxbitv)) continue;
    if ( (cmail->ForwardDone[fboxlong]&fboxbitv)) continue;
    bytes+=cmail->Bytes;
   }
  return(bytes);
 }

int MAIL_GetForwardMails(unsigned char *box)
 {
  signed long fboxn;
  unsigned long fboxlong;
  unsigned long fboxbitv;
  struct Mail *cmail;
  unsigned long i;
  unsigned long mails;

  fboxn=MAIL_GetFBoxNumber(box);
  if (fboxn==-1) return(0);
  fboxlong=fboxn/32;
  fboxbitv=1<<(fboxn%32);
  cmail=MailNode;
  mails=0;
  if (cmail==NULL) return(0);
  for (i=0;i<MailBase->NumberMails;++i,++cmail)
   {
    if (cmail->Number==0) continue;
    if (!(cmail->ForwardDest[fboxlong]&fboxbitv)) continue;
    if ( (cmail->ForwardDone[fboxlong]&fboxbitv)) continue;
    ++mails;
   }
  return(mails);
 }




int MAIL_AddForwardMail(const unsigned char *box,const unsigned char *bid)
 {
  signed long fboxn;
  unsigned long fboxlong;
  unsigned long fboxbitv;
  struct Mail *cmail;
  unsigned long i;

  fboxn=MAIL_GetFBoxNumber(box);
  if (fboxn==-1)
   {
    if (!MAIL_AddBoxCall(box)) return(FALSE);
    fboxn=MAIL_GetFBoxNumber(box);
    if (fboxn==-1) return(FALSE);
   }
  fboxlong=fboxn/32;
  fboxbitv=1<<(fboxn%32);
  cmail=MailNode;
  if (cmail==NULL) return(FALSE);
  for (i=0;i<MailBase->NumberMails;++i,++cmail)
   {
    if (cmail->Number==0) continue;
    if (!CompareString(bid,cmail->Bid)) continue;
    cmail->ForwardDest[fboxlong]|=fboxbitv;
    MAIL_SaveRecord(cmail);
    return(TRUE);
   }
  return(FALSE);
 }

int MAIL_RemoveFMail(unsigned char *box,unsigned long mnum)
 {
  signed long fboxn;
  unsigned long fboxlong;
  unsigned long fboxbitv;
  struct Mail *cmail;
  unsigned long i;

  fboxn=MAIL_GetFBoxNumber(box);
  if (fboxn==-1) return(FALSE);
  fboxlong=fboxn/32;
  fboxbitv=1<<(fboxn%32);
  cmail=MailNode;
  if (cmail==NULL) return(FALSE);
  for (i=0;i<MailBase->NumberMails;++i,++cmail)
   {
    if (cmail->Number!=mnum) continue;
    cmail->ForwardDone[fboxlong]|=fboxbitv;
    MAIL_SaveRecord(cmail);
    return(TRUE);
   }
  return(FALSE);
 }




int MAIL_GetNextFMail(unsigned char *box,unsigned long offset)
 {
  signed long fboxn;
  unsigned long fboxlong;
  unsigned long fboxbitv;
  struct Mail *cmail;
  unsigned long i;
  unsigned long xoffset;
  unsigned long mailn;

  fboxn=MAIL_GetFBoxNumber(box);
  if (fboxn==-1) return(0);
  fboxlong=fboxn/32;
  fboxbitv=1<<(fboxn%32);
  mailn=0;
  xoffset=offset;
  cmail=MailNode;
  if (cmail==NULL) return(0);
  for (i=0;i<MailBase->NumberMails;++i,++cmail)
   {
    if (cmail->Number==0) continue;
    if (!(cmail->ForwardDest[fboxlong]&fboxbitv)) continue;
    if ( (cmail->ForwardDone[fboxlong]&fboxbitv)) continue;
    if (xoffset==0)
     {
      mailn=cmail->Number;
      break;
     }
    xoffset--;
   }
  return(mailn);
 }


static void MAIL_ComposeRoute(unsigned char *at,unsigned char *hroute,unsigned char *route)
 {
  unsigned char *xr,*sc;

  xr=route;
  if ( (at!=NULL) && (at[0]!='\0') )
   {
    sc=at;
    while (*sc!='\0') *(xr++)=*(sc++);
    if ( (hroute!=NULL) && (hroute[0]!='\0'))
     {
      sc=hroute;
      *(xr++)='.';
      while (*sc!='\0') *(xr++)=*(sc++);
     }
   }
  *(xr++)='\0';
 }

signed long MAIL_WriteMail(struct MailHandle *mailh,void *data,unsigned long length)
 {
  if (length==0) return(0);
  if (mailh->MailMode==0) return(-1);

  if (mailh->LineBytes!=-1)
   {
    /* parse text lines of mail*/
    unsigned long si;
    unsigned char *scptr;

    for (si=0,scptr=data;si<length;++si,++scptr)
     {
      if ((*scptr=='\r') && (mailh->LineBytes!=0))
       {
        /* handle text line */
        mailh->LineBuffer[mailh->LineBytes]='\0';
        mailh->LineBytes=0;
        if ( (mailh->MailInHeader) && (mailh->LineBuffer[0]=='R')
             && (mailh->LineBuffer[1]==':'))
         {
          /* parse an R: Line */
          unsigned char date[16];
          unsigned char bbs[16];
          unsigned char *sptr,*cptr;
          unsigned long i;
          date[0]='\0';
          bbs[0]='\0';

          mailh->MailNode->Status&=((1<<MAILSTATUS_LOCAL)^0xffffffff);
          sptr=mailh->LineBuffer+2;
          cptr=date;
          i=0;
          while (1)
           {
            if (*sptr=='z') break;
            if (*sptr=='Z') break;
            if (*sptr==' ') break;
            if (*sptr=='\0') break;
            ++i;
            if (i==16) break;
            *(cptr++)=*(sptr++);

           }
          *cptr='\0';


          sptr=mailh->LineBuffer;
          cptr=bbs;
          i=999;
          while (1)
           {
            if ( (*sptr==' ') && (*(sptr+1)='@') && (*(sptr+2)=':'))
              {
               i=0;
               break;
              }
            ++sptr;
           }
          if (i!=999)
           {
            sptr+=3;
            while(1)
             {
              if (*sptr=='.') break;
              if (*sptr==' ') break;
              if (*sptr=='\0') break;
              ++i;
              if (i==7) break;
              *(cptr++)=*(sptr++);
             }
            *cptr='\0';
           }
          /* parse date string */

           {
            int validdate,i;

            validdate=TRUE;
            for (i=0,cptr=date;i<11;++i,++cptr)
             {
              if (i==6)
               {
                if (*cptr!='/')
                 {
                  validdate=FALSE;
                  break;
                 }
               }
               else
               {
                if ( (*cptr<'0') || (*cptr>'9'))
                 {
                  validdate=FALSE;
                  break;
                 }
               }
             }
            if (validdate==TRUE)
             {
              struct ClockData cdat;
              unsigned long seconds;

              cdat.sec=0;
              cdat.min=date[10]-'0'+(date[9]-'0')*10;
              cdat.hour=date[8]-'0'+(date[7]-'0')*10;
              cdat.mday=date[5]-'0'+(date[4]-'0')*10;
              cdat.month=date[3]-'0'+(date[2]-'0')*10;
              cdat.year=date[1]-'0'+(date[0]-'0')*10;
              cdat.year+=1900;
              if (cdat.year<1996) cdat.year+=100;
              cdat.wday=0;

              seconds=Date2Amiga(&cdat);
              mailh->MailNode->OriginDate[0]=seconds/(60*60*24);
              mailh->MailNode->OriginDate[1]=(seconds/60)%(60*24);
             }
           }


          /* parse rx from */

          if (bbs[0]!='\0')
           {
            CopyString(mailh->MailNode->OriginBBS,bbs);
            MAIL_RemoveFMail(bbs,mailh->MailNode->Number);
           }

         }
         else
         {
          if (mailh->MailInHeader)
           {
            /* R: header is done - eventually add mail text header*/

            mailh->MailInHeader=0;

            if ( (!(mailh->MailNode->Status&(1<<MAILSTATUS_ACKMAIL))) &&
                 (!mailh->ReceivedFWD))
             {
              unsigned char fromroute[80];
              unsigned char toroute[80];
              unsigned char targetarray[384];
              unsigned char *paramarray[8];
              unsigned long i;
              unsigned char *cptr;
              unsigned char *username;

              MAIL_ComposeRoute((unsigned char *) MAIL_GetBoxCall(),Preferences.BoxHRoute,fromroute);
              MAIL_ComposeRoute(mailh->MailNode->At,mailh->MailNode->HRoute,toroute);
              username=MAIL_GetUserName(mailh->MailNode->From);
              if (*username=='\0') username=NULL;

              paramarray[0]=mailh->MailNode->From;
              paramarray[1]=fromroute;
              paramarray[2]=(((unsigned char *) username==(unsigned char *) NULL)?(unsigned char *) "???":(unsigned char *) username);
              paramarray[3]=mailh->MailNode->To;
              paramarray[4]=toroute;

              RawDoFmt("\rFrom:%s@%s (%s)\rTo  :%s@%s\r\r",paramarray,PutRawDoFmt,targetarray);

              i=0;cptr=targetarray;
              while (*(cptr++)!='\0') ++i;
              if (Write(mailh->FileHandle,targetarray,i)!=i)
               {
                return(-1);
               }
              mailh->ProcessedBytes+=i;
              mailh->MailNode->Bytes+=i;
             }
           }


          /* test for #BIN# - set autobin flag and abort line parse*/

          if ( (mailh->LineBuffer[0]=='#') &&
               (mailh->LineBuffer[1]=='B') &&
               (mailh->LineBuffer[2]=='I') &&
               (mailh->LineBuffer[3]=='N') &&
               (mailh->LineBuffer[4]=='#'))

           {
            mailh->MailNode->Status|=(1<<MAILSTATUS_AUTOBINARY);
            mailh->LineBytes=-1;
            break;
           }

         }

       }

      if ( ((*scptr!='\r')) && (mailh->LineBytes<510))

       {
        mailh->LineBuffer[mailh->LineBytes]=*scptr;
        mailh->LineBytes++;
       }

     }
   }

  if (Write(mailh->FileHandle,data,length)!=length)
   {
    return(-1);
   }
  mailh->ProcessedBytes+=length;
  mailh->MailNode->Bytes+=length;
  return(0);
 }

void MAIL_HandleMailMacro(unsigned char *mailline,unsigned long number)
 {
  unsigned long remember,xremember;
  unsigned char *cptr;
  unsigned long column;
  unsigned long xline;
  unsigned long mailindouble;
  unsigned char *maildouble[64];
  unsigned long i;
  int firstrun;
  struct Mail *mail1;
  struct Mail *mail2;


  mailindouble=0;
  mailline[0]='\0';
  if (number<0) return;
  if (number>8) return;
  remember=GlobalArraysP->mailmacroremember[number];

  column=0;
  xline=0;
  cptr=mailline;
  xremember=remember;
  if (MailNode==NULL) return;

  mail1=MailNode+(MailBase->NumberMails);
  mail2=NULL;
  while (mail1>MailNode)
   {
    --mail1;
    if (mail1->Number==0) continue;
    if (mail1->Number<remember) continue;
    mail2=mail1;
    break;
   }
  if (mail2==NULL) mail2=MailNode+(MailBase->NumberMails-1);
  mail1=mail2;
  firstrun=TRUE;
  while (1)
   {
    if ( (mail1==mail2) && (firstrun==FALSE)) break;
    firstrun=FALSE;
    mail1--;
    if (mail1<MailNode) mail1=MailNode+(MailBase->NumberMails-1);
    if (mail1->Number==0) continue;
    if (!(mail1->Status& (1<<MAILSTATUS_PERSONAL))) continue;
    if ( (mail1->Status& (1<<MAILSTATUS_READ))) continue;
    if ( (mail1->Status& (1<<MAILSTATUS_FORWARD))) continue;
    if (!(mail1->Status& (1<<MAILSTATUS_LOCALUSER))) continue;

    /* output mail */
    if (mailindouble==64) break;
    remember=mail1->Number;
    for (i=0;i<mailindouble;++i)
     {
      if (CompareString(maildouble[i],mail1->To)) {i=9999;break;}
     }
    if (i==9999) continue;
    maildouble[mailindouble]=mail1->To;
    mailindouble++;

    CopyString(cptr,mail1->To);
    while (*cptr!='\0') {++cptr;++column;}

    if (column<60)
     {
      *(cptr++)=' ';
     }
     else
     {
      *(cptr++)=(number==9)?' ':'\r';
      column=0;
      xline++;
      if (xline==3) break;
     }
   }
  *(cptr)='\0';
  GlobalArraysP->mailmacroremember[number]=remember;

 }

unsigned long MAIL_LookLocalMail(void)
{
 struct Mail *cmail;
 unsigned long i,nm;
 if (MailNode==NULL) return(0);
 cmail=MailNode;
 nm=0;
 for (i=0;i<MailBase->NumberMails;++i,cmail++)
  {
   if (cmail->Number==0) continue;
   if (!(cmail->Status& (1<<MAILSTATUS_PERSONAL))) continue;
   if ( (cmail->Status& (1<<MAILSTATUS_READ))) continue;
   if ( (cmail->Status& (1<<MAILSTATUS_FORWARD))) continue;
   if (!(cmail->Status& (1<<MAILSTATUS_LOCALUSER))) continue;
   ++nm;
  }
 return(nm);
}


static void MAIL_MakeMailName(struct Mail *mail,unsigned char *fname)
 {
  unsigned char *sptr,*cptr;
  CopyString(fname,"data/bbs/");
  sptr=fname;
  while (*sptr!='\0') ++sptr;
  cptr=mail->Bid;
  while (*cptr!='\0') *(sptr++)=*(cptr++);
  *(sptr++)='.';
  *(sptr++)='m';
  *(sptr++)='l';
  *(sptr++)='f';
  *(sptr)='\0';
 }

static signed long MAIL_InternalKillMail(struct Mail *mail,unsigned long crashmode)
 {
  struct MailHandle *mhl;
  struct Mail *xmail,*ymail;
  mhl=(void *) MailHandles.lh_Head;
  while (mhl->Node.ln_Succ!=NULL)
   {
    if (mhl->MailNode==mail) return (-1);
    mhl=(void *) mhl->Node.ln_Succ;
   }
   {
    unsigned char fnarray[64];
    MAIL_MakeMailName(mail,fnarray);
    if (DeleteFile(fnarray)==0)
     {
      if (!crashmode) return (-2);
     }
   }
  xmail=mail-1;
  ymail=mail;
  while (ymail>MailNode)
   {
    MAIL_InternalMoveMail(xmail,ymail);
    --xmail;
    --ymail;
   }
  MAIL_ClearMail (MailNode);
  MAIL_SaveRecordAllMails();
  return(0);
 }

static void MAIL_InternalMoveMail(struct Mail *mail1,struct Mail *mail2)
 {
  struct MailHandle *mhl;
  mhl=(void *) MailHandles.lh_Head;
  while (mhl->Node.ln_Succ!=NULL)
   {
    if (mhl->MailNode==mail1) mhl->MailNode=mail2;
    mhl=(void *) mhl->Node.ln_Succ;
   }
  *mail2=*mail1;
 }

static void MAIL_KillIncompletes(void)
 {
  struct Mail *mailnode;
  unsigned long number;
  if (MailNode==NULL) return;
  number=MailBase->NumberMails;
  mailnode=MailNode;
  while (number>0)
   {
    if (mailnode->Status&(1<<MAILSTATUS_INWRITE))
     {
      MAIL_InternalKillMail(mailnode,TRUE);
      mailnode=MailNode;
      number=MailBase->NumberMails;
      continue;
     }
    number--;
    mailnode++;
   }
 }

void MAIL_DailyHousekeeping(void)
 {
  if (CurrentDateStamp.ds_Days==MailBase->HousekeepDay) return;
  MailBase->HousekeepDay=CurrentDateStamp.ds_Days;
  MAIL_SaveRecord(MailBase);
  return;
 }

static void MAIL_MakeSpaceMails(unsigned long nmailsgive)
 {
  unsigned long freemails,needmails;
  unsigned long i,pass;
  struct Mail *mail;
  if (MailNode==NULL) return;

  freemails=MAIL_GetMailCapacity();
  if (nmailsgive==0)
   {
    needmails=MailBase->NumberMails/100;
    if (needmails<8) needmails=8;
   }
   else
   {
    needmails=nmailsgive;
   }
  if (freemails>=needmails) return;
  needmails-=freemails;
  pass=0;
  while (needmails>0)
   {
    if (pass==10) break;
    for (i=0,mail=(MailNode+MailBase->NumberMails-1);i<MailBase->NumberMails;++i,--mail)
     {
      int delmail;
      delmail=FALSE;
      switch (pass)
       {
        case 0:  /* free killed mails */
          if (mail->Status&(1<<MAILSTATUS_KILLED)) delmail=TRUE;
          break;
        case 1:  /* free forwarded personal mails */
          if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
          if (!(mail->Status&(1<<MAILSTATUS_FORWARD))) break;
          delmail=TRUE;
          break;
        case 2:  /* free already read personal mails */
          if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
          if (!(mail->Status&(1<<MAILSTATUS_READ))) break;
          delmail=TRUE;
          break;
        case 3:  /* free bulletins already forwarded to all */
          if (mail->Status&(1<<MAILSTATUS_PERSONAL)) break;
           {
            int j,godd;

            godd=TRUE;
            for (j=0;j<4;++j)
             {
              if ( (mail->ForwardDest[j]&mail->ForwardDone[j])!=
                    mail->ForwardDest[j]) godd=FALSE;
             }
            if (godd==TRUE) delmail=TRUE;
            break;
           }
        case 4:  /* free all bulletins */
          if (mail->Status&(1<<MAILSTATUS_PERSONAL)) break;
          delmail=TRUE;
          break;
        case 5:  /* free all personal mails*/
          if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
          delmail=TRUE;
          break;
       }
      if (delmail)
       {
        if (MAIL_InternalKillMail(mail,FALSE)!=0)
         {
          continue;
         }
        --needmails;
        --pass;
        break;
       }
     }
    ++pass;
   }
  return;

 }

static unsigned long MAIL_GetMailCapacity(void)
 {
  unsigned long fmails;
  struct Mail *mail;
  unsigned long i;

  if (MailNode==NULL) return(0);

  mail=MailNode;
  fmails=0;
  for (i=0;i<MailBase->NumberMails;++i,++mail)
   {
    if (mail->Number==0) {++fmails;} else {break;}
   }
  return(fmails);
 }

struct Mail *MAIL_GetFreeMail(void)
 {
  struct Mail *freemail;
  int count;
  if (MailNode==NULL) return(NULL);
  if (MAIL_GetMailCapacity()==0)
   {
    MAIL_MakeSpaceMails(0);
    if (MAIL_GetMailCapacity()==0) return (NULL);
   }

  freemail=MailNode;
  count=MailBase->NumberMails;
  while (freemail->Number==0 && count!=0 ) {
    ++freemail;
    --count;
   }
  --freemail;
  return(freemail);

 }


const unsigned char *MAIL_GetBoxCall()
 {
  if (Preferences.BoxIdent[0]!='\0') return(Preferences.BoxIdent);
  if (Preferences.Callsets[0].MyCall!='\0') return(Preferences.Callsets[0].MyCall);
  return ("MYBBS");
 }

unsigned long MAIL_ComposeRLine(struct MailHandle *mailh,unsigned char *cbuf)
 {
  struct Mail *mail;
  unsigned char *cptr;
  const unsigned char *sptr;


  mail=mailh->MailNode;
  if (!Preferences.FullBBS) return(0);
  if (mail->Status&(1<<MAILSTATUS_ACKMAIL)) return(0);
  cptr=cbuf;
  *(cptr++)='R';
  *(cptr++)=':';
  MAIL_InternalGetDate(mail,cptr,TRUE);
  while (*cptr!='\0') ++cptr;
  *(cptr++)='Z';
  *(cptr++)=' ';
  *(cptr++)='@';
  *(cptr++)=':';
  sptr=MAIL_GetBoxCall();
  while (*sptr!='\0') *(cptr++)=*(sptr++);
  *(cptr++)='.';
  sptr=Preferences.BoxHRoute;
  while (*sptr!='\0') *(cptr++)=*(sptr++);
  *(cptr++)=' ';
  *(cptr++)='#';
  *(cptr++)=':';
  if (mail->Number>=10000) *(cptr++)=mail->Number/10000+'0';
  if (mail->Number>=1000) *(cptr++)=(mail->Number/1000)%10+'0';
  if (mail->Number>=100) *(cptr++)=(mail->Number/100)%10+'0';
  if (mail->Number>=10) *(cptr++)=(mail->Number/10)%10+'0';
  *(cptr++)=mail->Number%10+'0';
  *(cptr++)=' ';
  *(cptr++)='[';
  sptr=Preferences.BoxQTH;
  while (*sptr!='\0') *(cptr++)=*(sptr++);
  *(cptr++)=']';
  *(cptr++)=' ';
  *(cptr++)='P';
  *(cptr++)='P';
  *(cptr++)='B';
  *(cptr++)='o';
  *(cptr++)='x';
  *(cptr++)=0x0d;
  *(cptr)='\0';
  return(cptr-cbuf);
 }


static int MAIL_CopyCallUpper(unsigned char *xdptr,const unsigned char *xsptr,
                          unsigned long len,unsigned long mode)
 {
  unsigned char *dptr;
  const unsigned char *sptr;
  unsigned long i;

  dptr=xdptr;  /* mode 0=copy 1=copy-cut-SSID 2=copy-cut-SSID-HRoute*/
  sptr=xsptr;
  i=0;

  if ( (sptr==NULL) || (*sptr=='\0'))
   {
    *dptr='\0';
    return(TRUE);
   }

  while ( (*sptr!='\0') && ( (*sptr!='-') || (mode<1) ) &&
          ( (*sptr!='.') || (mode<2) ) )
   {
    ++i;
    if (i>len)
     {
      return(FALSE);
     }
    if ( (*sptr>='a') && (*sptr<='z'))
     {
      *(dptr++)=*(sptr++)-32;
     }
     else
     {
      *(dptr++)=*(sptr++);
     }
   }
  *dptr='\0';
  return(TRUE);
 }

void *MAIL_SendMail(const unsigned char *call,const unsigned char *tocall,
                    const unsigned char *atcall,unsigned long personal,
                    const unsigned char *bid)

 {
  unsigned char mailbid[32];
  struct Mail *smail;
  struct MailHandle *smailh;

  const unsigned char *sptr;
  unsigned char *dptr;
  unsigned long i;


  if (MailNode==NULL) return(NULL);
  if ( (call==NULL) || (call[0]=='\0') )  return(NULL);  /* No source call*/
  if ( (tocall==NULL) || (tocall[0]=='\0') ) return(NULL); /* No destination call */

  mailbid[0]='\0';
  if ( (bid!=NULL) && (bid[0]!='\0'))
   {
    if (MAIL_SearchMailBid(bid)!=NULL) return (NULL); /* BID already exists*/
    CopyString(mailbid,bid);
   }

  smail=MAIL_GetFreeMail();
  if (smail==NULL) return(NULL);
  MAIL_ClearMail(smail);


  /* read in mail parameters */

  if ( (!MAIL_CopyCallUpper(smail->From,call,6,1)) ||
       (!MAIL_CopyCallUpper(smail->To,tocall,8,1)) ||
       (!MAIL_CopyCallUpper(smail->At,atcall,6,2)))
   {
    MAIL_ClearMail(smail);
    MAIL_SaveRecord(smail);
    return(NULL);
   }

  smail->HRoute[0]='\0';
  if ( (atcall!=NULL) && (*atcall!='\0') )
   {
    sptr=atcall;
    while ( (*sptr!='.') && (*sptr!='\0') ) ++sptr;
    if (*sptr=='.')
     {
      ++sptr;
      if (!MAIL_CopyCallUpper(smail->HRoute,sptr,62,0))
       {
        MAIL_ClearMail(smail);
        MAIL_SaveRecord(smail);
        return(NULL);
       }
     }
   }

  smail->Title[0]='\0';
  smail->Date[0]=CurrentDateStamp.ds_Days;
  smail->Date[1]=CurrentDateStamp.ds_Minute;
  smail->DateStatus[0]=CurrentDateStamp.ds_Days;
  smail->DateStatus[1]=CurrentDateStamp.ds_Minute;
  smail->OriginDate[0]=CurrentDateStamp.ds_Days;
  smail->OriginDate[1]=CurrentDateStamp.ds_Minute;

  if (!MAIL_CopyCallUpper(smail->OriginBBS,MAIL_GetBoxCall(),6,0))
   {
    MAIL_ClearMail(smail);
    MAIL_SaveRecord(smail);
    return(NULL);
   }

  /* Preset mail fields*/

  smail->Status=1<<MAILSTATUS_INWRITE;
  smail->Bytes=0;
  if ((MailBase->LastBID%100000)==99999) ++MailBase->LastBID;
  ++MailBase->LastBID;
  smail->Number=MailBase->LastBID%100000;
  MAIL_SaveRecord(MailBase);

  /* Setup mail status */

  if (personal) smail->Status|=1<<MAILSTATUS_PERSONAL;
  if (personal==2) smail->Status|=1<<MAILSTATUS_ACKMAIL;
  if (mailbid[0]=='\0') smail->Status|=1<<MAILSTATUS_LOCAL;

  /* Make a BID if necessary */

  if (mailbid[0]=='\0')
   {
    dptr=mailbid;
    if (smail->Number>=10000) *(dptr++)=smail->Number/10000+'0';
    if (smail->Number>=1000) *(dptr++)=(smail->Number/1000)%10+'0';
    if (smail->Number>=100) *(dptr++)=(smail->Number/100)%10+'0';
    if (smail->Number>=10) *(dptr++)=(smail->Number/10)%10+'0';
    *(dptr++)=(smail->Number)%10+'0';
    if (smail->Number>=100000)
     {
      *(dptr++)=((smail->Number)%100000)-1+'A';
     }
     else
     {
      *(dptr++)='_';
     }
    CopyStringUpper(dptr,MAIL_GetBoxCall());
   }
  CopyString(smail->Bid,mailbid);

  /* Test for redirection of a mail to the sysop */

  if ( (smail->Status&(1<<MAILSTATUS_PERSONAL)) &&
       (Preferences.RedirectMycalls) )
   {
    unsigned char call1[12];
    unsigned char call2[12];
    int isredir=FALSE;
    CopyStringUpper(call1,smail->To);
    for (i=0;i<8;++i)
     {
      MAIL_CopyCallUpper(call2,Preferences.Callsets[i].MyCall,6,1);
      if (CompareString(call1,call2))
       {
        MAIL_CopyCallUpper(smail->To,MAIL_GetBoxCall(),6,1);
        smail->At[0]='\0';
        isredir=TRUE;
        break;
       }
     }


    /* autorouting of P-Mail with no @-target */

    if ( (!isredir) && (smail->At[0]=='\0') )
     {
      dptr=MAIL_GetUserBBS(smail->To);
      if (dptr!=NULL) CopyString(smail->At,dptr);
     }


   }





  /* removing of own box identifier in @ field */

   {
    unsigned char call1[16];

    MAIL_CopyCallUpper(call1,MAIL_GetBoxCall(),6,1);
    if (CompareString(call1,smail->At))
     {
      smail->At[0]='\0';
     }
   }

  /* adding an hierarchical route if @ field is defined but no HRoute*/

  if ( (smail->At[0]!='\0') && (smail->HRoute[0]=='\0'))
   {
    dptr=MAIL_GetHRoute(smail->At);
    if (dptr!=NULL) CopyString(smail->HRoute,dptr);
   }

  /* test for a local user - try to obtain user data from database */

  if (smail->Status&(1<<MAILSTATUS_PERSONAL))
   {
    struct User *muser;

    muser=QSO_OpenUser_Try(smail->To);
    if (muser!=NULL)
     {
      unsigned char call1[16];

      MAIL_CopyCallUpper(call1,MAIL_GetBoxCall(),15,1);
      QSO_CloseUser(muser);

      /* check for box call - don't make box msg to local users */
      if (!CompareString(call1,smail->To))
       {
        smail->Status|=1<<MAILSTATUS_LOCALUSER;
       }
     }
   }


  /* preparing mail handle structure - open mail file */

  smailh=AllocVec(sizeof(*smailh),0x10001);
  if (smailh==NULL)
   {
    MAIL_ClearMail(smail);
    MAIL_SaveRecord(smail);
    return(NULL);
   }

  smailh->Node.ln_Succ=NULL;
  smailh->Node.ln_Pred=NULL;
  smailh->Node.ln_Type=NT_UNKNOWN;
  smailh->Node.ln_Pri=0;
  smailh->Node.ln_Name=NULL;

  smailh->MailNode=smail;
  smailh->MailMode=1;
  smailh->FileHandle=NULL;
  smailh->ProcessedBytes=0;
  smailh->LineBytes=0;
  smailh->Authorization=0;
  smailh->ReceivedFWD=FALSE;
  smailh->MailInHeader=TRUE;

  MAIL_MakeMailName(smail,smailh->FileName);

  if ( (smailh->FileHandle=Open(smailh->FileName,MODE_NEWFILE))==NULL)
   {
    FreeVec(smailh);
    MAIL_ClearMail(smail);
    MAIL_SaveRecord(smail);
    return(NULL);
   }

  AddTail(&MailHandles,(struct Node *) smailh);


  /* looking for forward destinations */

  if (smail->At[0]!='\0')
   {
    MAIL_ForwardMail(smailh);
   }

  /* saveing record and return mailhandle to caller */

  MAIL_SaveRecord(smail);
  return(smailh);
 }


unsigned long MAIL_GetLatestMail()
 {
  unsigned long i;
  struct Mail *xmail;

  if (MailNode==NULL) return(0);
  for (i=0,xmail=MailNode;i<MailBase->NumberMails;++i,xmail++)
   {
    if (xmail->Number!=0) return (xmail->Number);
   }
  return(0);
 }

void MAIL_CloseMail(struct MailHandle *mailh)
 {
  struct Mail *mail;

  if (mailh==NULL) return;
  mail=mailh->MailNode;

  /* close open file - update byte size - test for incomplete*/
  if (mailh->FileHandle!=NULL)
   {
    Close(mailh->FileHandle);
    if (mailh->MailMode)
     {
      mail->Bytes=mailh->ProcessedBytes;
      mail->Status&=(1<<MAILSTATUS_INWRITE)^0xffffffff;
      MAIL_SaveRecord(mail);

      if (mail->Status&(1<<MAILSTATUS_INCOMPLETE))
       {
        Remove((struct Node *) mailh);
        FreeVec(mailh);
        MAIL_InternalKillMail(mail,FALSE);
        return;
       }
      mailh->MailMode=0;

      /* test for ARexx invocation */
      if (mail->Status&(1<<MAILSTATUS_PERSONAL) &&
         (mail->At[0]=='\0'))
       {
        unsigned char ARexxScript[64];
        unsigned char ARexxParams[64];
        CopyString(ARexxScript,"BBS_");
        CopyString(ARexxScript+4,mail->To);

        MAIN_LongToString(ARexxParams,mail->Number);
        MAIN_ExecuteARexxScript(ARexxScript,ARexxParams,1);

       }

      /* do an acknowledge if wanted */
      if ( (mail->Status&(1<<MAILSTATUS_WANTACK)) && (mail->At[0]=='\0') )
       {
        struct MailHandle *amail;
        const unsigned char *ackto,*ackat;

        amail=MAIL_SendMail(mail->To,mail->From,mail->OriginBBS,2,NULL);
        if (amail!=NULL)
         {
          unsigned char datestring[48];
          unsigned char timestring[48];

           /* set title of AckMail to ACK:<oldmailtitle>*/
           {
            unsigned char AMailTitle[100];
            CopyString(AMailTitle,"ACK:");
            CopyString(AMailTitle+4,mail->Title);
            MAIL_SetMailTitle(amail,AMailTitle);
           }
           /* make acknowledge date */
           {
            struct DateTime datetime;
            datetime.dat_Stamp=CurrentDateStamp;
            datetime.dat_Format=FORMAT_INT;
            datetime.dat_Flags=0;
            datetime.dat_StrDay=NULL;
            datetime.dat_StrDate=datestring;
            datetime.dat_StrTime=timestring;
            DateToStr(&datetime);
           }
           /* get acknowledge fields */

          ackto=mail->To;
          if (mail->At[0]!='\0')
           {
            ackat=mail->At;
           }
           else
           {
            ackat=MAIL_GetBoxCall();
           }

          /* output header using RawDoFmt*/
           {
            unsigned char RawDoOut[128];
            const unsigned char *RawDoArray[4];
            unsigned char *sptr;
            unsigned long slen;

            RawDoArray[0]=ackto;
            RawDoArray[1]=ackat;
            RawDoArray[2]=datestring;
            RawDoArray[3]=timestring;

            RawDoFmt("MSG %s@%s - %s / %s local time\r",RawDoArray,PutRawDoFmt,RawDoOut);
            sptr=RawDoOut;
            slen=0;
            while (*(sptr++)!='\0') ++slen;
            MAIL_WriteMail(amail,RawDoOut,slen);
            MAIL_CloseMail(amail);
           }
         }
       }
     }
   }
  Remove((struct Node*) mailh);
  FreeVec(mailh);
  return;
 }

int MAIL_CopyMail(const unsigned char *call,const unsigned char *tocall,
                   const unsigned char *atcall,unsigned long personal,
                   const unsigned char *bid,unsigned long sourcenum,
                   const unsigned char *opencall,
                   const unsigned char *mailtitle)
 {
  struct MailHandle *smail;
  struct MailHandle *tmail;
  char mailline[256];
  int sz,mode=0;

  if ((smail=MAIL_OpenMail(sourcenum,opencall))==0) return(0);
  if ((tmail=MAIL_SendMail(call,tocall,atcall,personal,bid))==0)
   {
    return(0);
   }

  MAIL_SetMailTitle(tmail,mailtitle);

  tmail->MailInHeader=0;
   {
    const char *x="\r>>>> FORWARDED MESSAGE <<<<\r\r";
    if (MAIL_WriteMail(tmail,(char *) x,StringLength(x))!=0)
     {
      MAIL_MarkAsIncomp(tmail);
      MAIL_CloseMail(tmail);
      MAIL_CloseMail(smail);
      return(0);
     }
   }

  while (1)
   {
    if (mode==0)
     {
      sz=MAIL_ReadMailLine(smail,mailline,256);
     }
     else
     {
      sz=MAIL_ReadMail(smail,mailline,256);
     }
    if (sz==-1)
     {
      MAIL_MarkAsIncomp(tmail);
      MAIL_CloseMail(tmail);
      MAIL_CloseMail(smail);
      return(0);
     }

    if (sz==0) break;
    if ( mode==0 && mailline[0]=='R' && mailline[1]==':'  ) continue;
    mode=1;
    if (MAIL_WriteMail(tmail,mailline,sz)!=0)
     {
      MAIL_MarkAsIncomp(tmail);
      MAIL_CloseMail(tmail);
      MAIL_CloseMail(smail);
      return(0);
     }
   }
  MAIL_CloseMail(smail);
  MAIL_CloseMail(tmail);
  return(1);
 }

void *MAIL_OpenMail(unsigned long mailnum,const unsigned char *opencall)
 {
  struct Mail *tmail;
  struct MailHandle *tmailh;
  unsigned long i;
  if (MailNode==NULL) return(NULL);
  if (mailnum==0) return(NULL);

  for (i=0,tmail=MailNode;i<MailBase->NumberMails;++i,++tmail)
   {
    if (tmail->Number==mailnum)
     {
      i=12345678;
      break;
     }
   }
  if (i!=12345678) return(NULL);

  tmailh=(struct MailHandle *) MailHandles.lh_Head;

  while (tmailh->Node.ln_Succ!=NULL)
   {
    if ( (tmailh->MailNode==tmail) && (tmailh->MailMode))
     {
      return((void *) -1);
     }
    tmailh=(struct MailHandle *) tmailh->Node.ln_Succ;
   }


  /* check right for reading */

  if ( (opencall!=NULL) && (tmail->Status&(1<<MAILSTATUS_PERSONAL)))
   {
    unsigned char xcall[16];
    MAIL_CopyCallUpper(xcall,opencall,15,1);
    if ( (!CompareString(xcall,tmail->From)) &&
         (!CompareString(xcall,tmail->To)) )
     {
      return ((void *) -1);
     }
   }

  tmailh=AllocVec(sizeof(*tmailh),0x10001);
  if (tmailh==NULL) return(NULL);
  tmailh->Node.ln_Succ=NULL;
  tmailh->Node.ln_Pred=NULL;
  tmailh->Node.ln_Type=NT_UNKNOWN;
  tmailh->Node.ln_Pri=0;
  tmailh->Node.ln_Name=NULL;

  tmailh->MailNode=tmail;
  tmailh->MailMode=0;
  tmailh->FileHandle=0;
  tmailh->ProcessedBytes=0;
  MAIL_MakeMailName(tmail,tmailh->FileName);
  AddTail(&MailHandles,(struct Node *) tmailh);
  return(tmailh);
 }

unsigned long MAIL_SearchMail(const unsigned char *call,
                              unsigned long mode,unsigned long lastmail)
 {
  const unsigned char *searchcallptr;
  const unsigned long *extensionptr;

  unsigned char call1[12];
  unsigned char call2[12];

  struct Mail *mail;
  unsigned long restmails;

  if (MailNode==NULL) return(0);
  searchcallptr=call;
  extensionptr=NULL;

  if ( (searchcallptr==NULL) && (mode!=6) ) searchcallptr=MAIL_GetBoxCall();
  if (!MAIL_CopyCallUpper(call1,searchcallptr,11,1)) return(0);
  if ( (mode==8) || (mode==9))
   { /* duo calls*/
    if (call==NULL) return(0);
    if (!MAIL_CopyCallUpper(call2,call+16,11,1)) return(0);
   }
  if ( (mode==10) || (mode==11))
   { /* general extension pointer : area / list */
    extensionptr=*((unsigned long **) (call+16));
    if (extensionptr==NULL) return(0);
   }

  mail=MailNode;
  restmails=MailBase->NumberMails;
  if (lastmail!=0)
   {
    while (1)
     {
      if (restmails==0) return(0);
      if (mail->Number==lastmail) break;
      ++mail;--restmails;
     }
    ++mail;--restmails;
   }
  while (restmails!=0)
   {
    if ( (mail->Number==0) ||
         (mail->Status&(1<<MAILSTATUS_INWRITE)) ||
         (mail->Status&(1<<MAILSTATUS_KILLED))
       )
     {
      mail++;restmails--;continue;
     }

    switch (mode)
     {
      case 0:         /* standard > filter */
        if (CompareString(call1,mail->To)) return(mail->Number);
        break;
      case 1:         /* personal > filter */
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
        if (CompareString(call1,mail->To)) return(mail->Number);
        break;
      case 2:         /* standard < filter */
        if (CompareString(call1,mail->From)) return(mail->Number);
        break;
      case 3:         /* new personal > filter */
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
        if (mail->Status&(1<<MAILSTATUS_READ)) break;
        if (mail->Status&(1<<MAILSTATUS_FORWARD)) break;
        if (CompareString(call1,mail->To)) return(mail->Number);            
        break;
      case 4:         /* old personal > filter */ 
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
        if (!mail->Status&(1<<MAILSTATUS_READ)) break;
        if (CompareString(call1,mail->To)) return(mail->Number);
        break;
      case 5:         /* foreign personal filter */ 
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) break;
        if (CompareString(call1,mail->From)) break;
        if (CompareString(call1,mail->To)) break;
        return(mail->Number);
      case 6:         /* general bulletin only */
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) return(mail->Number);
        break;
      case 7:         /* general access filter */
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) return(mail->Number);
        if (CompareString(call1,mail->From)) return(mail->Number);
        if (CompareString(call1,mail->To)) return(mail->Number);
        break;
      case 8:         /* test for accessible mail from foreign call */
        if (!(CompareString(call2,mail->From))) break;
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) return(mail->Number);
        if (CompareString(call1,mail->To)) return(mail->Number);
        if (CompareString(call1,mail->From)) return(mail->Number);
        break;
      case 9:         /* test for accessible mail to foreign call */ 
        if (!(CompareString(call2,mail->To))) break;
        if (!(mail->Status&(1<<MAILSTATUS_PERSONAL))) return(mail->Number);
        if (CompareString(call1,mail->From)) return(mail->Number);
        if (CompareString(call1,mail->To)) return(mail->Number);
        break;
      case 10:        /* test for mail list*/
         {
          unsigned long i,found;
          found=FALSE;
          for (i=0;i<6;++i)
           {
            if (*(extensionptr+i)==0) break;
            if (*(extensionptr+i)==mail->Number)
             {
              found=TRUE;
              break;
             }
           }
          if (found==FALSE) break;
          if (!mail->Status&(1<<MAILSTATUS_PERSONAL)) return(mail->Number);
          if (CompareString(call1,mail->From)) return(mail->Number);
          if (CompareString(call1,mail->To)) return(mail->Number);          
          break;
         }
        
      case 11:        /* test for mail area */
        if (mail->Number<(*extensionptr)) break;
        if (mail->Number>(*(extensionptr+1))) break;
        if (!mail->Status&(1<<MAILSTATUS_PERSONAL)) return(mail->Number);
        if (CompareString(call1,mail->From)) return(mail->Number);
        if (CompareString(call1,mail->To)) return(mail->Number);          
        break;
      default:
        return(0);
     }
    mail++;restmails--;continue;
   }
  return(0);
 }

void MAIL_SetMailTitle(struct MailHandle *mailh,const unsigned char *title)
 {
  if (mailh->MailMode==0) return;
  CopyStringLimit(mailh->MailNode->Title,title,78);
  return;
 }

void MAIL_SetNotForward(struct MailHandle *mailh,const unsigned char *call)
 {
  mailh->ReceivedFWD=TRUE;
  if (!MAIL_CopyCallUpper(mailh->MailNode->RxFrom,call,6,0)) return;
  MAIL_RemoveFMail(mailh->MailNode->RxFrom,mailh->MailNode->Number);
 }

unsigned long MAIL_GetNumberMail(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Number);
 }

const unsigned char *MAIL_GetMailBid(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Bid);
 }

const unsigned char *MAIL_GetMailFm(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->From);
 }

const unsigned char *MAIL_GetMailTo(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->To);
 }

const unsigned char *MAIL_GetMailAt(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->At);
 }

const unsigned char *MAIL_GetMailTitle(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Title);
 }

const unsigned long *MAIL_GetMailDate(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Date);
 }

unsigned long MAIL_GetMailStatus(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Status);
 }

const unsigned char *MAIL_GetMailHRoute(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->HRoute);
 }

unsigned long MAIL_GetMailBytes(const struct MailHandle *mailh)
 {
  return(mailh->MailNode->Bytes);
 }

static void MAIL_InternalStatusTxt(const struct Mail *mail,unsigned char *xout)
 {
  unsigned char *yout;

  yout=xout;
  if (mail->Status&(1<<MAILSTATUS_PERSONAL))
   {
    if (mail->Status&(1<<MAILSTATUS_ACKMAIL))
     {
      *(yout++)='A';
     }
     else
     {
      *(yout++)='P';
     }
    if (mail->Status&(1<<MAILSTATUS_READ))
     {
      *(yout++)='Y';
     }
     else
     {
      if (mail->Status&(1<<MAILSTATUS_FORWARD))
       {
        *(yout++)='F';
       }
       else
       {
        *(yout++)='N';
       }
     }
   }
   else
   {
    *(yout++)='B';
    if (mail->Status&(1<<MAILSTATUS_FORWARD))
     {
      *(yout++)='F';
     }
     else
     {
      *(yout++)='$';
     }
   }
  if (mail->Status&(1<<MAILSTATUS_LOCAL))
   {
    *(yout++)='L';
   }
   else
   {
    *(yout++)=' ';
   }
  if ( (mail->Status&(1<<MAILSTATUS_7PLUS)) ||
       (mail->Status&(1<<MAILSTATUS_AUTOBINARY)) )
   {
    *(yout++)='D';
   }
   else
   {
    *(yout++)=' ';
   }
 }

void MAIL_GetMailStatusTxt(const struct MailHandle *mailh,unsigned char *chars)
 {
  MAIL_InternalStatusTxt(mailh->MailNode,chars);
  *(chars+4)='\0';
 }

unsigned long MAIL_TestForMail(const unsigned char *call)
 {
  unsigned long omails;
  unsigned long nmails;
  unsigned long i;
  unsigned char xcall[16];
  struct Mail *mail;
  if (MailNode==NULL) return(0);
  if (call!=NULL)
   {
    MAIL_CopyCallUpper(xcall,call,15,1);
   }
   else
   {
    MAIL_CopyCallUpper(xcall,MAIL_GetBoxCall(),15,1);
   }
  omails=0;nmails=0;
  for (i=0,mail=MailNode;i<MailBase->NumberMails;++i,++mail)
   {
    if (mail->Number==0) continue;
    if (mail->Status&(1<<MAILSTATUS_INWRITE)) continue;
    if (mail->Status&(1<<MAILSTATUS_INCOMPLETE)) continue;
    if (mail->Status&(1<<MAILSTATUS_KILLED)) continue;
    if (mail->Status&(1<<MAILSTATUS_FORWARD)) continue;
    if (!CompareString(xcall,mail->To)) continue;
    if (mail->Status&(1<<MAILSTATUS_READ)) 
     {
      ++omails;
     }
     else
     {
      ++nmails;
     }
   }
  return(nmails*65536+omails);
 }

signed long MAIL_ReadMail(struct MailHandle *mailh,unsigned char *data,unsigned long size)
 {
  if (mailh->MailMode==1) return(FALSE);
  if (mailh->FileHandle==NULL)
   {
    mailh->FileHandle=Open(mailh->FileName,MODE_OLDFILE);
    if (mailh->FileHandle==NULL) return(-1);
   }
  return(Read(mailh->FileHandle,data,size));
 }

signed long MAIL_ReadMailLine(struct MailHandle *mailh,unsigned char *data,unsigned long size)
 {
  signed long xlen,stepback,i;
  unsigned char *xptr;
  xlen=MAIL_ReadMail(mailh,data,size);
  if (xlen==-1) return(xlen);
  if (xlen==0) return(xlen);
  for (xptr=data,i=0;i<xlen;++i,++xptr)
   {
    if (*xptr==0x0d)
     {
      ++xptr;
      stepback=xlen-(xptr-data);
      if (Seek(mailh->FileHandle,-stepback,OFFSET_CURRENT)==-1) return(-1);
      return(xptr-data);
     }
   }
  return(xlen);
 }

static void MAIL_InternalGetDate(const struct Mail *mail,unsigned char *dest,
                                 unsigned long yearmode)
 {
  unsigned char *cptr;
  struct ClockData cdat;
   
  Amiga2Date((mail->Date[0]*60*24+mail->Date[1])*60,&cdat);
  cptr=dest;
  if (yearmode)
   {
    *(cptr++)=(cdat.year%100)/10+'0';
    *(cptr++)=(cdat.year%10)+'0';
   }
  *(cptr++)=(cdat.month/10)+'0';
  *(cptr++)=(cdat.month%10)+'0';
  *(cptr++)=(cdat.mday/10)+'0';
  *(cptr++)=(cdat.mday%10)+'0';
  *(cptr++)='/';
  *(cptr++)=(cdat.hour/10)+'0';
  *(cptr++)=(cdat.hour%10)+'0';
  *(cptr++)=(cdat.min/10)+'0';
  *(cptr++)=(cdat.min%10)+'0';
  *(cptr)='\0';
 }

void MAIL_GetMailDateTxt(const struct MailHandle *mailh,unsigned char *dest)
 {
  MAIL_InternalGetDate(mailh->MailNode,dest,FALSE);
 }

static struct Mail *MAIL_GetMailFromNumber(unsigned long number)
 {
  struct Mail *mail;
  unsigned long i;
  if (number==0) return(NULL);
  for (i=0,mail=MailNode;i<MailBase->NumberMails;++i,++mail)
   {
    if (mail->Number==number) return(mail);
   }
  return(NULL);
 }

signed long MAIL_KillMail(unsigned long number,const unsigned char *call)
 {
  struct Mail *mail;
  if (MailNode==NULL) return (-1);
  mail=MAIL_GetMailFromNumber(number);
  if (mail==NULL) return(-1);
   {
    struct MailHandle *tmailh;
    tmailh=(struct MailHandle *) MailHandles.lh_Head;

    while (tmailh->Node.ln_Succ!=NULL)
     {
      if (tmailh->MailNode==mail) 
       {
        return(-2);
       }
      tmailh=(struct MailHandle *) tmailh->Node.ln_Succ;
     }
   }
  if (call!=NULL)
   {
    unsigned char xcall[16];
    MAIL_CopyCallUpper(xcall,call,15,1);
   
    if ( (!CompareString(xcall,mail->From)) &&
         ( (!mail->Status&(1<<MAILSTATUS_PERSONAL)) ||
           (!CompareString(xcall,mail->To)) ) )
     {
      return(-2);
     }      
   }
  if (MAIL_InternalKillMail(mail,FALSE)) return(-3);
  return(0);
 }

void MAIL_MarkAsRead(const struct MailHandle *mailh)
 {
  mailh->MailNode->Status|=(1<<MAILSTATUS_READ);
  mailh->MailNode->ReadCounter++;
  MAIL_SaveRecord(mailh->MailNode);
 }

void MAIL_MarkAsForward(const struct MailHandle *mailh)
 {
  mailh->MailNode->Status|=(1<<MAILSTATUS_FORWARD);
  mailh->MailNode->ForwardCounter++;
  MAIL_SaveRecord(mailh->MailNode);
 }

void MAIL_MarkAsIncomp(const struct MailHandle *mailh)
 {
  if (mailh->MailMode==0) return;
  mailh->MailNode->Status|=(1<<MAILSTATUS_INCOMPLETE); 
 }

void MAIL_MarkAs7Plus(const struct MailHandle *mailh)
 {
  if (mailh->MailMode==0) return;
  mailh->MailNode->Status|=(1<<MAILSTATUS_7PLUS);
 }

void MAIL_MarkAsWantAck(const struct MailHandle *mailh)
 {
  if (mailh->MailMode==0) return;
  mailh->MailNode->Status|=(1<<MAILSTATUS_WANTACK);
 }

unsigned long MAIL_SearchMailBid(const unsigned char *bid)
 {
  struct Mail *mail;
  unsigned long i;
  
  if (MailNode==NULL) return(0);
  for (i=0,mail=MailNode;i<MailBase->NumberMails;++i,++mail)
   {
    if (mail->Number==0) continue;
    if (CompareString(bid,mail->Bid)) return(mail->Number); 
   }
  return(0); 
 }

signed long MAIL_GetMailLines(unsigned long mode,signed long lastmail,
                              const unsigned char *call,unsigned char *mailline)
 {
  struct Mail *mail;
  unsigned char internalstatus[8];
  unsigned char internaldate[16];
  unsigned char internalat[16];
  unsigned char internaltitle[32];
  signed long lastmailx;

  if (MailNode==NULL) return(0);
  if (lastmail==0)
   {
    CopyString(mailline,QSO_GetQSOText(17));
    return(-1);
   }
  if (lastmail==-1)
   {
    CopyString(mailline,QSO_GetQSOText(18));
    return(-2);
   }
  if (lastmail==-2)
   {
    lastmailx=(signed long) MAIL_SearchMail(call,mode,0); 
   }
   else
   {
    lastmailx=(signed long) MAIL_SearchMail(call,mode,(unsigned long) lastmail);
   }

  if (lastmailx==0) return(0);
 
  mail=MAIL_GetMailFromNumber(lastmailx);
  if (mail==NULL) return(0);
  
  MAIL_InternalStatusTxt(mail,internalstatus);
  internalstatus[4]='\0';
  MAIL_InternalGetDate(mail,internaldate,FALSE);
  internalat[0]='\0';
  CopyStringLimit(internaltitle,mail->Title,29);
  if (mail->At[0]!='\0')
   {
    internalat[0]='@';
    CopyString(internalat+1,mail->At);
   }

   {
    void *rawarray[8];
    
    rawarray[0]=(void *) mail->Number;
    rawarray[1]=internalstatus;
    rawarray[2]=(void *) mail->Bytes;
    rawarray[3]=mail->To;
    rawarray[4]=internalat;
    rawarray[5]=mail->From;
    rawarray[6]=internaldate;
    rawarray[7]=internaltitle;
    RawDoFmt("%5ld  %s%5ld %-6s%-7s %-6s %s %-29s\r",rawarray,PutRawDoFmt,mailline);
   }
  return(lastmailx);
 }


int MAIL_SendMailFile(unsigned long personal,unsigned long binary,
                      const unsigned char *from,const unsigned char *to,
                      const unsigned char *at,const unsigned char *title,
                      const unsigned char *filename,
                      const unsigned char *bid,
                      const unsigned char *notforward,
                      unsigned long notconvert)
 {
  struct MailHandle *mailh;
  BPTR fileh;

  struct DateStamp filedate;
  unsigned long    filesize;
  unsigned long    filecrc;
  unsigned char     *buffer;
  unsigned char     binaryhead[128];


  filecrc=0;

  /* allocate file buffer*/

  buffer=AllocVec(4096,1);
  if (buffer==NULL) return(-1); /* no memory*/

  /* prepare mail for write*/
  mailh=MAIL_SendMail(from,to,at,personal,bid);
  if (mailh==NULL)
   { /* cannot send*/
    FreeVec(buffer);
    return(-2);
   }
  MAIL_SetMailTitle(mailh,title);
  if (notforward!=NULL) MAIL_SetNotForward(mailh,notforward);

  /* open mail file */

  fileh=Open((unsigned char *) filename,MODE_OLDFILE);
  if (fileh==NULL)
   {
    MAIL_MarkAsIncomp(mailh);
    MAIL_CloseMail(mailh);
    FreeVec(buffer);
    return(-3); /* file open error*/
   }


  /* open & examine source file */

   {
    struct FileInfoBlock *myfib;
    myfib=AllocDosObject(DOS_FIB,NULL);
    if (myfib==NULL)
     {
      Close(fileh);
      MAIL_MarkAsIncomp(mailh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(-1); /* no memory */
     }


    if ((ExamineFH(fileh,myfib))==FALSE)
     {
      FreeDosObject(DOS_FIB,myfib);
      Close(fileh);
      MAIL_MarkAsIncomp(mailh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(-4); /* Read error*/
     }


    filedate=myfib->fib_Date;
    filesize=myfib->fib_Size;

    FreeDosObject(DOS_FIB,myfib);

    if (!NameFromFH(fileh,buffer,4096))
     {
      Close(fileh);
      MAIL_MarkAsIncomp(mailh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(-4); /* Read error*/
     }
   }

  if (filesize==0)
   {
    Close(fileh);
    MAIL_MarkAsIncomp(mailh);
    MAIL_CloseMail(mailh);
    FreeVec(buffer);
    return(-4);   /* Read error*/
   }

  if (binary)
   {
    /* send autobinary mail */
    unsigned long remainbytes;

    filecrc=QSO_CRCFile(filename);
    if (MAIL_WriteMail(mailh,binaryhead,UTIL_MakeBinHead
            (binaryhead,filesize,filecrc,&filedate,buffer,FALSE)))
     {
      Close(fileh);
      MAIL_MarkAsIncomp(mailh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(-5); /* Write error */
     }
    remainbytes=filesize;
    while (remainbytes>0)
     {
      unsigned long stepbytes;
      stepbytes=(remainbytes>4096)?4096:remainbytes;
      remainbytes-=stepbytes;
      if ( Read(fileh,buffer,stepbytes)!=stepbytes)
       {
        Close(fileh);
        MAIL_MarkAsIncomp(mailh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(-4); /* read error*/
       }
      if ( MAIL_WriteMail(mailh,buffer,stepbytes))
       {
        Close(fileh);
        MAIL_MarkAsIncomp(mailh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(-5); /* write error*/
       }
     }
   }
   else

   {
    /* send standard text / 7+ based mail */
    unsigned long plusstate,plusline;


    plusstate=FALSE;

    while (FGets(fileh,buffer,4096)!=NULL)
     {
      unsigned char *dptr;
      unsigned long len;

      dptr=buffer;

      /*convert LF to CR */

      while (*(dptr)!='\0')
       {
        if (*dptr=='\n') *dptr='\r';
        ++dptr;
       }

      /* test for acknowledge mail */

      if (CompareStringLimit("/ACK",buffer,4)) MAIL_MarkAsWantAck(mailh);

      /* test for 7plus line and convet non 7+ */

      plusline=UTIL_Test7PlusLine(buffer);

      if (plusline%2) plusstate=TRUE;

      if ( (!plusstate) && (!notconvert)) MAIN_ConvertToPC(buffer);

      if ( (plusline!=0) && ((plusline%2)==0) ) plusstate=FALSE;

      /* output mailline*/

      len=0;
      dptr=buffer;
      while (*(dptr++)!='\0') ++len;
      if (MAIL_WriteMail(mailh,buffer,len))
       {
        Close(fileh);
        MAIL_MarkAsIncomp(mailh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(-5); /* write error*/
       }

     }
    if (IoErr()!=0)
     {
      Close(fileh);
      MAIL_MarkAsIncomp(mailh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(-4); /* read error*/
     }

   }

  Close(fileh);
  MAIL_CloseMail(mailh);
  FreeVec(buffer);
  return(0);
 }

int MAIL_ExtractMailFile(const unsigned char *filename,unsigned long mailnr,
                         unsigned long disableconvert)
 {
  unsigned char *buffer;
  struct MailHandle *mailh;
  BPTR fileh;
  unsigned long mailstatus,mailbytes;


  buffer=AllocVec(4096,1);
  if (buffer==NULL) return(1); /* No memory*/
  mailh=MAIL_OpenMail(mailnr,NULL);
  if (mailh==NULL)
   {
    FreeVec(buffer);
    return(2);                 /* No mail */
   }
  if (mailh==((void* )1))
   {
    FreeVec(buffer);
    return(2);                 /* Mail in use*/
   }

  fileh=Open((unsigned char *)filename,MODE_NEWFILE);
  if (fileh==NULL)
   {
    MAIL_CloseMail(mailh);
    FreeVec(buffer);
    return(3);                 /* Cannot open mail */
   }


  mailbytes=MAIL_GetMailBytes(mailh);
  mailstatus=MAIL_GetMailStatus(mailh);

  if (mailstatus&(1<<MAILSTATUS_AUTOBINARY))
   {
    /* read an autobinary mail*/

    unsigned long slen;

    signed long binsize,bincrc;
    struct DateStamp bintime;
    unsigned char binpath[128];
    int binextend;

    while (1)
     {
      unsigned long xitems;
      if ((slen=MAIL_ReadMailLine(mailh,buffer,4000))==-1)
      if (slen==0)
       {
        Close(fileh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(6);             /* Autobin corrupt*/
       }
      *(buffer+slen)='\0';
      if (!CompareStringLimit("#BIN#",buffer,5)) continue;

      xitems=UTIL_ParseAutobinLine(buffer,&binsize,&bincrc,&bintime,
                                   binpath,&binextend);

      if ( xitems==0 || (binsize==0))
       {
        Close(fileh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(6);             /* Autobin corrupt*/
       }
      break;

     }
    while (binsize>0)
     {
      slen=binsize>4096?4096:binsize;

      binsize-=slen;

      if (MAIL_ReadMail(mailh,buffer,slen)!=slen)
       {
        Close(fileh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(5);             /* Read error*/
       }

      if (Write(fileh,buffer,slen)!=slen)
       {
        Close(fileh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(4);             /* Write error*/
       }
     }

    Close(fileh);
    if (bintime.ds_Days!=0)
     {
      SetFileDate((unsigned char *) filename,&bintime);
     }
    if (bincrc!=-1)
     {
      if (QSO_CRCFile(filename)!=bincrc)
       {
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(7);             /* Autobin CRC error*/
       }
     }
   }
   else

   {
    /* read a text / 7+ mail */

    unsigned long plusstate,plusline,len;


    plusstate=FALSE;

    while ((len=MAIL_ReadMailLine(mailh,buffer,4096))!=0)
     {
      unsigned char *dptr;
      unsigned long i;

      if (len==0) break;

      dptr=buffer;

      /*convert CR to LF */

      for (i=0;i<len;++i)
       {
        if (*dptr=='\r') *dptr='\n';
        ++dptr;
       }

      /* test for acknowledge mail */

      if (CompareStringLimit("/ACK",buffer,4)) MAIL_MarkAsWantAck(mailh);

      /* test for 7plus line and convet non 7+ */

      plusline=UTIL_Test7PlusLine(buffer);

      if (plusline%2) plusstate=TRUE;

      if ( (!plusstate) && (!disableconvert)) MAIN_ConvertToAmiga(buffer);

      if ( (plusline!=0) && ((plusline%2)==0) ) plusstate=FALSE;

      /* output mailline*/

      if (Write(fileh,buffer,len)!=len)
       {
        Close(fileh);
        MAIL_CloseMail(mailh);
        FreeVec(buffer);
        return(5); /* write error*/
       }

     }
    if (len!=0)
     {
      Close(fileh);
      MAIL_CloseMail(mailh);
      FreeVec(buffer);
      return(4); /* read error*/
     }


    Close(fileh);
   }
  MAIL_CloseMail(mailh);
  FreeVec(buffer);
  return(0);
 }

int MAIL_TestPrivateMail(const unsigned char *boxcall)
 {
  struct BBSObject *bbo;

  bbo=MAIL_GetCronEntry(boxcall);
  if (bbo==NULL) return(0);
  return(bbo->BBSUnion.ForwardCron.PrivOnly);
 }

int MAIL_TestForwardTime(const unsigned char *boxcall)
 {
  struct BBSObject *bbo;
  bbo=MAIL_GetCronEntry(boxcall);
  if (bbo==NULL) return(1);
  return(UTIL_TestTimeRange(
        bbo->BBSUnion.ForwardCron.StartHour,
        bbo->BBSUnion.ForwardCron.StartMinute,
        bbo->BBSUnion.ForwardCron.StopHour,
        bbo->BBSUnion.ForwardCron.StopMinute));

 }

void MAIL_ForwardBox(const unsigned char *boxcall)
 {
  struct BBSObject *bbo;
  unsigned char tcall[32];
  int callset;
  callset=-1;

  bbo=MAIL_GetCronEntry(boxcall);
  if (bbo==NULL) return;

   {
    int i;
    struct QSO *qso;
    qso=QSOs;
    for (i=1;i<=MaxChannel;++i,++qso)
     {
      if (qso->HardwareUnit!=bbo->BBSUnion.ForwardCron.TNC) continue;
      if (!CompareString
          ("BBS",Preferences.Callsets[qso->CallSet].ServerName)) continue;
      callset=qso->CallSet;
      if (qso->LinkStatus==0) continue;
      if (CompareString(qso->Call,boxcall)) return;
     }
   }

  if (callset==-1) return;
  if (bbo->BBSUnion.ForwardCron.Port==0)
   {
    CopyString(tcall,boxcall);
   }
   else
   {
    tcall[0]=0x30+bbo->BBSUnion.ForwardCron.Port;
    tcall[1]=':';
    CopyString(tcall+2,boxcall);
   }
  MAIN_EstablishLink(tcall,bbo->BBSUnion.ForwardCron.ForwardPath,
                     bbo->BBSUnion.ForwardCron.TNC,callset);
  return;
 }

void MAIL_NewMinute(void)
 {

  struct BBSObject *bbo,*bbo2;

  bbo=BBSHook;
  while (bbo!=NULL)
  {
    int inte;


    bbo2=bbo;
    bbo=bbo->next;
    if (bbo2->objecttype!=BBSObject_ForwardCron) continue;
    if (!UTIL_TestTimeRange(
          bbo2->BBSUnion.ForwardCron.StartHour,
          bbo2->BBSUnion.ForwardCron.StartMinute,
          bbo2->BBSUnion.ForwardCron.StopHour,
          bbo2->BBSUnion.ForwardCron.StopMinute)) continue;


    inte=CurrentDateStamp.ds_Minute-
          (bbo2->BBSUnion.ForwardCron.StartHour*60)-
          (bbo2->BBSUnion.ForwardCron.StartMinute);
    if (inte<0) inte+=24*60;

    if (bbo2->BBSUnion.ForwardCron.Interval==0) continue;

    if ( (inte%(bbo2->BBSUnion.ForwardCron.Interval))==0)
     {
      MAIL_ForwardBox(bbo2->BBSUnion.ForwardCron.ForwardBox);
     }

   }
  return;
 }

#else  /*DISABLE_BBS*/

#define MAIL_PRIVATE
#include "Mail.h"

void MAIL_ChangeUser(unsigned char *call,unsigned char *name,
                     unsigned char *qth,unsigned char *zipcode,
                     unsigned char *homebbs,int savedb)
 {
  return;
 }

unsigned char *MAIL_GetUserName(unsigned char *call)
 {
  return(NULL);
 }

unsigned char *MAIL_GetUserQTH(unsigned char *call)
 {
  return(NULL);
 }

unsigned char *MAIL_GetUserZIP(unsigned char *call)
 {
  return(NULL);
 }

unsigned char *MAIL_GetUserBBS(unsigned char *call)
 {
  return(NULL);
 }

unsigned char *MAIL_GetHRoute(unsigned char *bbs)
 {
  return(NULL);
 }

int MAIL_AddForwardMail(const unsigned char *box,const unsigned char *bid)
 {
  return(FALSE);
 }

int MAIL_RemoveFMail(unsigned char *box,unsigned long mnum)
 {
  return(FALSE);
 }

int MAIL_GetNextFMail(unsigned char *box,unsigned long offset)
 {
  return(FALSE);
 }

int MAIL_GetForwardBytes(unsigned char *box)
 {
  return(0);
 }

int MAIL_GetForwardMails(unsigned char *box)
 {
  return(0);
 }

unsigned long MAIL_LookLocalMail(void)
 {
  return(0);
 }

signed long MAIL_WriteMail(struct MailHandle *mailh,void *data,unsigned long length)
 {
  return(-1);
 }

void *MAIL_SendMail(const unsigned char *call,const unsigned char *tocall,
                    const unsigned char *atcall,unsigned long personal,
                    const unsigned char *bid)
 {
  return(NULL);
 }

void *MAIL_OpenMail(unsigned long mailnum,const unsigned char *opencall)
 {
  return(NULL);
 }

void MAIL_CloseMail(struct MailHandle *mailh)
 {
  return;
 }

void MAIL_SetMailTitle(struct MailHandle *mail,const unsigned char *title)
 {
  return;
 }

const unsigned char *MAIL_GetMailBid(const struct MailHandle *mailh)
 {
  return(NULL);
 }

unsigned long MAIL_SearchMail(const unsigned char *call,unsigned long mode,
                              unsigned long lastmail)
 {
  return(0);
 }

void MAIL_SetNotForward(struct MailHandle *mailh,const unsigned char *call)
 {
  return;
 }

unsigned long MAIL_GetNumberMail(const struct MailHandle *mailh)
 {
  return(0);
 }

const unsigned char *MAIL_GetMailFm(const struct MailHandle *mailh)
 {
  return(NULL);
 }

const unsigned char *MAIL_GetMailTo(const struct MailHandle *mailh)
 {
  return(NULL);
 }

const unsigned char *MAIL_GetMailAt(const struct MailHandle *mailh)
 {
  return(NULL);
 }

const unsigned char *MAIL_GetMailTitle(const struct MailHandle *mailh)
 {
  return(NULL);
 }

const unsigned char *MAIL_GetBoxCall(void)
 {
  return(NULL);
 }

const unsigned long *MAIL_GetMailDate(const struct MailHandle *mailh)
 {
  return(0);
 }

unsigned long MAIL_GetMailStatus(const struct MailHandle *mailh)
 {
  return(0);
 }

const unsigned char *MAIL_GetMailHRoute(const struct MailHandle *mailh)
 {
  return(NULL);
 }

unsigned long MAIL_GetMailBytes(const struct MailHandle *mailh)
 {
  return(0);
 }

void MAIL_GetMailStatusTxt(const struct MailHandle *mailh,unsigned char *chars)
 {
  return;
 }

unsigned long MAIL_TestForMail(const unsigned char *call)
 {
  return(0);
 }

signed long MAIL_ReadMail(struct MailHandle *mailh,unsigned char *data,unsigned long size)
 {
  return(-1);
 }

signed long MAIL_ReadMailLine(struct MailHandle *mailh,unsigned char *data,unsigned long size)
 {
  return(-1);
 }

void MAIL_GetMailDateTxt(const struct MailHandle *mailh,unsigned char *dest)
 {
  return;
 }

signed long MAIL_KillMail(unsigned long number,const unsigned char *call)
 {
  return(-1);
 }

void MAIL_MarkAsRead(const struct MailHandle *mailh)
 {
  return;
 }

void MAIL_MarkAsForward(const struct MailHandle *mailh)
 {
  return;
 }

void MAIL_MarkAsIncomp(const struct MailHandle *mailh)
 {
  return;
 }

void MAIL_MarkAs7Plus(const struct MailHandle *mailh)
 {
  return;
 }

void MAIL_MarkAsWantAck(const struct MailHandle *mailh)
 {
  return;
 }

unsigned long MAIL_SearchMailBid(const unsigned char *bid)
 {
  return(0);
 }

signed long MAIL_GetMailLines(unsigned long mode,signed long lastmail,
                              const unsigned char *call,unsigned char *mailline)
 {
  return(0);
 }

int MAIL_SendMailFile(unsigned long personal,unsigned long binary,
                      const unsigned char *from,const unsigned char *to,
                      const unsigned char *at,const unsigned char *title,
                      const unsigned char *filename,
                      const unsigned char *bid,
                      const unsigned char *notforward,
                      unsigned long notconvert)
 {
  return(-1);
 }

int MAIL_ExtractMailFile(const unsigned char *filename,unsigned long mailnr,
                         unsigned long disableconvert)
 {
  return(1);
 }


void MAIL_DoPoll(void)
 {
  return;
 }

int MAIL_Init(void)
 {
  return(TRUE);
 }

void MAIL_Cleanup(void)
 {
  return;
 }

void MAIL_DailyHousekeeping(void)
 {
  return;
 }

unsigned long MAIL_ComposeRLine(struct MailHandle *mailh,unsigned char *cbuf)
 {
  return(0);
 }

unsigned long MAIL_GetLatestMail()
 {
  return(0);
 }

int MAIL_GetForwardDest(struct MailHandle *xmail,unsigned char *xline)
 {
  return(0);
 }

void MAIL_HandleMailMacro(unsigned char *mailline,unsigned long number)
 {
  mailline[0]='\0';
  return;
 }

int MAIL_TestPrivateMail(const unsigned char *boxcall)
 {
  return(0);
 }

void MAIL_NewMinute(void)
 {
  return;
 }

void MAIL_ForwardBox(const unsigned char *boxcall)
 {
  return;
 }

int MAIL_TestForwardTime(const unsigned char *boxcall)
 {
  return(0);
 }

#endif /*DISABLE_BBS*/


