#include <stdlib.h>
#include <string.h>

#include <time.h>

#include <exec/types.h>

#include <libraries/dos.h>
#include <libraries/dosextens.h>

#include <dos/dos.h>

#include <dlg/cron.h>
#include <dlg/user.h>
#include <dlg/misc.h>
#include <dlg/log.h>
#include <dlg/portconfig.h>
#include <dlg/resman.h>

#include <link/io.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

extern struct DosLibrary *DOSBase;
char **libgetlang(void);

void  __saveds __asm LIBSMDate(register __d0 ULONG, register __a0 char *);
void  __saveds __asm LIBUnpackTime(register __d0 ULONG, register __a0 struct ATime *);
ULONG __saveds __asm LIBAmigaTime(void);

BOOL  __saveds __asm LIBExists(register __a0 char *);
BPTR  __saveds __asm LIBOpenGroup(register __a0 char *);
void  __saveds __asm LIBCloseGroup(register __a0 BPTR);
void  __saveds __asm LIBUpper(register __a0 char *);
void  __saveds __asm LIBCapitalize(register __a0 char *);
void  __saveds __asm LIBUnderScore(register __a0 char *);
LONG  __saveds __asm LIBGetFirstStruct(register __a0 char *, register __a1 char *, register __d0 ULONG);
BOOL  __saveds __asm LIBDispForm(register __a0 char *, register __a1 struct USER_DATA *, register __a2 struct USER_DATA *, register __a3 struct Ram_File *, register __d0 char *);
BOOL  __saveds __asm LIBDialogBatch(register __a0 char *, register __a1 struct USER_DATA *, register __a2 struct Ram_File *, register __a3 char *);

LONG  __saveds __asm LIBTCheckCarrier(register __a0 char *);
BOOL  __saveds __asm LIBWriteLog(register __d0 UBYTE, register __a0 char *, register __a1 char *, register __a2 char *);
LONG  __saveds __asm LIBHandleBCMsgs(register __a0 char *);
LONG  __saveds __asm LIBBCResume(register __a0 char *);

LONG  __saveds __asm LIBCronEvent(register __d0 UBYTE, register __d1 ULONG, register __a0 char *);
LONG  __saveds __asm LIBWhenEvent(register __a0 char *);
LONG  __saveds __asm LIBStricmp(register __a0 char *,  register __a1 char *);
LONG  __saveds __asm LIBLoadLang(register __a0 char *, register __a1 char *);
BOOL  __saveds __asm LIBDB(register __a0 char *);


/// GetDevName
LONG __saveds __asm LIBGetDevName(register __a0 char *devname)
{
   struct RootNode *rn;
   struct DosInfo  *dosi;
   struct DevInfo  *devi;
   struct Process  *myproc;
   long             conadd;
   long             result;
   char            *dname;
   char            *pname;
   char             portname[256];

   myproc = (struct Process *)FindTask(0);
   conadd = (long)myproc->pr_ConsoleTask;

   Forbid();
   rn   = (struct RootNode *)DOSBase->dl_Root;
   dosi = (struct DosInfo *)BADDR(rn->rn_Info);
   devi = (struct DevInfo *)BADDR(dosi->di_DevInfo);

   result = -1;

   while(devi)
   {
      if (devi->dvi_Type==DLT_DEVICE)
      {
         if (conadd==(LONG)devi->dvi_Task)
         {
            dname = (char *)BADDR(devi->dvi_Name);
            dname++;
            pname = stpcpy(portname, dname);
            strcpy(pname,   "control");

            if (FindPort(portname))
            {
               result = 0;
               strcpy(devname, dname);
            }

            break;
         }
      }

      devi=(struct DevInfo *)BADDR(devi->dvi_Next);
   }

   Permit();

   return(result);
}
//-

/// ReadRam
BOOL __saveds __asm LIBReadRam(register __a0 struct Ram_File *RamStruct,
register __a1 char            *port)
{
   char filename[18];

   ASPrintf(NULL, filename, "T:%3.3s.user", port);
   if (LIBGetFirstStruct(filename, (char *)RamStruct, sizeof(struct Ram_File)) == -1)
   return(FALSE);

   return(TRUE);
}
//-

