
/* **** Includes *********************************************************** */

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

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

#include <HBBS/ANSI_Codes.h>
#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/release.h>
char *versionstr="$VER: AccountEdit "RELEASE_STR;

/* **** Variables ********************************************************** */

/* Common */

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

struct BBSGlobalData *BBSGlobal = NULL;
struct NodeData *N_ND           = NULL;
int    N_NodeNum                = -1;
char   outstr[1024];
char   tmpstr[80];
char   tmpstr2[80];

long __stack=16*1024; // increse this in 4k incrments if you suffer from
                      // random/suprious crashings after or during the running
                      // of your door.

int    gargc;         // these are just copies of main()'s argc and argv..
char   **gargv;

/* Used By This Door Only */

BOOL SysopMode=FALSE;
BOOL CallDataOnly=TRUE;
ULONG GLFlags=GL_EDIT + GL_DISPLAY;



/* **** Functions ********************************************************** */


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

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);
}

/* strof ********
  create a string of x characters and return a pointer to
  the destination string
*/
char *strof(char *dest,const char character,const ULONG length)
{
  ULONG loop=0;

  while (loop < length)
  {
    dest[loop++] = character;
  }
  dest[loop]=0; // null terminate
  return(dest);
}

/* **** DoorMain *********************************************************** */

