#include <CrashMail.h>

extern BOOL messageend;
extern BOOL shortread;

ImportMSG(struct Area *area)
{
   UBYTE buf[200],buf2[20];
   BPTR l,fh;
   struct StoredMsg Msg;

// LogWrite(6,DEBUG,"ImportMSG");

   if(cfg_Flags & CFG_MSGHIGHWATER)
   {
      if(area->HighWater == 0)
      {
         strcpy(buf,area->Path);
         AddPart(buf,"1.msg",200);

         if(fh=Open(buf,MODE_OLDFILE))
         {
            if(Read(fh,&Msg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg))
            {
               area->HighWater=Msg.ReplyTo;
               area->OldHighWater=Msg.ReplyTo;
            }
            Close(fh);
         }
      }
   }

   if(area->HighMsg==0)
      if(!GetHighMsg(area))
      {
         exitprg=TRUE;
         return;
      }

   area->HighMsg++;

   if(area->HighMsg == area->HighWater+1)
      area->HighWater++;

   sprintf(buf2,"%lu.msg",area->HighMsg);
   strcpy(buf,area->Path);
   AddPart(buf,buf2,200);

   l=Lock(buf,SHARED_LOCK);

   while(l || IoErr()==ERROR_OBJECT_IN_USE)
   {
      if(l) UnLock(l);

      area->HighMsg++;

      if(area->HighWater+1 == area->HighMsg)
         area->HighWater++;

      sprintf(buf2,"%lu.msg",area->HighMsg);
      strcpy(buf,area->Path);
      AddPart(buf,buf2,200);

      l=Lock(buf,SHARED_LOCK);
   }

   WriteMSG(buf,area);

   if(diskfull || nomem)
      return;

   if(!(area->Flags & AREA_BAD))
      toss_import++;
}

