#include "zmiglobals.h"
#include "ivn.h"

#include <link/io.h>

#define UP TRUE
#define DOWN FALSE

#define OLD 0  /* this picks between the library and the old RAM method */

#define NEWROSSAREAS 1 // this define causes the areas from the main program to be used
// instead of reading them in

/* Globals */


struct GConfig *GCFG;

BOOL DLGMailV2=FALSE;

BPTR nilfh=0;

BOOL GOTNETMAIL=FALSE;
BOOL GOTECHOMAIL=FALSE;
BOOL GOTTIC=FALSE;

struct NameStruct *UserMem = NULL;
int TotalUsers=0;

int  BORROWED_AREA=0;
long TotalAreas;
long MSGSIMPORTED=0;

char localareaname[50];
char CurrentARCmail[50];
char ARCpat[7][13];
char logstring[2000];

struct FileInfoBlock *FIB = NULL;
struct areas *a;

BPTR DirectoryLock;

struct Msg_Area *AllAreas = NULL;
UBYTE *SacredPointer;

struct Library *DLGBase = NULL;
BPTR sout = NULL;

long __stack = 100000L;

/* Globals from ztime.c */

struct tm *tp;

char timenow[30];

long tt;

/// AddressToZone
int AddressToZone(char *input)
{
   char zone[10], net[10], node[10], point[10];
   
   strsfn(input,zone,net,node,point);

   /**/  return(atoi(zone));
}
//-

/// AddressToNet
int AddressToNet(char *input) 
{
   char zone[10], net[10], node[10], point[10];
   
   strsfn(input,zone,net,node,point);

   /**/  return(atoi(net));
}
//-

/// AddressToNode
int AddressToNode(char *input)
{
   char zone[10], net[10], node[10], point[10];
   
   strsfn(input,zone,net,node,point);

   /**/  return(atoi(node));
}
//-

/// AddressToPoint
int AddressToPoint(char *input)
{
   char zone[10], net[10], node[10], point[10];
   
   strsfn(input,zone,net,node,point);

   /**/  return(atoi(point));
}
//-

/**********************************/

void QuietExit();

/// Main
int main(int argc, char **argv)
{
   char how[100];

   /*struct areas *tmp;*/

   sout = Output();

   DLGBase = OpenLibrary("dlg.library",2L);
   
   if(DLGBase==NULL)
   {
      AFPrintf(NULL,sout,"No DLG.library - Exiting\n");
      exit(20);
   }

   AFPrintf(NULL,sout,"%s\n",ID_STRING);

   strcpy(how,"");

   if(argc!=2) exit(20);

   GCFG=NULL;

   ASPrintf(NULL,logstring,"*--- %s",ID_STRING);
   Log(logstring);

   DLGMailV2=FALSE;

/// Global Config
   if(!Stricmp(argv[1],"NEW"))
   {
      FILE *fp;

      DLGMailV2=TRUE;
      /* get GCFG from elsewhere */
      fp=fopen("ENV:GCFG","r");

      if(fp)
      {
         fgets(how,16,fp);
         GCFG=(struct GConfig *)atoi(how);
         fclose(fp);
      }
   }
   else
   {
      GCFG=(struct GConfig *)atoi(argv[1]);
   }

   if(GCFG==NULL)
   {
      AFPrintf(NULL,sout,"No GCFG - Exiting\n");
      Log("! No global configuration");
      exit(20);
   }

   if((GCFG->MARKER1 != 5551212) || (GCFG->MARKER2 != 5551212))
   {
      AFPrintf(NULL,sout,"GCFG Marker Failure - Exiting\n");
      Log("! Configuration version failure");
      exit(20);
   }
//-

/// Set up dupe table
   the_dup_table=(void *)calloc(TABLELENGTH+10,4);

   if(!the_dup_table)
   {
      Log("! No mem for dup table");
      AFPrintf(NULL,sout,"no mem for dup table\n");
      exit(20);
   }

   strcpy(last_dup_table,"");
   last_dup_table_written=FALSE;
//-

   _RETURNCODE=0;

   SetZTaskPri();

   totREMEMBEREXP=0;

/// Set up FIB
   FIB = AllocDosObject(DOS_FIB,NULL);

   if(!FIB)
   {
      AFPrintf(NULL,sout,"Can't allocate space for the FIB\n");
      _RETURNCODE=ACT_QUIT;
      exit(20);
   }
//-

   LoadUserMem();

   a=_ROSSAREAS;

   if(_PCFRIENDLY)
      Log(". Using Planet Connect-friendly method of throwing away messages in unconfigured echo message areas");

   if(LoadDialogArea())
   {
      EnterAreaLoop();

      NormalProcess();
   }

   QuietExit();
}
//-