void DisplayUserDetails ( struct UserData *UserDataPtr)
{
  char numstr1[21]; // max 20 used by BytesUp/Down
  char numstr2[21];

  DOOR_WriteText(ANSI_RESET "\033[1;1H");

  sprintf(outstr,ANSI_FG_CYAN"01"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Handle   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[1;42H"
                 ANSI_FG_CYAN"02"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Password "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          UserDataPtr->Handle,
          strof(tmpstr,' ',LEN_HANDLE - strlen( UserDataPtr->Handle ) ),
          UserDataPtr->Password,
          strof(tmpstr2,' ',LEN_PASSWORD - strlen( UserDataPtr->Password ) ) );
  DOOR_WriteText(outstr);

  sprintf(outstr,ANSI_FG_CYAN"03"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Group        "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          UserDataPtr->Group,
          strof(tmpstr,' ',LEN_GROUP - strlen( UserDataPtr->Group ) ) );
  DOOR_WriteText(outstr);

  sprintf(outstr,ANSI_FG_CYAN"04"ANSI_FG_BLUE") "ANSI_FG_YELLOW"SentBy       "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          UserDataPtr->SentBy,
          strof(tmpstr,' ',LEN_SENTBY - strlen( UserDataPtr->SentBy ) ) );
  DOOR_WriteText(outstr);

  sprintf(outstr,ANSI_FG_CYAN"05"ANSI_FG_BLUE") "ANSI_FG_YELLOW"ConfAcs File "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          UserDataPtr->ConfAcsDataFile,
          strof(tmpstr,' ',LEN_CONFACCESSFILE - strlen( UserDataPtr->ConfAcsDataFile ) ) );
  DOOR_WriteText(outstr);


  sprintf(numstr1,"%d",UserDataPtr->Access); // for working out how many chars the number is.

  sprintf(outstr,ANSI_FG_CYAN"06"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Access       "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[5;42H"
                 ANSI_FG_CYAN"07"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Status       "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%c"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',3 - strlen( numstr1 ) ),
          UserDataPtr->Status);
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%d",UserDataPtr->BytesRatio);
  sprintf(numstr2,"%d",UserDataPtr->BytesRatio);

  sprintf(outstr,ANSI_FG_CYAN"08"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Byte Ratio   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[6;42H"
                 ANSI_FG_CYAN"09"ANSI_FG_BLUE") "ANSI_FG_YELLOW"File Ratio   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',3 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',3 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%1.0f",UserDataPtr->UploadBytes);
  sprintf(numstr2,"%d",UserDataPtr->UploadFiles);

  sprintf(outstr,ANSI_FG_CYAN"10"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Bytes Up     "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[7;42H"
                 ANSI_FG_CYAN"11"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Files Up     "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',20 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',6 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%1.0f",UserDataPtr->DownloadBytes);
  sprintf(numstr2,"%d",UserDataPtr->DownloadFiles);

  sprintf(outstr,ANSI_FG_CYAN"12"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Bytes Down   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[8;42H"
                 ANSI_FG_CYAN"13"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Files Down   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',20 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',6 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%d",UserDataPtr->TimeAllowed);
  sprintf(numstr2,"%d",UserDataPtr->MessagesWritten);

  sprintf(outstr,ANSI_FG_CYAN"14"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Time Allowed "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[9;42H"
                 ANSI_FG_CYAN"15"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Messages W.  "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',5 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',7 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%d",UserDataPtr->TimeUsed);
  sprintf(numstr2,"%d",UserDataPtr->PreferredConf);

  sprintf(outstr,ANSI_FG_CYAN"16"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Time Used    "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[10;42H"
                 ANSI_FG_CYAN"17"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Pref. Conf.  "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',5 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',6 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%d",UserDataPtr->ExtraTimeLimit);
  sprintf(numstr2,"%d",UserDataPtr->LastConf);

  sprintf(outstr,ANSI_FG_CYAN"18"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Extra Time   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[11;42H"
                 ANSI_FG_CYAN"19"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Last Conf.   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',4 - strlen( numstr1 ) ), // anything larger than (60 * 24) 1440 won't make any difference, so limit digits to 4.
          numstr2,
          strof(tmpstr2,' ',6 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(numstr1,"%d",UserDataPtr->CallsMade);
  sprintf(numstr2,"%d",UserDataPtr->Language);

  sprintf(outstr,ANSI_FG_CYAN"20"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Calls Made   "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\033[12;42H"
                 ANSI_FG_CYAN"21"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Language     "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          numstr1,
          strof(tmpstr,' ',7 - strlen( numstr1 ) ),
          numstr2,
          strof(tmpstr2,' ',3 - strlen( numstr2 ) ));
  DOOR_WriteText(outstr);

  sprintf(outstr,ANSI_FG_CYAN"22"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Leech Acs File "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n"
                 ANSI_FG_CYAN"23"ANSI_FG_BLUE") "ANSI_FG_YELLOW"Time Acs File  "ANSI_FG_CYAN"["ANSI_FG_WHITE ANSI_BG_RED"%s"ANSI_BG_BLUE"%s"ANSI_FG_CYAN ANSI_BG_BLACK"]"
                 "\r\n",
          UserDataPtr->LeechAccDataFile,
          strof(tmpstr,' ',LEN_LEECHACCESSFILE - strlen( UserDataPtr->LeechAccDataFile ) ),
          UserDataPtr->TimeAccessFile,
          strof(tmpstr2,' ',LEN_TIMEACCESS - strlen( UserDataPtr->TimeAccessFile ) ));
  DOOR_WriteText(outstr);         
  
  sprintf(outstr,ANSI_FG_CYAN "UserID"ANSI_FG_BLUE": "ANSI_FG_GREEN"%04d",UserDataPtr->UserID);
  DOOR_WriteText(outstr);         

}

void MoveCursor( void )
{
  DOOR_WriteText(ANSI_RESET "\033[16;1H\033[K\033[16;1H");
}                                   

short text_entry_colours[2] = {0,7} ; /* ANSI fg, bg */
 
void HandleOption(int OptionNum,struct UserData *UserDataPtr)
{
  V_SMALLNUM SmallNum;
  V_BIGNUM BigNum;

  switch (OptionNum)
  {
    case 1: // Handle
      sprintf(outstr,"\033[1;15H" "\033[3%d;4%dm" "%s%s\033[1;15H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_HANDLE));
      DOOR_WriteText(outstr);

      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_HANDLE,0,UserDataPtr->Handle);
      if (N_ND->CurrentLine[0])
      {
        if (HBBS_HandleNameOK(N_ND->CurrentLine))
        {
          strcpy(UserDataPtr->Handle,N_ND->CurrentLine);
        }
        else
        {
          MoveCursor();
          DOOR_ContinuePrompt(ANSI_FG_YELLOW "That handle contains invalid characters! [Return]",DEFAULT_NONE|DCP_NODISPLAY|DCP_COLOURIZE);
          MoveCursor();
        }
      }
      break;
    case 2: // Password
      sprintf(outstr,"\033[1;56H" "\033[3%d;4%dm" "%s\033[1;56H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_PASSWORD));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_PASSWORD,0,UserDataPtr->Password);
      if (N_ND->CurrentLine[0])
      {
        strcpy(UserDataPtr->Password,N_ND->CurrentLine);
      }
      break;
    case 3: // group
      sprintf(outstr,"\033[2;19H" "\033[3%d;4%dm" "%s\033[2;19H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_GROUP));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_GROUP,0,UserDataPtr->Group);
      if (N_ND->CurrentLine[0])
      {
        strcpy(UserDataPtr->Group,N_ND->CurrentLine);
      }
      break;

    case 4: // sentby
      sprintf(outstr,"\033[3;19H" "\033[3%d;4%dm" "%s\033[3;19H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_SENTBY));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_SENTBY,0,UserDataPtr->SentBy);
      strcpy(UserDataPtr->SentBy,N_ND->CurrentLine);
      break;

    case 5: // ConfAcs File
      sprintf(outstr,"\033[4;19H" "\033[3%d;4%dm" "%s\033[4;19H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_CONFACCESSFILE));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_CONFACCESSFILE,0,UserDataPtr->ConfAcsDataFile);
      if (N_ND->CurrentLine[0])
      {
        strcpy(outstr,"HBBS:System/Data/ConfAcs");
        AddPart(outstr,N_ND->CurrentLine,1024);
        strcat(outstr,".CFG");
        if (PathOK(outstr))
        {
          strcpy(UserDataPtr->ConfAcsDataFile,N_ND->CurrentLine);
        }
        else
        {
          MoveCursor();
          DOOR_PausePrompt(ANSI_FG_YELLOW "Invalid, check HBBS:System/Data/ConfAcs/#? for valid names");
          MoveCursor();
        }
      }
      break;

    case 6: //access level
      sprintf(outstr,"\033[5;19H" "\033[3%d;4%dm" "   \033[5;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->Access);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,3,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        // validate access level!
        if (HBBS_FindNodeNum(BBSGlobal->AcsLevelList,N_ND->CurrentLine)!=-1)
        {
          UserDataPtr->Access=SmallNum;
        }
        else
        {
          MoveCursor();
          DOOR_PausePrompt(ANSI_FG_YELLOW"Invalid Access Level, check HBBS:Access/Levels/Level_List for valid ones");
          MoveCursor();
        }
      }
      break;

    case 7: //status
    
      // display posibilities first
      
      MoveCursor();
      DOOR_WriteText(ANSI_FG_CYAN "Enter one of: V, N, D, O, L or I (see the docs for more info)");
      
      sprintf(outstr,"\033[5;60H" "\033[3%d;4%dm" " \033[5;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%c",UserDataPtr->Status);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,1,0,outstr);
      if (N_ND->CurrentLine[0])
      {
        UserDataPtr->Status=N_ND->CurrentLine[0];
      }
      MoveCursor();
      
      break;

    case 8: // bytes ratio
      MoveCursor();
      DOOR_WriteText(ANSI_FG_CYAN "Where the ratio is x : 1");

      sprintf(outstr,"\033[6;19H" "\033[3%d;4%dm" "   \033[6;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->BytesRatio);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,3,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->BytesRatio=SmallNum;
      }
      
      MoveCursor();
      break;

    case 9: // files ratio
      MoveCursor();
      DOOR_WriteText(ANSI_FG_CYAN "Where the ratio is x : 1");

      sprintf(outstr,"\033[6;60H" "\033[3%d;4%dm" "   \033[6;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->FilesRatio);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,3,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->FilesRatio=SmallNum;
      }
      MoveCursor();

      break;

    case 10: //bytes uploaded
      MoveCursor();
      DOOR_WriteText(ANSI_FG_CYAN "Use '+n' to add, '-n' to replace or just 'n' to set, eg: +300.");
      sprintf(outstr,"\033[7;19H" "\033[3%d;4%dm" "%s\033[7;19H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',20));
      DOOR_WriteText(outstr);

      sprintf(outstr,"%1.0f",UserDataPtr->UploadBytes);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,20,0,outstr);

      switch (N_ND->CurrentLine[0])
      {
        case '+':
          UserDataPtr->UploadBytes+=atof(N_ND->CurrentLine+1);
          break;
          
        case '-':
          UserDataPtr->UploadBytes-=atof(N_ND->CurrentLine+1);
          break;
          
        default:
          if (N_ND->CurrentLine[0])
          {
            UserDataPtr->UploadBytes = atof(N_ND->CurrentLine);
          }
          break;
      }
      MoveCursor();
      break;

    case 11: //files uploaded
      sprintf(outstr,"\033[7;60H" "\033[3%d;4%dm" "      \033[7;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->UploadFiles);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,6,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&BigNum) == 1)
      {
        UserDataPtr->UploadFiles=BigNum;
      }
      break;

    case 12: //bytes downloaded
      MoveCursor();
      DOOR_WriteText(ANSI_FG_CYAN "Use '+n' to add, '-n' to replace or just 'n' to set, eg: +300.");
      sprintf(outstr,"\033[8;19H" "\033[3%d;4%dm" "%s\033[8;19H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',20));
      DOOR_WriteText(outstr);

      sprintf(outstr,"%1.0f",UserDataPtr->DownloadBytes);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,20,0,outstr);

      switch (N_ND->CurrentLine[0])
      {
        case '+':
          UserDataPtr->DownloadBytes+=atof(N_ND->CurrentLine+1);
          break;
          
        case '-':
          UserDataPtr->DownloadBytes-=atof(N_ND->CurrentLine+1);
          break;
          
        default:
          if (N_ND->CurrentLine[0])
          {
            UserDataPtr->DownloadBytes = atof(N_ND->CurrentLine);
          }
          break;
      }
      MoveCursor();
      break;

    case 13: //files downloaded
      sprintf(outstr,"\033[8;60H" "\033[3%d;4%dm" "      \033[8;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->DownloadFiles);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,6,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&BigNum) == 1)
      {
        UserDataPtr->DownloadFiles=BigNum;
      }
      break;

    case 14: // Time Allowed
      sprintf(outstr,"\033[9;19H" "\033[3%d;4%dm" "     \033[9;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->TimeAllowed);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,5,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->TimeAllowed=SmallNum;
      }
      break;

    case 15: // MessagesWritten
      sprintf(outstr,"\033[9;60H" "\033[3%d;4%dm" "       \033[9;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->MessagesWritten);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,7,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->MessagesWritten=SmallNum;
      }
      break;

    case 16: // Time Used
      sprintf(outstr,"\033[10;19H" "\033[3%d;4%dm" "     \033[10;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);

      sprintf(outstr,"%ld",UserDataPtr->TimeUsed);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,5,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->TimeUsed=SmallNum;
      }
      break;

    case 17: // Preferred Conf
      sprintf(outstr,"\033[10;60H" "\033[3%d;4%dm" "      \033[10;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->PreferredConf);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,4,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->PreferredConf=SmallNum;
      }
      break;
    case 18: // Extra Time Limit
      sprintf(outstr,"\033[11;19H" "\033[3%d;4%dm" "    \033[11;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->ExtraTimeLimit);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,4,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->ExtraTimeLimit=SmallNum;
      }
      break;
    case 19: // Last Conf
      sprintf(outstr,"\033[11;60H" "\033[3%d;4%dm" "      \033[11;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->LastConf);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,6,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->LastConf=SmallNum;
      }
      break;

    case 20: // Calls Made
      sprintf(outstr,"\033[12;19H" "\033[3%d;4%dm" "       \033[12;19H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->CallsMade);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,7,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->CallsMade=SmallNum;
      }
      break;
    case 21: // Language
      sprintf(outstr,"\033[12;60H" "\033[3%d;4%dm" "   \033[12;60H",text_entry_colours[0],text_entry_colours[1]);
      DOOR_WriteText(outstr);
      sprintf(outstr,"%ld",UserDataPtr->Language);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,3,0,outstr);
      if (sscanf(N_ND->CurrentLine,"%d",&SmallNum) == 1)
      {
        UserDataPtr->Language=SmallNum;
      }
      break;

    case 22: // LeechAcsFile
      sprintf(outstr,"\033[13;21H" "\033[3%d;4%dm" "%s\033[13;21H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_LEECHACCESSFILE));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_LEECHACCESSFILE,0,UserDataPtr->LeechAccDataFile);
      strcpy(UserDataPtr->LeechAccDataFile,N_ND->CurrentLine);
      break;

    case 23: // TimeAcsFile
      sprintf(outstr,"\033[14;21H" "\033[3%d;4%dm" "%s\033[14;21H",text_entry_colours[0],text_entry_colours[1],
              strof(tmpstr,' ',LEN_TIMEACCESS));
      DOOR_WriteText(outstr);
      DOOR_GetLine(GLFlags | GL_NODISTURB,0,LEN_TIMEACCESS,0,UserDataPtr->TimeAccessFile);
      strcpy(UserDataPtr->TimeAccessFile,N_ND->CurrentLine);
      break;

    Default :
      DOOR_WriteText("Unknown Option!\r\n");
      break;
  }
}

void DisplayHelp( void )
{
  DOOR_WriteText(ANSI_CLS ANSI_FG_CYAN
                 "To use the Validate option, first set the access level for the user, then use\r\n"
                 "Validate option from the menu and the rest of the users settings will be\r\n"
                 "changed accordingly\r\n\r\n");
  DOOR_PausePrompt(NULL);
}

LONG EditUser ( struct UserData *UserDataPtr,LONG EUFlags)
{
  // Return Values

  #define EU_Save 1
  #define EU_Cancel 0

  // Flags

  #define EUF_None 0


  V_BIGNUM BigNum,OptionNum;
  BOOL Done=FALSE,ChangesMade=FALSE;
  LONG Retval=EU_Cancel;
  struct UserData TmpUser;

  CopyMem(UserDataPtr,&TmpUser,sizeof(struct UserData));

  DOOR_WriteText(ANSI_CLS);
  do
  {
    DisplayUserDetails(&TmpUser);

    MoveCursor();
    DOOR_MenuPrompt("[S]ave, [Q]uit, [H]elp, [V]alidate or # of option:",' ');
    if (DOOR_GetLine(GLFlags,'\0',0,0,NULL)==IN_GOTLINE)
    {
      MoveCursor();
      RemoveSpaces(N_ND->CurrentLine);
      if (stricmp("S",N_ND->CurrentLine)==0)
      {
        DOOR_WriteText("Save\r\n");
        Retval=EU_Save;
        Done=TRUE;
      }
      else
      if (stricmp("Q",N_ND->CurrentLine)==0)
      {
        DOOR_WriteText("Quit\r\n");
        if (ChangesMade && DOOR_ContinuePrompt("Save changes first ",DEFAULT_NO|DCP_ADDYN))
        {
          Retval=EU_Save;
        }
        Done=TRUE;
      }
      else
      if (stricmp("H",N_ND->CurrentLine)==0)
      { 
        DisplayHelp();
      }
      else
      if (stricmp("V",N_ND->CurrentLine)==0)
      {
        // Set VALIDATED status
        TmpUser.Status=USER_VALIDATED;

        sprintf(outstr,"%d",TmpUser.Access);
        if ((BigNum=HBBS_FindNodeNum(BBSGlobal->AcsLevelList,outstr))>=0)
        {
          strcpy(TmpUser.ConfAcsDataFile,HBBS_ListName(BBSGlobal->AcsLevelConfAcsDef,BigNum));

          HBBS_ApplyAccountDefaults(&TmpUser);

        }
      }
      else
      {
        DOOR_WriteText("\r\n");
        OptionNum=0;
        if (sscanf(N_ND->CurrentLine,"%d",&OptionNum) == 1)
        {
          HandleOption(OptionNum,&TmpUser);
          ChangesMade=TRUE;
        }
      }
    }
    else
    {
      Done=TRUE;
    }
  } while (!Done);

  if (Retval==EU_Save)
  {
    CopyMem(&TmpUser, UserDataPtr, sizeof(struct UserData));
  }

  return(Retval);
}

#define EDIT_NONE   0
#define EDIT_BROWSE 1
#define EDIT_NEW    2

struct UserNode
{
  struct Node node;
  V_BIGNUM FileOffset;
};

void DoorMain( void )
{
  struct UserData UserDat;
  BOOL Done2,Done=FALSE;
  char defaultopt;
  struct List *UserList;
  struct UserNode *node,*CurrentUser;
  V_BIGNUM UserID,UsersInList,BytesRead,FileOffset;
  short ListMode;

  BOOL CreatedList;
  BPTR FH;
  BPTR FL;

  if ((gargc>=3) && (iposition("SYSOPONLY",gargv[2])>=0))
  {
    SysopMode=TRUE;
    CallDataOnly=FALSE;
    DOOR_WriteText(ANSI_RESET ANSI_CLS "Wait while the sysop changes your account settings!\r\n");

    /* Block Output to the serial port so the user doesn't see what we're doing.. */

    N_ND->NodeFlags+=NFLG_BLOCKSERIAL;

    GLFlags+=GL_SYSOP;

    if ((gargc>=4) && (iposition("CALLONLY",gargv[3])>=0))
    {
      CallDataOnly=TRUE;
    }

    if (N_ND->User->Valid)
    {
      if (EditUser(N_ND->User->CallData,EUF_None)==EU_Save)
      {

        // copy the modified data to the users normal data, if we're supposed to!

        if (!CallDataOnly)
        {
          CopyMem(N_ND->User->CallData,N_ND->User->NormalData,sizeof(struct UserData));
        }

        if (SysopMode && CallDataOnly) DOOR_WriteText("Changes only last for this call!\r\n");
      }
    }
    else
    {
      DOOR_SysopText("No User is Logged On Yet!\r\n");
    }
    N_ND->NodeFlags-=NFLG_BLOCKSERIAL;

    HBBS_SetAccess();
  }
  else
  {
    do
    {
      DOOR_WriteText(ANSI_CLS ANSI_RESET ANSI_FG_YELLOW "Account Editor\r\n" ANSI_FG_WHITE);
      strcpy(N_ND->CharsAllowed,"SsNnQqBbIi");
      DOOR_MenuPrompt("[N]ew Users, [S]pecific User, [I]d, [B]rowse, [Q]uit:",'Q');
      DOOR_GetLine(GLFlags | GL_IMMEDIATE | GL_USECHARS,0,1,0,NULL);
      if (N_ND->OnlineStatus==OS_ONLINE && N_ND->CurrentLine[0])
      {
        ListMode=EDIT_NONE;

        switch(toupper(N_ND->CurrentLine[0]))
        {
          case 'I':
            DOOR_MenuPrompt("Enter User ID:",' ');
            DOOR_GetLine(GLFlags,0,LEN_HANDLE,0,NULL);
            RemoveSpaces(N_ND->CurrentLine);
            if (N_ND->CurrentLine[0]) // anything left in the line ?
            {
              UserID=atoi(N_ND->CurrentLine);

              if (HBBS_LoadUser(0, UserID, NULL, NULL, &UserDat, LOADUSER_SKIPOVERWRITABLE))
              {
                if (EditUser(&UserDat,EUF_None)==EU_Save)
                {
                  HBBS_SaveUserData(&UserDat);
                }
              }
              else DOOR_WriteText("That user ID does not exist!\r\n");
            }
            break;

          case 'S':
            DOOR_MenuPrompt("Enter Handle:",' ');
            DOOR_GetLine(GLFlags,0,LEN_HANDLE,0,NULL);
            RemoveSpaces(N_ND->CurrentLine);
            if (N_ND->CurrentLine[0])
            {
              if (HBBS_ValidUserHandle(N_ND->CurrentLine,&UserDat))
              {
                if (EditUser(&UserDat,EUF_None)==EU_Save)
                {
                  HBBS_SaveUserData(&UserDat);
                }

              }
              else
              {
                DOOR_WriteText("Could not find that user!\r\n");
              }
            }
            break;
          case 'B':
            ListMode=EDIT_BROWSE;
            break;
          case 'N':
            ListMode=EDIT_NEW;
            break;
          case 'Q':
            Done=TRUE;
            break;
        }

        if (ListMode!=EDIT_NONE)
        {
          defaultopt='E';
          DOOR_WriteText("Searching...");

          /*
            Build linked list of users in memory, needs to contain userid of user
            this way we can go [N]ext and [P]rev even after you have validated a user
            (the user's status may have been changed so we couldn't search backwards
            from current to find the last user with a status of N)
            Also, this keeps the userdata file unlocked for the rest of the time..
          */

          if (UserList=HBBS_CreateList())
          {
            UsersInList=0;
            CurrentUser=0;
            CreatedList=FALSE;
            FileOffset=0;

            FL=HBBS_LockUserData(ACCESS_READ);

            if (FH=OpenFromLock(FL))
            {
              do
              {
                if (BytesRead = Read(FH,&UserDat,sizeof(struct UserData))) // read some bytes ?
                {
                  if (BytesRead == sizeof(struct UserData))
                  {
                    FileOffset++;
                    sprintf(outstr,"%ld : %s\033[K\r", FileOffset, UserDat.Handle); // erase line and return to start of line
                    DOOR_WriteText(outstr); 

                    if ((ListMode==EDIT_NEW && UserDat.Status==USER_NEW) || (ListMode==EDIT_BROWSE && UserDat.Status != USER_OVERWRITABLE))
                    {
                      if (node=(struct UserNode*)HBBS_CreateNode(NULL,sizeof(struct UserNode)))
                      {
                        node->FileOffset=FileOffset;
                        AddTail(UserList,(struct Node*)node);
                        UsersInList++;
                      }
                    }
                  }
                  else
                  {
                    DOOR_WriteText("Could not read all of the data file!\r\n");
                    CreatedList=TRUE;
                  }
                }
                else
                {
                  CreatedList=TRUE;
                }
              } while (!CreatedList);

              Close(FH);
            }
            else
            {
              UnLock(FL);
            }

            HBBS_UnLockUserData();

            sprintf(outstr,"\033[K\rOK.\r\nFound %d %suser%s\r\n",
                    UsersInList,
                    ListMode==EDIT_NEW ? "new " : "",
                    UsersInList==1 ? "" : "s");
            DOOR_WriteText(outstr);
            DOOR_PausePrompt(NULL);

            if (UsersInList)
            {
              CurrentUser=(struct UserNode *)UserList->lh_Head;

              Done2=FALSE;

              do
              {
                if (HBBS_LoadUser((ULONG)CurrentUser->FileOffset,0,NULL,NULL,&UserDat,LOADUSER_NONE))
                {
                  DOOR_WriteText(ANSI_CLS ANSI_RESET ANSI_FG_YELLOW "Account Editor\r\n");
                  sprintf(outstr,ANSI_FG_CYAN "Current User "ANSI_FG_YELLOW"(%ld) "ANSI_FG_BLUE": "ANSI_FG_YELLOW"%s"ANSI_FG_BLUE" / "ANSI_FG_YELLOW"%s\r\n"ANSI_FG_WHITE,UserDat.UserID,UserDat.Handle,UserDat.Group);
                  DOOR_WriteText(outstr);
                  DOOR_MenuPrompt("Options: [E]dit, [D]elete, [N]ext, [P]rev, [Q]uit:",defaultopt);
                  strcpy(N_ND->CharsAllowed,"EeDdNnPpQq");
                  DOOR_GetLine(GLFlags | GL_IMMEDIATE | GL_USECHARS,0,1,0,NULL);
                  if (N_ND->OnlineStatus==OS_ONLINE)
                  {
                    if (N_ND->CurrentLine[0]==0) N_ND->CurrentLine[0]=defaultopt;
                    switch(toupper(N_ND->CurrentLine[0]))
                    {
                      case 'D':
                        if (DOOR_ContinuePrompt("Are you sure!",DCP_ADDYN))
                        {
                          UserDat.Status=USER_DELETED;
                          HBBS_SaveUserData(&UserDat);
                          DOOR_WriteText("DELETED!\r\n");
                          if ((struct Node **)CurrentUser->node.ln_Succ != &UserList->lh_Tail)
                          {
                            CurrentUser=(struct UserNode *)CurrentUser->node.ln_Succ;
                            defaultopt='E';
                          }
                          else DOOR_PausePrompt("No More! - Press Return");
                        }
                        break;
                      case 'P':
                        if ((struct Node **)CurrentUser->node.ln_Pred != &UserList->lh_Head)
                        {
                          CurrentUser=(struct UserNode *)CurrentUser->node.ln_Pred;
                        }
                        else DOOR_PausePrompt("No More! - Press Return");
                        break;
                      case 'Q':
                        Done2=TRUE;
                        break;
                      case 'E':
                        if (EditUser(&UserDat,EUF_None)==EU_Save)
                        {
                          HBBS_SaveUserData(&UserDat);
                        }
                        // and follow on to save code repetition...
                      case 'N':
                        if ((struct Node **)CurrentUser->node.ln_Succ != &UserList->lh_Tail)
                        {
                          CurrentUser=(struct UserNode *)CurrentUser->node.ln_Succ;
                          defaultopt='E';
                        }
                        else DOOR_PausePrompt("No More! - Press Return");
                        break;
                    }

                  } else Done2=TRUE;

                }
                else Done2=TRUE;

              } while (!Done2);
              HBBS_FreeListNodes(UserList);
            }
            FreeVec(UserList);
          } else DOOR_WriteText("No Mem\r\n");

        }
      }
      if (N_ND->OnlineStatus==OS_OFFLINE) Done=TRUE;
    } while (!Done);
  }

  DOOR_WriteText("Done.\r\n");
}

int main(int argc,char **argv)
{
  gargc=argc;
  gargv=argv;

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

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

/* **** End Of File ******************************************************** */