WriteMSG(UBYTE *file,struct Area *area)
{
   UBYTE chrstxt[50];
   UBYTE *chrs;
   ULONG c,d;
   struct jbFile *jb;
   struct StoredMsg Msg;
   struct TextChunk *chunk;

// LogWrite(6,DEBUG,"WriteMSG");

   strcpy(Msg.From,MemMessage.From);
   strcpy(Msg.To,MemMessage.To);
   strcpy(Msg.Subject,MemMessage.Subject);
   strcpy(Msg.DateTime,MemMessage.DateTime);

   Msg.TimesRead=0;
   Msg.ReplyTo=0;
   Msg.NextReply=0;
   Msg.Cost=MemMessage.Cost;
   Msg.Attr=MemMessage.Attr | SENT;

   if(MemMessage.Area[0]==0)
   {
      Msg.DestZone   =  MemMessage.DestNode.Zone;
      Msg.DestNet    =  MemMessage.DestNode.Net;
      Msg.DestNode   =  MemMessage.DestNode.Node;
      Msg.DestPoint  =  MemMessage.DestNode.Point;

      Msg.OrigZone   =  MemMessage.OrigNode.Zone;
      Msg.OrigNet    =  MemMessage.OrigNode.Net;
      Msg.OrigNode   =  MemMessage.OrigNode.Node;
      Msg.OrigPoint  =  MemMessage.OrigNode.Point;
   }
   else
   {
      Msg.DestZone   =  0;
      Msg.DestNet    =  0;
      Msg.DestNode   =  0;
      Msg.DestPoint  =  0;

      Msg.OrigZone   =  0;
      Msg.OrigNet    =  0;
      Msg.OrigNode   =  0;
      Msg.OrigPoint  =  0;
   }

// LogWrite(6,DEBUG,"MsgCheckpoint 1");

   if(!(jb=jbOpen(file,MODE_NEWFILE,5000)))
   {
      diskfull=TRUE;
      return;
   }

// LogWrite(6,DEBUG,"MsgCheckpoint 2");

   if(cfg_Flags & CFG_XLATMSG)
   {
// LogWrite(6,DEBUG,"XLATMSG");

      chrstxt[0]=0;

      for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
         for(c=0;c<chunk->Length;)
         {
            if(strncmp(&chunk->Data[c],"\x01CHRS: ",7)==0)
            {
               d=0;

               while(d<50 && chunk->Data[c+7+d]!=13 && c<chunk->Length)
               {
                  chrstxt[d]=chunk->Data[c+7+d];
                  d++;
               }
               chrstxt[d]=0;
            }
            while(chunk->Data[c]!=13 && c<chunk->Length) c++;
            if(chunk->Data[c]==13) c++;
         }

      chrs=(UBYTE *)GetCharset(chrstxt,area->DefaultCHRS);

      if(chrs != cfg_LocalCharset)
      {
         Xlat(MemMessage.From,chrs,strlen(MemMessage.From));
         Xlat(MemMessage.To,chrs,strlen(MemMessage.To));
         Xlat(MemMessage.Subject,chrs,strlen(MemMessage.Subject));

         for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
            Xlat(chunk->Data,chrs,chunk->Length);

         chrs=NULL;

         if(cfg_LocalCharset == IbmToAmiga) chrs=AmigaToIbm;
         if(cfg_LocalCharset == MacToAmiga) chrs=AmigaToMac;
         if(cfg_LocalCharset == SF7ToAmiga) chrs=AmigaToSF7;

         Xlat(MemMessage.From,chrs,strlen(MemMessage.From));
         Xlat(MemMessage.To,chrs,strlen(MemMessage.To));
         Xlat(MemMessage.Subject,chrs,strlen(MemMessage.Subject));

         for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
            Xlat(chunk->Data,chrs,chunk->Length);
      }

      jbWrite(jb,&Msg,sizeof(struct StoredMsg));

      if(MemMessage.BadReason[0]!=0)
         jbWrite(jb,MemMessage.BadReason,strlen(MemMessage.BadReason));

      for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
         for(c=0;c<chunk->Length;)
         {
            d=0;
            while(chunk->Data[c+d]!=13 && c+d<chunk->Length) d++;
            if(chunk->Data[c+d]==13) d++;

            if(strncmp(&chunk->Data[c],"\x01CHRS: ",7)==0)
            {
               jbWrite(jb,"\x01_CHRS: ",8);
               jbWrite(jb,&chunk->Data[c+7],d-7);
            }
            else
            {
               jbWrite(jb,&chunk->Data[c],d);
            }

            c+=d;
         }
   }
   else
   {
// LogWrite(6,DEBUG,"MsgCheckpoint 3");

      jbWrite(jb,&Msg,sizeof(struct StoredMsg));

      if(MemMessage.BadReason[0]!=0)
         jbWrite(jb,MemMessage.BadReason,strlen(MemMessage.BadReason));

      for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
         jbWrite(jb,chunk->Data,chunk->Length);

//   LogWrite(6,DEBUG,"MsgCheckpoint 4");
   }

// LogWrite(6,DEBUG,"MsgCheckpoint 5");

   if(cfg_Flags & CFG_IMPORTSEENBY);
      WriteNodes2D(jb,&MemMessage.SeenBy);

// LogWrite(6,DEBUG,"MsgCheckpoint 6");

   WritePath(jb,&MemMessage.Path);

// LogWrite(6,DEBUG,"MsgCheckpoint 7");

   jbPutChar(jb,0);

   jbClose(jb);

// LogWrite(6,DEBUG,"MsgCheckpoint 8");

}

GetHighMsg(struct Area *area)
{
   BPTR l;
   struct FileInfoBlock *fib;

   if(!(l=Lock(area->Path,SHARED_LOCK)))
   {
      LogWrite(2,SYSTEMINFO,"Creating directory \"%s\"",area->Path);

      if(!(l=CreateDir(area->Path)))
      {
         LogWrite(1,SYSTEMERR,"Unable to create directory");
         return(FALSE);
      }
   }

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      UnLock(l);
      nomem=TRUE;
      return(FALSE);
   }

   Examine(l,fib);

   while(ExNext(l,fib))
      if(strlen(fib->fib_FileName)>=5)
         if(stricmp(&fib->fib_FileName[strlen(fib->fib_FileName)-4],".msg")==0)
         {
            if(atol(fib->fib_FileName)>area->HighMsg)
               area->HighMsg=atol(fib->fib_FileName);

            if(atol(fib->fib_FileName)<area->LowMsg || area->LowMsg==0 || area->LowMsg==1)
            {
              if(atol(fib->fib_FileName)>=2) area->LowMsg=atol(fib->fib_FileName);
            }
         }

   if(area->HighMsg==0)
      area->HighMsg=1;

   if(area->LowMsg==0 || area->LowMsg==1)
      area->LowMsg=2;

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));
   return(TRUE);
}