/// NormalProcess
int NormalProcess()
{
   /* this function tosses pkts, then undoes ARCmail, tosses the pkts-|
                                          ^                           |
                                          *---------------------------|  */
   int i;

   if(_VERBOSITY>1)
      Log("-> Begin Normal Tossing");

   while(1)
   {
      if(CheckDLGMAILSTOP())
         break;

      while(1)
      {
         if(CheckDLGMAILSTOP())
            break;

         i=TossPackets();
         if(i==0) break;
      }

      i=UnBundle();
      if(i==0) break;
   }
   
   FastCloseAll();
   FileToPKT(0);
   exportreport();

   if(_VERBOSITY>1) Log("<- End Normal Tossing");

   return(0);
}
//-

/// Extract
int Extract(char *what,char *where,char *resultname)
{
   int rc;
   char currentpath[255];
   char string[100];
   BPTR archivename;
   UBYTE filescan[11];
   int error;

   error=getcd(0,currentpath);
   if(error != 0) return(0);

   archivename=Open(what,MODE_OLDFILE);      

   if(!archivename)
   {
      ASPrintf(NULL,logstring,"! ERROR: Can't open %s to determine archive type",what);
      Log(logstring);

      AFPrintf(NULL,sout,"%% Can't open %s to determine archive type\n",what);
      return(0);
   }

   Read(archivename,filescan,10);
   Close(archivename);

   strcpy(string,"");

   strcpy(resultname,"TMP_BUNDLE.XXX");

   if(filescan[0]==0x1a)
   {
      strcpy(resultname,"TMP_BUNDLE.ARC");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.ARC");
      ASPrintf(NULL,string,_ARCEXTRACT,"TMP_BUNDLE.ARC");
   }

   if(filescan[0]=='Z')
   {
      strcpy(resultname,"TMP_BUNDLE.ZOO");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.ZOO");
      ASPrintf(NULL,string,_ZOOEXTRACT,"TMP_BUNDLE.ZOO");
   }

   if(filescan[0]=='P')
   {
      strcpy(resultname,"TMP_BUNDLE.ZIP");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.ZIP");
      ASPrintf(NULL,string,_ZIPEXTRACT,"TMP_BUNDLE.ZIP");
   }

   /* modify for lha */

   if(filescan[3]=='l' && filescan[4]=='h' && filescan[5]=='5')
   {
      strcpy(resultname,"TMP_BUNDLE.LHA");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.LHA");
      ASPrintf(NULL,string,_LHAEXTRACT,"TMP_BUNDLE.LHA");
   }

   /* modify for lzh */

   if(filescan[3]=='l' && filescan[4]=='h' && filescan[5]!='5')
   {
      strcpy(resultname,"TMP_BUNDLE.LZH");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.LZH");
      ASPrintf(NULL,string,_LZHEXTRACT,"TMP_BUNDLE.LZH");
   }

   /* modify for arj */

   if(filescan[0]==0x60 && filescan[1]==0xea)
   {
      strcpy(resultname,"TMP_BUNDLE.ARJ");
      SmartRename("TMP_BUNDLE.XXX","TMP_BUNDLE.ARJ");
      ASPrintf(NULL,string,_ARJEXTRACT,"TMP_BUNDLE.ARJ");
   }

   if(strlen(string)<5)
   {
      Log("! Error: Can't determine type of archiver used");
      AFPrintf(NULL,sout,"Can't determine type of archive\n");
      return(0);
   }

   if(_VERBOSITY)
   {
      ASPrintf(NULL,logstring,". Extracting: %s",string);
      Log(logstring);
   }

   AFPrintf(NULL,sout,"\n[32mExtracting... %s[0m\n",string);
   rc=Spawn(Input(),sout,string);

   return(rc);
}
//-

