/*

   NewUser
   =======

*/


#include <exec/types.h>
#include <exec/memory.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>

#include <dos/dos.h>
#include <clib/dos_protos.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>


#ifdef __SASC
int CXBRK(void) { return(0); }
int _CXBRK(void) { return(0); }
void chkabort(void) {}
#endif

#include <HBBS/Defines.h>
#include <HBBS/types.h>
#include <HBBS/structures.h>
#include <HBBS/hbbscommon_protos.h>
#include <HBBS/hbbscommon_pragmas.h>
#include <HBBS/Hbbsnode_protos.h>
#include <HBBS/Hbbsnode_pragmas.h>
#include <HBBS/ANSI_Codes.h>
#include <HBBS/release.h>
char *versionstr="$VER: NewUser "RELEASE_STR;

ULONG __stack=16*1024; //16K

struct Library *HBBSCommonBase=NULL;
struct Library *HBBSNodeBase=NULL;

struct BBSGlobalData *BBSGlobal=NULL;
struct NodeData *N_ND=NULL;
int N_NodeNum=-1;
char outstr[BIG_STR];

static VOID cleanup(ULONG num)
{
  if (HBBSNodeBase)
  {
    HBBS_CleanUpDoor();
    CloseLibrary (HBBSNodeBase);
  }

  if (HBBSCommonBase)
  {
    HBBS_CleanUpCommon();
    CloseLibrary (HBBSCommonBase);
  }

  if (num) printf("Door Error = %d\n",num);

  exit(0);
}

static VOID init(char *name)
{
  if(!(HBBSCommonBase = OpenLibrary("HBBSCommon.library",0)))
  {
    cleanup(1);
  }

  if (!(HBBS_InitCommon()))
  {
    cleanup(2);
  }

  if(!(HBBSNodeBase = OpenLibrary("HBBSNode.library",0)))
  {
    cleanup(3);
  }

  if (!(HBBS_InitDoor(N_NodeNum,name)))
  {
    cleanup(4);
  }
  SetProgramName(name);
}


/********************************* ACTUAL DOOR CODE **************************/

BOOL GetOption(char *prompt,char *destination,short minlen, short maxlen, BOOL required,BOOL PasswordMode)
{
  // returns FALSE for carrier loss, or true when done
  BOOL Done=FALSE;
  while (N_ND->OnlineStatus==OS_ONLINE && !Done)
  {
    DOOR_WriteText(ANSI_RESET ANSI_FG_YELLOW);
    DOOR_WriteText(prompt);
    DOOR_WriteText(N_ND->BBSCols->MenuPromptANSI);
    
    if (DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_HISTORY,PasswordMode ? '*' : '\0',maxlen,0,NULL)==IN_GOTLINE)
    {
      if (strlen(N_ND->CurrentLine)>=minlen && strlen(N_ND->CurrentLine)<=maxlen)
      {
        strcpy(destination,N_ND->CurrentLine);
        Done=TRUE;
      }
      if (!required && N_ND->CurrentLine[0]==0) Done=TRUE;
    }
  }
  return(Done);
}

void OptionMsg (char *msgstr)
{
  DOOR_DisplaySpecialScreen("OptionMsg_TOP");
  DOOR_WriteText(msgstr);
  DOOR_WriteText("\r\n");
  DOOR_DisplaySpecialScreen("OptionMsg_BOT");
}                                              