RescanMSG(struct Area *area,ULONG max)
{
   ULONG start,rescan;

   if(area->HighMsg==0)
      if(!GetHighMsg(area))
         return(0);

   start=area->LowMsg;

   if(max !=0 && area->HighMsg-start+1 > max)
      start=area->HighMsg-max+1;

   rescan=0;

   while(start <= area->HighMsg)
   {
      isrescanning=TRUE;

      if(ExportMSGNum(area,start));
         rescan++;

      isrescanning=FALSE;

      if((SetSignal(0L,0L) & SIGBREAKF_CTRL_C) || nomem || exitprg)
         return(rescan);

      start++;
   }
   return(rescan);
}

ExportAreaMSG(struct Area *area)
{
   ULONG start;
   UBYTE buf[200];
   BPTR fh;
   struct StoredMsg Msg;

   Printf("Scanning area %s\n",(long)area->Tagname);

   if(area->HighMsg==0)
      if(!GetHighMsg(area))
         return;

   if(cfg_Flags & CFG_MSGHIGHWATER)
   {
      if(area->HighWater == 0)
      {
         strcpy(buf,area->Path);
         AddPart(buf,"1.msg",200);

         if(fh=Open(buf,MODE_OLDFILE))
         {
            if(Read(fh,&Msg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg))
            {
               area->HighWater=Msg.ReplyTo;
               area->OldHighWater=Msg.ReplyTo;
            }
            Close(fh);
         }

         if(area->HighWater == 0)
         {
            area->HighWater=1;
            area->OldHighWater=1;
         }
      }
      start=area->HighWater+1;
   }
   else
   {
      start=area->LowMsg;
   }

   if(start<area->LowMsg)
      start=area->LowMsg;

   while(start <= area->HighMsg)
   {
      ExportMSGNum(area,start);
      start++;

      if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
         return;
   }

   area->HighWater=start-1;
}