/// IncrementalRename
int IncrementalRename(char *old, char *new)
{
   int i;

   char buffer[100];

   for(i=0;i<1000;i++)
   {
      ASPrintf(NULL,buffer,"%s%03d",new,i);

      if(0 == SmartRename(old,buffer))
         break;
   }
   return(1);
}
//-

/// LoadDialogArea
int LoadDialogArea()
{
   BPTR area = NULL;

   ULONG i;
   ULONG IndexSize = 0;

/// Size up area.bbs. If -1 returned, file not found
   if(FileSize("Msg:Area.BBS",&IndexSize) == -1)
   {
      Log("! Error: Can't find MSG:Area.BBS");
      AFPrintf(NULL,sout,"Can't find MSG:AREA.BBS file!\n");
      TotalAreas=0;
      return(0);
   }
//-

/// If no areas, get outta here
   if(IndexSize == 0)
   {
      Log("! Error: Can't read MSG:Area.BBS");
      AFPrintf(NULL,sout,"Can't read in MSG:AREA.BBS file!\n");
      TotalAreas=0;
      return(0);
   }
//-

/// allocate memory to hold area.bbs
   AllAreas = calloc(1,IndexSize);

   if(AllAreas == NULL)
   {
      AFPrintf(NULL,sout,"Can't allocate space for MSG:area.bbs file\n");
      Close(area);
      return(0);
   }
//-

/// Open and load area.bbs
   area=Open("MSG:AREA.BBS",MODE_OLDFILE);

   if(area != NULL)
   {
      i=Read(area,AllAreas,IndexSize);
      Close(area);

///   sanity check; did we read in everything?
      if(i != IndexSize)
      {
         ASPrintf(NULL,logstring,"! Error reading in file areas!");
         Log(logstring);
         AFPrintf(NULL,sout,"! Error reading in file areas!");
         TotalAreas=0;
         return(0);
      }
//-

      TotalAreas = IndexSize/sizeof(struct Msg_Area);

      if(_VERBOSITY)
      {
         ASPrintf(NULL,logstring,". Read in MSG:AREA.BBS, total of %d areas present",TotalAreas);
         Log(logstring);
      }

      return(TotalAreas);
   }
   else
   {
      Log("! Error: Can't read MSG:Area.BBS");
      AFPrintf(NULL,sout,"Can't read in MSG:AREA.BBS file!\n");
      TotalAreas=0;
      return(0);
   }
//-

}
//-

/// LogEvent
int LogEvent(char *to, char *from, char *fidoname,int msgnum,int areanumber,char *subject)
{
   /* localareaname contains where the message was tossed to */   

   char junque[100];

   char bcjunque[250];

   /* for informing users of pending echomail */

//   char eventlogstring[250];

   if(!Stricmp(fidoname,"BAD_MSGS")) return(1);
   if(strlen(to)==0) return(0);

   if(0==SearchUsers(to))
   {
      return(1);
   }

   if(Stricmp(fidoname,"Private Directory Netmail") && _NOTIFYACTIVEONLY==1)
   {
      /* check to see if user is active in this area before notifying */

      if(0 == InUserMsgFile(areanumber,to))
      {
         return(0);
      }
   }

   ASPrintf(NULL,junque,"%d",areanumber);

   if(!Stricmp(fidoname,"Private Directory Netmail"))
   {
      ASPrintf(NULL,junque,"Pvt Netmail");
      ASPrintf(NULL,bcjunque,"Rec'd Msg [%d] From [%s] In Area [%s]",msgnum,from,junque);
      Inform(to,bcjunque,NULL,NULL);

      if(_VERBOSITY>1)
      {
         ASPrintf(NULL,logstring,"* Event logging message to user %s, area %s",to,junque);
         Log(logstring);
      }
   }
//   if(Stricmp(fidoname,"Private Directory Netmail"))
//   {
//      ASPrintf(NULL,eventlogstring,"Received Netmail Message From [%s]\n",from);
//      WriteEvent(to,eventlogstring);
//   }
   else
   {
      if(MyDEBUG)
      {
         AFPrintf(NULL,sout,"calling WaitingMail(%s,%s,%s,%d,%s,%d,NULL)\n",to,from,subject,areanumber,localareaname,msgnum);
         Delay(100);
      }

      WaitingMail(to,from,subject,areanumber,localareaname,msgnum,NULL);
   }
   return(0);
}
//-