/// WriteRam
BOOL __saveds __asm LIBWriteRam(register __a0 struct Ram_File *RamStruct,
register __a1 char            *port)
{
   BPTR fh;
   char filename[18];

   ASPrintf(NULL, filename, "T:%3.3s.user", port);

   if (!(fh = Open(filename, MODE_READWRITE)))
   if (!(fh = Open(filename, MODE_NEWFILE)))
   return(FALSE);

   LIBCapitalize(RamStruct->Name);
   Write(fh, RamStruct, sizeof(struct Ram_File));
   Close(fh);

   return(TRUE);
}
//-

/// ReadUser
BOOL __saveds __asm LIBReadUser(register __a0 struct Ram_File  *RamStruct,
register __a1 struct USER_DATA *UserStruct,
register __a2 char             *port)
{
   char filename[80];

   if (!LIBReadRam(RamStruct,port))  return(FALSE);

   ASPrintf(NULL,filename,"USER:%s/User.data",RamStruct->Name);
   LIBUnderScore(filename);

   if (LIBGetFirstStruct(filename,(char *)UserStruct,sizeof(struct USER_DATA))==-1)
   return(FALSE);

   return(TRUE);
}
//-

/// WriteUser
BOOL __saveds __asm LIBWriteUser(register __a0 char             *name,
register __a1 struct USER_DATA *UserStruct)
{
   BPTR fh;
   char filename[80];

   ASPrintf(NULL,filename,"USER:%s/User.data", name);
   LIBUnderScore(filename);

   if (!(fh = Open(filename, MODE_READWRITE)))
   if (!(fh = Open(filename, MODE_NEWFILE)))
   return(FALSE);

   Write(fh,UserStruct,sizeof(struct USER_DATA));
   Close(fh);

   return(TRUE);
}
//-

/// GetLevel
SHORT __saveds __asm LIBGetLevel(register __a0 char *name)
{
   char             filename[80];
   struct USER_DATA User;

   ASPrintf(NULL, filename, "User:%s/User.data", name);
   LIBUnderScore(filename);

   if (LIBGetFirstStruct(filename, (char *)&User, sizeof(User)) == -1)
   User.User_Level = 257;

   return(User.User_Level);
}
//-

/// GetComputerType
LONG __saveds __asm LIBGetComputerType(register __d0 SHORT number,
register __a0 char *string)
{
   BPTR                 fh;
   struct Computer_Type Ct;
   long                 count;

   count = 0;

   if ((fh = Open("DLGConfig:Port/ComputerTypes.bbs", MODE_OLDFILE)))
   {
      while(Read(fh, &Ct, sizeof(Ct)) == sizeof(Ct))
      {
         count++;
         if (Ct.Number == number)  strcpy(string, Ct.Name);
      }

      Close(fh);
   }

   return(count);
}
//-

/// Age
LONG __saveds __asm LIBAge(register __d0 SHORT year,
register __d1 SHORT month,
register __d2 SHORT day)
{
   struct ATime  currtime;
   LONG          age;

   LIBUnpackTime(LIBAmigaTime(), &currtime);
   age = currtime.year - year - 1900;
   if (age < 0)  age += 100;

   if (currtime.mon < month)
   age--;
   else
   if (currtime.mon == month  &&  currtime.mday < day) age--;

   return(age);
}
//-

/// CheckUser
LONG __saveds __asm LIBCheckUser(register __a0 char *name)
{
   BPTR fh;
   char filename[54];

   ASPrintf(NULL, filename, "USER:%s/User.data", name);
   LIBUnderScore(filename);

   if (!LIBExists(filename))
   {
      if (fh = LIBOpenGroup(name))
      {
         LIBCloseGroup(fh);
         return(2);
      }

      return(0);
   }

   return(1);
}
//-

/// TimeUntilShutdown
LONG __saveds __asm LIBTimeUntilShutdown(register __a0 char *ext)
{
   char string[40];
   LONG left;


   ASPrintf(NULL, string, "*%s SHUTDOWN*", ext);
   left = LIBWhenEvent(string);

   /* return time until shutdown or 1400 if no shutdown event is present */
   return((left!=-1)?left:1440);
}
//-

/// SuspendTime
void __saveds __asm LIBSuspendTime(register __a0 struct Ram_File *ram,
register __a1 char            *ext)
{
   char  string[40];

   /* Cron Event Command */
   ASPrintf(NULL, string, "> NIL: DLG:REMOVEUSER %s", ext);


   /* Figure out how much time is left */
   ram->time_left = LIBWhenEvent(string);
   ram->suspended = LIBAmigaTime();
   LIBWriteRam(ram, ext);


   /* Add an event for the maximum time allowed before a shutdown */
   LIBCronEvent(DELEVENT, 0, string);
   LIBCronEvent(ADDEVENT, LIBTimeUntilShutdown(ext)-2, string);
   return;
}
//-