ExportMSGNum(struct Area *area,ULONG num)
{
   ULONG rlen;
   UBYTE buf[200],buf2[200],charset[30];
   BOOL export,kludgeadd;
   BPTR fh;
   APTR chrs;
   struct jbFile *jb;
   struct StoredMsg Msg;
   struct TextChunk *chunk;

   charset[0]=0;

   strcpy(buf,area->Path);
   sprintf(buf2,"%lu.msg",num);
   AddPart(buf,buf2,200);

   if(jb=jbOpen(buf,MODE_OLDFILE,2000))
   {
      export=FALSE;

      if(jbRead(jb,&Msg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg))
         if(!(Msg.Attr & SENT) || isrescanning)
         {
            export=TRUE;

            MemMessage.OrigNode.Zone=0;
            MemMessage.OrigNode.Point=0;
            MemMessage.DestNode.Zone=0;
            MemMessage.DestNode.Point=0;

            MemMessage.OrigNode.Net=Msg.OrigNet;
            MemMessage.OrigNode.Node=Msg.OrigNode;
            MemMessage.DestNode.Net=Msg.DestNet;
            MemMessage.DestNode.Node=Msg.DestNode;

            if(area->Flags & AREA_NETMAIL)
               strcpy(MemMessage.Area,"");

            else
               strcpy(MemMessage.Area,area->Tagname);


            mystrncpy(MemMessage.To,Msg.To,36);
            mystrncpy(MemMessage.From,Msg.From,36);
            mystrncpy(MemMessage.Subject,Msg.Subject,72);

            mystrncpy(MemMessage.DateTime,Msg.DateTime,20);

            MemMessage.Attr = Msg.Attr & (PVT|CRASH|FILEATTACH|FILEREQ|RREQ|IRRR|AUDIT|HOLD);
            MemMessage.Cost = Msg.Cost;
            MemMessage.Rescanned = FALSE;
            MemMessage.BadReason[0]=0;

            ((struct TextChunk *)MemMessage.TextChunks.First)->Next=NULL;
            ((struct TextChunk *)MemMessage.TextChunks.First)->Length=0;
            ((struct Nodes2D *)MemMessage.SeenBy.First)->Nodes=0;
            ((struct Nodes2D *)MemMessage.SeenBy.First)->Next=NULL;
            ((struct Path *)MemMessage.Path.First)->Paths=0;
            ((struct Path *)MemMessage.Path.First)->Next=NULL;

            kludgeadd=FALSE;
            messageend=FALSE;
            shortread=FALSE;

            rlen=ReadCR(buf,199,jb);

            while(!messageend && !shortread)
            {
               if(buf[0]==1 && rlen!=0)
               {
                  ProcessKludge(buf,rlen);
               }
               else if(kludgeadd==FALSE && rlen!=0 && buf[0]!=10)
               {
                  kludgeadd=TRUE;

                  if(cfg_Flags & CFG_XLATMSG)
                  {
                     if(area->ExportCHRS!=(UBYTE *)CHARSET_ASCII)
                     {
                        if(area->ExportCHRS==NULL)
                           strcpy(buf2,"\x01CHRS: LATIN-1 2\x0d");

                        if(area->ExportCHRS==AmigaToMac)
                           strcpy(buf2,"\x01CHRS: MAC 2\x0d");

                        if(area->ExportCHRS==AmigaToIbm)
                           strcpy(buf2,"\x01CHRS: IBMPC 2\x0d");

                        if(area->ExportCHRS==AmigaToSF7)
                           strcpy(buf2,"\x01CHRS: SWEDISH 1\x0d");

                        AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                     }
                  }

                  if((cfg_Flags & CFG_ADDTID) && !isrescanning)
                  {
                     if(Checksum11() != checksums[11])
                        strcpy(buf2,"\x01TID: CrashMail "TID_VERSION" Unreg\x0d");

                     else
                        sprintf(buf2,"\x01TID: CrashMail "TID_VERSION" %lu\x0d",key.Serial);

                     AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                  }

                  if(isrescanning)
                  {
                     sprintf(buf2,"\x01RESCANNED %lu:%lu/%lu.%lu\x0d",area->Aka->Node.Zone,
                                                                      area->Aka->Node.Net,
                                                                      area->Aka->Node.Node,
                                                                      area->Aka->Node.Point);
                     AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                  }

                  if(MemMessage.Area[0]==0)
                  {
                     if(Msg.DestPoint!=0 && MemMessage.DestNode.Point == 0)
                     {
                        sprintf(buf2,"\x01TOPT %lu\x0d",Msg.DestPoint);
                        AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                        MemMessage.DestNode.Point=Msg.DestPoint;
                     }
                     if(Msg.OrigPoint!=0 && MemMessage.OrigNode.Point == 0)
                     {
                        sprintf(buf2,"\x01FMPT %lu\x0d",Msg.OrigPoint);
                        AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                        MemMessage.OrigNode.Point=Msg.OrigPoint;
                     }
                     if((Msg.OrigZone!=0 && MemMessage.OrigNode.Zone == 0) ||
                        (Msg.DestZone!=0 && MemMessage.DestNode.Zone == 0))
                     {
                        sprintf(buf2,"\x01INTL %lu:%lu/%lu %lu:%lu/%lu\x0d",Msg.DestZone,Msg.DestNet,Msg.DestNode,
                                                                            Msg.OrigZone,Msg.OrigNet,Msg.OrigNode);

                        AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));

                        MemMessage.OrigNode.Zone=Msg.OrigZone;
                        MemMessage.DestNode.Zone=Msg.DestZone;
                     }

                     if(MemMessage.DestNode.Zone == 0 || MemMessage.OrigNode.Zone == 0)
                     {
                        MemMessage.DestNode.Zone=area->Aka->Node.Zone;
                        MemMessage.OrigNode.Zone=area->Aka->Node.Zone;
                        Msg.DestZone=area->Aka->Node.Zone;
                        Msg.OrigZone=area->Aka->Node.Zone;

                        if(cfg_Flags & CFG_FORCEINTL)
                        {
                           sprintf(buf2,"\x01INTL %lu:%lu/%lu %lu:%lu/%lu\x0d",Msg.DestZone,Msg.DestNet,Msg.DestNode,
                                                                               Msg.OrigZone,Msg.OrigNet,Msg.OrigNode);

                           AddChunkList(&MemMessage.TextChunks,buf2,strlen(buf2));
                        }
                     }
                  }
               }

               if(rlen > 8 && MemMessage.Area[0] && strncmp(buf,"SEEN-BY:",8)==0)
                  AddSeenby(&buf[8],&MemMessage.SeenBy);

               else if(rlen > 6 && MemMessage.Area[0] && strncmp(buf,"\x01PATH:",6)==0)
                  AddPath(&buf[7],&MemMessage.Path);

               else if(rlen > 6 && MemMessage.Area[0] && strncmp(buf,"\x01CHRS:",6)==0 && (cfg_Flags & CFG_XLATMSG))
               {
                  strncpy(charset,&buf[7],30);
                  charset[29]=0;
               }

               else if(rlen > 8 && MemMessage.Area[0] && strncmp(buf,"\x01CHARSET:",9)==0 && (cfg_Flags & CFG_XLATMSG))
               {
                  strncpy(charset,&buf[10],30);
                  charset[29]=0;
               }

               else
               {
                  AddChunkList(&MemMessage.TextChunks,buf,rlen);
               }

               if(shortread || messageend)
                  break;

               rlen=ReadCR(buf,199,jb);
            }

            if(!isrescanning)
            {
               if(MemMessage.Area[0]==0)
               {
                  LogWrite(4,TOSSINGINFO,"Exporting message #%lu from \"%s\" to \"%s\" at %lu:%lu/%lu.%lu",num,MemMessage.From,MemMessage.To,
                                                                                                   MemMessage.DestNode.Zone,
                                                                                                   MemMessage.DestNode.Net,
                                                                                                   MemMessage.DestNode.Node,
                                                                                                   MemMessage.DestNode.Point);
               }
               else
               {
                  LogWrite(4,TOSSINGINFO,"Exporting message #%lu from \"%s\" to \"%s\" in %s",num,MemMessage.From,MemMessage.To,area->Tagname);
               }
            }

            if(cfg_Flags & CFG_XLATMSG)
            {
               chrs=(UBYTE *)GetCharset(charset,(UBYTE *)cfg_LocalCharset);

               if(chrs == IbmToAmiga) chrs=AmigaToIbm;
               if(chrs == MacToAmiga) chrs=AmigaToMac;
               if(chrs == SF7ToAmiga) chrs=AmigaToSF7;

               if(area->ExportCHRS != chrs && area->ExportCHRS!=(UBYTE *)CHARSET_ASCII)
               {
                  Xlat(MemMessage.To,chrs,strlen(MemMessage.To));
                  Xlat(MemMessage.From,chrs,strlen(MemMessage.From));
                  Xlat(MemMessage.Subject,chrs,strlen(MemMessage.Subject));

                  for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
                     Xlat(chunk->Data,chrs,chunk->Length);

                  Xlat(MemMessage.To,area->ExportCHRS,strlen(MemMessage.To));
                  Xlat(MemMessage.From,area->ExportCHRS,strlen(MemMessage.From));
                  Xlat(MemMessage.Subject,area->ExportCHRS,strlen(MemMessage.Subject));

                  for(chunk=MemMessage.TextChunks.First;chunk;chunk=chunk->Next)
                     Xlat(chunk->Data,area->ExportCHRS,chunk->Length);
               }
            }

            HandleMessage();

            if(!isrescanning)
               scan_num++;

            Msg.Attr|=SENT;
         }

      jbClose(jb);

      strcpy(buf,area->Path);
      sprintf(buf2,"%lu.msg",num);
      AddPart(buf,buf2,200);

      if(export)
      {
         if(!isrescanning)
         {
            if(cfg_Flags & CFG_MSGWRITEBACK)
            {
               MemMessage.Attr=Msg.Attr;
               WriteMSG(buf,area);
            }
            else
            {
               if(fh=Open(buf,MODE_READWRITE))
               {
                  Write(fh,&Msg,sizeof(struct StoredMsg));
                  Close(fh);
               }
            }
         }
      }
      CleanMemMessage();

      return(TRUE);
   }
   return(FALSE);
}