/// InUserMsgFile
int InUserMsgFile(long areanumber, char *name)
{
   int rc=1;
   char path[50];
   BPTR fh;
   struct Msg_Log *ml;
   int i;

   ml=(void *)calloc(sizeof(struct Msg_Log),1);

   if(ml)
   {
      ASPrintf(NULL,path,"MSG:%d/User.MSG",areanumber);

      fh=Open(path,MODE_OLDFILE);

      if(fh)
      {
         while(1)
         {
            i=Read(fh,(void *)ml,sizeof(struct Msg_Log));

            if(i!=sizeof(struct Msg_Log))
            {
               rc=0;
               break;
            }

            if(!Stricmp((void *)ml,name)) break; /* found the name */
         }
         Close(fh);
      }

      free((void *)ml);
   }
   return(rc);
}
//-

/// QuietExit
void QuietExit(void)
{
   if(_LINKREPLIES) EXPtoLink();

   WriteEXP();
   NotateTosses();

   LeaveAreaLoop();

   if(last_dup_table_written==FALSE && *last_dup_table)
   {
      write_dup_table(last_dup_table,the_dup_table,TRUE);
   }

   if(the_dup_table) free(the_dup_table);

   if(FIB)
      FreeDosObject(DOS_FIB,FIB); /* free(FIB);*/

   if(AllAreas) free(AllAreas);
   if(UserMem) free(UserMem);

   ASPrintf(NULL,logstring,". IMPORT SUMMARY: %d Messages in %d configured areas",MSGSIMPORTED,totREMEMBEREXP);
   Log(logstring);

   if(_PCFRIENDLY)
   {
      ASPrintf(NULL,logstring,". %d Messages in unconfigured areas sent to the bit bucket",NULLMSGS);
      Log(logstring);
   }

   Log("*-- DLGImp Exit\n");

   AFPrintf(NULL,sout,"DLGImp processing completed...\n");

   if(_RETURNCODE != ACT_QUIT)
   {
      _RETURNCODE=0;
      

      if(!DLGMailV2)
      {
         if(GOTNETMAIL) _RETURNCODE |= 4;
         if(GOTECHOMAIL) _RETURNCODE |= 8;
         if(GOTTIC && _ENABLE_TICK) _RETURNCODE |= 128;
      }
      else  /* new DLGMAIL v2 stuff */
      {
         if(GOTNETMAIL) _RETURNCODE |= ACT_DLGNET;
         if(GOTECHOMAIL) _RETURNCODE |= ACT_DLGEXP;
      }
   }
   exit(0);
}
//-

/// MyBorrowArea
int MyBorrowArea(long number)
{
   int rc;

   if((number == 0) || (_BORROW == NULL) ) return(0);

   rc=NewMyBorrowArea(number);

   return(rc);
}
//-

/// UnBorrowArea
int UnBorrowArea(long number)
{
   int rc;

   if(number==0 || _BORROW==NULL) return(0);

   rc=NewUnBorrowArea(number);

   return(rc);
}
//-

/// NewMyBorrowArea
int NewMyBorrowArea(long areanum)
{
   int j;
   
   j=BorrowArea(areanum,"DLGImp","Importing",(short)64,(short)MSGLOCK);
   return(j);
}
//-

/// NewUnBorrowArea
int NewUnBorrowArea(long areanum)
{
   int j;

   j=FreeArea(areanum,"DLGImp",(short)MSGLOCK);
   return(j);
}
//-

/// EnterAreaLoop
int EnterAreaLoop()
{
   char drive[FMSIZE];
   char pth[FMSIZE];
   char fname[FMSIZE];
   char ext[FMSIZE];

   char xMSGAREAPATH[50];
   int xMSGAREANUMBER;

   long areacounter;

   struct area *thisarea;

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

   for(areacounter=1;;areacounter++)
   {

      thisarea=get_area(a,areacounter);

      if(thisarea==NULL)
      {
         break;   // we've run out of areas
      }

      strcpy(xMSGAREAPATH,thisarea->path);

      /* figure out what the DLG area number is */

      xMSGAREANUMBER=0;

      strsfn(xMSGAREAPATH,drive,pth,fname,ext);

      xMSGAREANUMBER=atoi(pth);

      if((thisarea->passthru == 0) && (xMSGAREANUMBER != 0))
      {
         EnterArea(xMSGAREANUMBER,MSGLOCK);
      }
   }

   return(0);
}
//-