/// ResumeTime
void __saveds __asm LIBResumeTime(register __a0 struct Ram_File *ram,
register __a1 char            *ext)
{
   char  string[40];
   long  shutdown;

   /* Determine minutes left */
   shutdown = LIBTimeUntilShutdown(ext) - 2;
   if (shutdown < ram->time_left)  ram->time_left = shutdown;

   /* Add the number of minutes we were suspended for */
   ram->suspd_adj += ((LIBAmigaTime() - ram->suspended) / 60);
   LIBWriteRam(ram, ext);

   ASPrintf(NULL, string, "> NIL: DLG:REMOVEUSER %s",ext);
   LIBCronEvent(DELEVENT,     0,          string);
   LIBCronEvent(ADDEVENT, ram->time_left, string);

   return;
}
//-

/// LogOut
void __saveds __asm LIBLogOut(register __a0 struct Ram_File  *Ram,
register __a1 struct USER_DATA *User,
register __a2 char             *Ext,
register __a3 char             *module)
{
   BPTR   sout;
   long   timeonline;
   char   ramfile[256];
   char **SA;
   struct Global_Settings *gs = NULL;
   struct LangStruct *mls = NULL;
   struct Port *mp;


   if (!module)  module = "";

   // Check for Carrier
   if (LIBTCheckCarrier(Ext))
   {
      LIBWriteLog(NORMAL_LOGOUT, Ram->Name, Ext, module);
   }
   else
   {
      LIBWriteLog(LOST_CARRIER,  Ram->Name, Ext, module);
   }

   /* Clear out any pending BroadCast Messages */
   LIBHandleBCMsgs(Ext);
   LIBBCResume(Ext);

   /* Delete Event log */
   ASPrintf(NULL, ramfile, "USER:%s/Event.Log", Ram->Name);
   LIBUnderScore(ramfile);
   DeleteFile(ramfile);

   /* Delete the tagged file */
   ASPrintf(NULL, ramfile, "t:%s.tagged", Ext);
   DeleteFile(ramfile);

   /* Get Language File/StdOut */
   SA   = libgetlang();
   sout = Output();

   /* Get Login Date & Compute time online */
   LIBSMDate(User->Long_Date, User->Last_Login);
   timeonline = ((LIBAmigaTime() - User->Long_Date) / 60) - Ram->suspd_adj;
   AFPrintf(User, sout, SA[3658], timeonline);


   /* Add time online to User Record */
   User->Daily_Used  += timeonline;
   User->Online_Time += timeonline;
   LIBWriteUser(Ram->Name, User);

   /* Execute Logout Batch */
   if (LIBExists("DLGCONFIG:Batch/LogOut.DLGBatch"))
   LIBDialogBatch("DLGCONFIG:Batch/LogOut.DLGBatch",User,Ram,Ext);

   LIBDispForm("DLGCONFIG:Text/Logout.txt",User,User,Ram,Ext);
   AFPrintf(NULL, sout, "\n");

   // Delete the T:<port>.User file
   ASPrintf(NULL, ramfile, "T:%s.User", Ext);
   while(LIBExists(ramfile))
   {
      if (DeleteFile(ramfile)) break;
   }

   // Remove Cron Event
   ASPrintf(NULL, ramfile, "> NIL: DLG:RemoveUser %s", Ext);
   LIBUpper(ramfile);
   while(LIBCronEvent(DELEVENT, 0, ramfile));

   // Load default language for port
   gs = calloc(1,sizeof(struct Global_Settings));
   mls = calloc(1,sizeof(struct LangStruct));
   mp = calloc(1,sizeof(struct Port));

   if(gs && mls && mp)
   {
      ASPrintf(NULL,ramfile,"DLGConfig:Port/%s.port",Ext);

      if(!LIBGetFirstStruct(ramfile,(char *)mp,sizeof(struct Port)))
      {
         ASPrintf(NULL,ramfile,"DLGConfig:Port/%s",mp->GlobalFile);

         if(!LIBGetFirstStruct(ramfile,(char *)gs,sizeof(struct Global_Settings)))
         {
            if(LIBStricmp(gs->Language,mls->name))
            {
            LIBLoadLang(Ext,gs->Language);
            }
         }
      }
   }

   if(gs) free(gs);
   if(mls) free(mls);
   if(mp) free(mp);
}
//-