WriteHighWater(struct Area *area)
{
   BPTR fh;
   UBYTE buf[200];
   struct StoredMsg Msg;
   struct DateStamp ds;

   if(area->HighWater > 65535)
   {
      LogWrite(1,TOSSINGERR,"Warning: Highwater mark in %s exceeds 65535, cannot store in 1.msg",
         area->Tagname);

      return;
   }
   
   strcpy(Msg.From,"CrashMail");
   strcpy(Msg.To,"All");
   strcpy(Msg.Subject,"HighWater mark");

   DateStamp(&ds);
   MakeFidoDate(&ds,Msg.DateTime);

   Msg.TimesRead=0;
   Msg.DestNode=0;
   Msg.OrigNode=0;
   Msg.Cost=0;
   Msg.OrigNet=0;
   Msg.DestNet=0;
   Msg.DestZone=0;
   Msg.OrigZone=0;
   Msg.OrigPoint=0;
   Msg.DestPoint=0;
   Msg.ReplyTo=area->HighWater;
   Msg.Attr=SENT | PVT;
   Msg.NextReply=0;

   strcpy(buf,area->Path);
   AddPart(buf,"1.msg",200);

   if(fh=Open(buf,MODE_NEWFILE))
   {
      Write(fh,&Msg,sizeof(struct StoredMsg));
      Write(fh,"",1);
      Close(fh);
   }
}