/// LeaveAreaLoop
int LeaveAreaLoop()
{
   char drive[FMSIZE];
   char pth[FMSIZE];
   char fname[FMSIZE];
   char ext[FMSIZE];

   char xMSGAREAPATH[50];
   int xMSGAREANUMBER;

   long areacounter;

   struct area *thisarea;

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

   for(areacounter=1;;areacounter++)
   {
      thisarea=get_area(a,areacounter);

      if(thisarea==NULL)
      {
         break;   // we've run out of areas
      }

      strcpy(xMSGAREAPATH,thisarea->path);

      /* figure out what the DLG area number is */

      xMSGAREANUMBER=0;

      strsfn(xMSGAREAPATH,drive,pth,fname,ext);

      xMSGAREANUMBER=atoi(pth);

      if((thisarea->passthru == 0) && (xMSGAREANUMBER != 0))
      {
         LeaveArea(xMSGAREANUMBER,MSGLOCK);
      }
   }

   return(0);
}
//-

/// LoadUserMem
int LoadUserMem()
{
   BPTR fh = NULL;
   int i;
   ULONG size;

   if(-1 == FileSize("DLGConfig:Misc/Users.BBS",&size))
   {
      TotalUsers = 0;
      return(0);
   }

   UserMem = calloc(1,size);

   if(UserMem == NULL)
   {
      TotalUsers = 0;
      return(0);
   }

   fh = Open("DLGConfig:Misc/USERS.BBS",MODE_OLDFILE);

   if(!fh)
   {
      TotalUsers = 0;
      return(0);
   }

   TotalUsers = size/sizeof(struct NameStruct);

   i=Read(fh,UserMem,size);
   Close(fh);

   if(i!=size)
   {
      AFPrintf(NULL,sout,"problem reading in file Users.BBS\n");
      Log("! Problem reading in file Users.BBS\n");
      TotalUsers=0;
      return(0);
   }

   return(1);
}
//-

/// SearchUsers
int SearchUsers(char *searchfor)
{
   int i;

   for(i = 0; i < TotalUsers; i++)
   {
      if(!Stricmp(UserMem[i].name,searchfor)) return(1);
   }

   return(0);
}
//-

/// SetZTaskPri
int SetZTaskPri(void)
{
   struct Task *MyTask;

   MyTask=(struct Task *)FindTask(NULL);

   if(_ZTASKPRI)
   {
      SetTaskPri(MyTask,_ZTASKPRI);
   }

   return(0);
}
//-

/// UnBundle

/*   This function returns a NULL if no ARCmail exists, a negative
      number if any failure occurs, or a positive number if
      the unarchiving was successful. For doing an unbundle of
      all ARCmail, this routine should be called until it returns
      a NULL. */