void DoorMain( int argc,char *argv[] )
{
  BOOL Done=FALSE;
  BOOL UserAdded=FALSE;
  BOOL PasswordOK=FALSE;
  short loop;
  char tmpstr[BIG_STR];
  struct CfgFileData *NewUserCFG=NULL;
  BOOL ConfigOK=FALSE;
  struct UserData NU;
  short p;

  strcpy(outstr,argv[0]);
  if ((p=iposition(".HBBS",outstr))==(strlen(outstr)-5))
  {
    outstr[p]=0; //terminate string
  }
  strcat(outstr,".CFG");

  if (NewUserCFG=HBBS_LoadConfig(outstr,LCFG_NONE))
  {
    if (HBBS_GetSetting(NewUserCFG,(void *)&NU.Access,VTYPE_BIGNUM,"AccessLevel",OPT_SINGLE) &&
        HBBS_GetSetting(NewUserCFG,(void *)&NU.LastConf,VTYPE_BIGNUM,"ConfNum",OPT_SINGLE) &&
        HBBS_GetSetting(NewUserCFG,(void *)&NU.TimeAllowed,VTYPE_BIGNUM,"TimeAllowed",OPT_SINGLE))
    {
      ConfigOK=TRUE;
    }
    HBBS_FlushConfig(NewUserCFG);
  }

  if (!ConfigOK)
  {
    DOOR_PausePrompt("The NewUser door's config file could not be found or has errors\r\nA new user could not be created! - Press Return\r\n");
  }
  else
  {
    // initialise UserData structure for our new user.
                                                               
    HBBS_InitUserData(N_ND->User->CallData,NU.Access,NU.LastConf);
    N_ND->User->CallData->TimeAllowed=NU.TimeAllowed;
                                     
    // Get the users handle from the parameters passed to the door, remembering
    // that the users handle MAY have spaces in it..

    N_ND->User->CallData->Handle[0]=0;
    for (loop=2;loop<argc;loop++)
    {
      if (loop!=2) strcat(N_ND->User->CallData->Handle," ");
      strcat(N_ND->User->CallData->Handle,argv[loop]);
    }                       

    HBBS_ApplyAccountDefaults(N_ND->User->CallData);

    // Ok, we need to see if new users are allowed
    // a) at this time
    // b) on this node

    // *C* add time check..

    if (N_ND->NodeSettings.AllowNewUsers==FALSE)
    {
      DOOR_DisplaySpecialScreen(SSCREEN_NONEWAT_ALL);
    }
    else
    {
      // *C* display the screen "NoNewAt_ThisTime" if user is not allowed at this time.

      // display the screen "NoNewAt_BAUD" if users modem is too slow..

      sprintf(tmpstr,"NoNewAt_%s",N_ND->ConnectBaud);
      if (DOOR_DisplaySpecialScreen(tmpstr))
      {
        DOOR_HangUp();
        N_ND->OnlineStatus=OS_OFFLINE;
      }
      else
      {

        while (N_ND->OnlineStatus==OS_ONLINE && !Done)
        {
          DOOR_DisplaySpecialScreen("PreDetails");
          
          do
          { 
            sprintf(tmpstr,"Enter your new password (minimum %d letter%s)",BBSGlobal->MinPasswordLength,BBSGlobal->MinPasswordLength == 1 ? "" : "s");
            OptionMsg(tmpstr);

            if (GetOption("Password",N_ND->User->CallData->Password,BBSGlobal->MinPasswordLength,LEN_PASSWORD,TRUE,TRUE))
            {
              if (GetOption("Verify",tmpstr,BBSGlobal->MinPasswordLength,LEN_PASSWORD,FALSE,TRUE))
              {                 
                if (strcmp(N_ND->User->CallData->Password,tmpstr) == 0)
                {
                  PasswordOK=TRUE;
                }
              }
            }
            
            if ((!PasswordOK) && (N_ND->OnlineStatus==OS_ONLINE)) 
            {
              DOOR_WriteText(ANSI_FG_YELLOW "Verification failed!\r\n");
            }
          } while ((N_ND->OnlineStatus==OS_ONLINE) && (!PasswordOK));
          
          if (PasswordOK)
          {
            OptionMsg("Enter your real name, this information is only shown to the sysop.");

            if (GetOption("Real Name",N_ND->User->CallData->RealName,3,LEN_REALNAME,FALSE,FALSE))
            {
              OptionMsg("Enter the names of any scene groups your are a member of, if any");

              if (GetOption("Scene group",N_ND->User->CallData->Group,2,LEN_GROUP,FALSE,FALSE))
              {
                OptionMsg("Enter the name of the town/city you are calling from");

                if (GetOption("Town or City",N_ND->User->CallData->GeoLocation,3,LEN_GEOLOCATION,FALSE,FALSE))
                {
                  OptionMsg("What country are you are calling from");

                  if (GetOption("Country",N_ND->User->CallData->Country,2,LEN_COUNTRY,FALSE,FALSE))
                  {
                    OptionMsg("Please enter your voice phone number");

                    if (GetOption("Voice Number",N_ND->User->CallData->PhoneNumber,5,LEN_PHONENUMBER,FALSE,FALSE))
                    {
                      OptionMsg("Please enter details of all your computers (1 Line)");

                      if (GetOption("Computers",N_ND->User->CallData->ComputerType,2,LEN_COMPUTERTYPE,FALSE,FALSE))
                      {
                        DOOR_DisplaySpecialScreen("DetailsDone");

                        DOOR_WriteText(ANSI_FG_YELLOW"\r\nThank you, Adding user to data file...");

                        N_ND->User->CallData->Language=1; // provide a default

                        // We have to add the user to the userdatafile now, so that the doors that we call
                        // in a moment can access the user in the user.data file...

                        if (HBBS_AddUser(N_ND->User->CallData))
                        {
                          DOOR_WriteText("OK\r\n");
                          CopyMem(N_ND->User->CallData,N_ND->User->NormalData,sizeof(struct UserData));

                          N_ND->User->Valid=TRUE; // set this flag so that other programs can use the data from now on.

                          DOOR_SystemDoor("SelectLanguage",NULL);
                          if (N_ND->OnlineStatus==OS_ONLINE)
                          {
                            DOOR_SystemDoor("LinesPerScreen",NULL);
                            if (N_ND->OnlineStatus==OS_ONLINE)
                            {
                              DOOR_UserDoor("SENT",NULL);
                              if (N_ND->OnlineStatus==OS_ONLINE)
                              {
                                DOOR_SystemDoor("Questionnaire",NULL);
                                if (N_ND->OnlineStatus==OS_ONLINE)
                                {
                                  HBBS_SaveUserData(N_ND->User->CallData);
                                  DOOR_DisplaySpecialScreen("Joined");

                                  N_ND->Actions[ACTN_NEWUSER]=ACTC_NEWUSER;
                                  UserAdded=TRUE;
                                  sprintf(tmpstr,"Created a new user: %s / %s",N_ND->User->CallData->Handle,N_ND->User->CallData->Group);
                                  HBBS_LogError(BBSGlobal->ErrorLogFile,ERR_GENERAL,tmpstr,TYPE_WARNING);
                                  Done=TRUE;
                                }
                              }
                            }
                          }
                        }
                        else
                        {
                          DOOR_WriteText("FAILED - Sysop has been notified\r\n");
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  if (!UserAdded)
  {
    DOOR_SysopText("Failed to add user\r\n");
    HBBS_LogError(BBSGlobal->ErrorLogFile,ERR_GENERAL,"Failed To Create A NewUser Account",TYPE_WARNING);
    DOOR_Continue(FALSE);
  }

  DOOR_Return(UserAdded ? "USERADDED" : "FAILED");
}

int main(int argc,char *argv[])
{
  if (sscanf(argv[1],"%d",&N_NodeNum)==0)
  {
    printf("Invalid/No Paramaters for door!\n");
    exit (20);
  }
  init("NewUser");

  if (BBSGlobal=HBBS_GimmeBBS())
  {
    if (N_ND=HBBS_NodeDataPtr(N_NodeNum)) // this should not fail in normal circumstances..
    {
      DoorMain(argc,argv);
    }
  }
  cleanup(0);
}