int UnBundle(void) 
{
   char tempstring[100];
   int i;
   char resultstring[100];

   if(_VERBOSITY) Log("-> Begin UnBundle()");

   i=FindOldestBundle(CurrentARCmail);

   if(i==0)
   {
      if(_VERBOSITY) Log("<- No more bundles.");
      return(0);
   }

   if(MyDEBUG>1) AFPrintf(NULL,sout,"[32mFound[0m %s\n",CurrentARCmail);

   DeleteFile("INBOUND:TMP_BUNDLE.XXX");
   strcpy(tempstring,"INBOUND:");
   strcat(tempstring,CurrentARCmail);

   if(0 == SmartRename(tempstring,"INBOUND:TMP_BUNDLE.XXX"))
   {
      if(0 == Extract("INBOUND:TMP_BUNDLE.XXX","INBOUND:",resultstring))
      {
         DeleteFile("INBOUND:TMP_BUNDLE.ARC");
         DeleteFile("INBOUND:TMP_BUNDLE.ZOO");
         DeleteFile("INBOUND:TMP_BUNDLE.ZIP");
         DeleteFile("INBOUND:TMP_BUNDLE.LZH");
         DeleteFile("INBOUND:TMP_BUNDLE.LHA");
         DeleteFile("INBOUND:TMP_BUNDLE.ARJ");
         DeleteFile("INBOUND:TMP_BUNDLE.UNK");

         SmartRename("INBOUND:TMP_BUNDLE.XXX","INBOUND:TMP_BUNDLE.UNK");
         if(_VERBOSITY) Log("<- Done unbundling");
         return(1); /* <---- fix this to return appropriate value */
      }
      else
      {
         Log("! Couldn't unarchive TMP_BUNDLE.XXX - renaming to BAD_BUNDLE");
         AFPrintf(NULL,sout,"[33mCouldn't extract from TMP_BUNDLE.XXX[0m\n");
         IncrementalRename(resultstring,"BAD_BUNDLE.");
         return(-97);
      }
   }
   else
   {
      Log("! Couldn't rename to TMP_BUNDLE.XXX");
      AFPrintf(NULL,sout,"[33m----> Can't rename %s to INBOUND:TMP_BUNDLE.XXX\n",tempstring);
      return(-98);
   }
}
//-

/// LogImported
int LogImported(int imported,int exported,int totnodes,char *path,char *tagname)
{
   BPTR fh;
   struct EchoLog *el;
   int i,magic;
   char file[50];
   UBYTE clock[10],date,month;
   UWORD year;

   getclk(clock);

   year =clock[1]+1980;
   month=clock[2];
   date =clock[3];

   magic=month*32+date;
   
   ASPrintf(NULL,file,"%s%s",path,ECHOLOGNAME);

   el=(void *)calloc(sizeof(struct EchoLog),1);

   if(el)
   {
      fh=Open(file,MODE_OLDFILE);

      if(fh)
         i=Read(fh,el,sizeof(struct EchoLog));
      
      /* new */

      if(el->el_daily[magic].d_recorddate.od_year != year)
      {
         el->el_daily[magic].d_imported=0;
         el->el_daily[magic].d_exported=0;
         el->el_daily[magic].d_totexported=0;
         el->el_daily[magic].d_totnodes=0;
      }
      
      /* end new */     

      el->el_daily[magic].d_recorddate.od_year=year;
      el->el_daily[magic].d_recorddate.od_month=month;
      el->el_daily[magic].d_recorddate.od_date=date;

      el->el_daily[magic].d_imported+=imported;
      el->el_daily[magic].d_exported+=exported;
      el->el_daily[magic].d_totexported+=(exported*totnodes);

      if(el->el_daily[magic].d_totnodes<totnodes)
         el->el_daily[magic].d_totnodes=totnodes;

      if(imported)
      {
         el->el_lastimported.od_year=year;
         el->el_lastimported.od_month=month;
         el->el_lastimported.od_date=date;
      }

      if(exported)
      {
         el->el_lastexported.od_year=year;
         el->el_lastexported.od_month=month;
         el->el_lastexported.od_date=date;
      }

      if(!fh)
      {
         /* fill in structures for first time */

         strcpy(el->el_tagname,tagname);

         el->el_created.od_year=year;
         el->el_created.od_month=month;
         el->el_created.od_date=date;

         fh=Open(file,MODE_NEWFILE);
      }

      if(fh)
      {
         /*safe to write*/
         Seek(fh,0,OFFSET_BEGINNING);
         i=Write(fh,el,sizeof(struct EchoLog));
         Close(fh);
      }
   }
   return 0;
}
//-

#define MAX_ARGS 25

/*******************
 *
 * PRIVATE
 * ParseArgs
 *
 *******************/

/// ParseArgs
int ParseArgs(char **argv,char *argstring)
{
   char token[100];
   char *s;
   int i=0;

   s=argstring;

   argv[i]=NULL;

   while(*s != NULL && i<MAX_ARGS)
   {
      s=stpblk(s);

      if(*s)
      {
         argv[i]=s;
         i++;
         argv[i]=NULL;
         s=stptok(s,token,sizeof(token)," \t");
         if(*s) *s++=NULL;
      }
   }

   return(i);
}
//-
