
#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>


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

#include <HBBS/ANSI_Codes.h>
#include <HBBS/Defines.h>
#include <HBBS/types.h>
#include <HBBS/structures.h>
#include <HBBS/Access.h>
#include <HBBS/hbbscommon_protos.h>
#include <HBBS/hbbscommon_pragmas.h>
#include <HBBS/Hbbsnode_protos.h>
#include <HBBS/Hbbsnode_pragmas.h>

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

struct BBSGlobalData *BBSGlobal=NULL;
struct NodeData *N_ND=NULL;
int N_NodeNum=-1;

char tmpstr[BIG_STR];
char outstr[BIG_STR];
V_SMALLNUM LinesOutput=0;
BOOL Quit=FALSE,NonStop=FALSE;
V_BIGNUM CurrentFileNumber=0;

#define FLM_NONE     0
#define FLM_NEW      1
#define FLM_REVERSE  2
#define FLM_LIST     3

ULONG Mode=FLM_NONE;

int gargc;
char **gargv;

char versionstr[]="$VER: FileList.HBBS V1.0 (25.12.95)";

char monthstr[12][4]={"JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"};
  LONG todaytime,fromtime;
  struct tm *todaytr,*fromtr;

#define BUFFERSIZE 1024  // *C* Increase to 32k



ULONG FH;
ULONG FL;
UBYTE Buffer[BUFFERSIZE];
ULONG BytesInBuffer;
ULONG BufferOffset;

#define DIR_FORWARDS TRUE
#define DIR_REVERSE FALSE

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

void ErrorOpening( void )
{
  DOOR_WriteText("Error Opening List File!\r\n");
}

void strpad(char *buffer, int requiredlen, UBYTE PadChar)
{
  int many;
  int loop;
  int clen=strlen(buffer);

  if (clen<requiredlen)
  {
    many=requiredlen-clen;
    for (loop=0;loop<=many;loop++) buffer[clen+loop]=PadChar;
    buffer[requiredlen]=0;
  }
}

void PrintLine( char *Buffer)
{
  // Depending on the it at the start of the buffer different things happen to the
  // output of the reset of the buffer..

  UBYTE buffer[82];
  strcpy(buffer,Buffer);

  if (buffer[1]==' ')
  {
    switch (buffer[0])
    {
      case 'F' :
        CurrentFileNumber++;
        DOOR_WriteText(ANSI_RESET ANSI_FG_BLUE);
        sprintf(tmpstr,"-- "ANSI_FG_YELLOW"["ANSI_FG_WHITE" %d "ANSI_FG_YELLOW"]"ANSI_FG_WHITE" - "ANSI_FG_YELLOW"["ANSI_FG_WHITE" %s "ANSI_FG_YELLOW"]"ANSI_FG_WHITE" - "ANSI_FG_YELLOW"["ANSI_FG_WHITE" Node %d "ANSI_FG_YELLOW"]"ANSI_FG_BLUE" ",CurrentFileNumber,BBSGlobal->BBSName,N_ND->NodeNum);
        strpad(tmpstr,79+60,'-'); // +60 for the ansi!
        strcat(tmpstr,"\r\n");
        DOOR_WriteText(tmpstr);

        // first part of line needs to be CYAN

        DOOR_WriteText(ANSI_FG_CYAN);
        strNcpy(tmpstr,&buffer[2],34);
        DOOR_WriteText(tmpstr);

        // last part of line needs to be WHITE

        DOOR_WriteText(ANSI_FG_WHITE);
        strfcpy(tmpstr,&buffer[2],34); // index at 0, so use 34 instead of 35 for the 34th char..
        DOOR_WriteText(tmpstr);
        DOOR_WriteText("\r\n");
        LinesOutput+=2;
        break;
      case 'I' :
        DOOR_WriteText(ANSI_FG_WHITE);
        DOOR_WriteText(&buffer[2]);
        DOOR_WriteText("\r\n");
        LinesOutput++;
        break;
      case 'X' :
        strpad(buffer,81,' '); // make sure it's 81 chars long.. 79 are printed..
        DOOR_WriteText(ANSI_BG_BLUE ANSI_FG_WHITE);
        DOOR_WriteText(&buffer[2]);
        DOOR_WriteText("\r\n");
        DOOR_WriteText(ANSI_RESET);
        LinesOutput++;
        break;
      case 'P' :
        DOOR_WriteText(ANSI_RESET);
        DOOR_WriteText(&buffer[2]);
        DOOR_WriteText("\r\n");
        DOOR_WriteText(ANSI_RESET);
        LinesOutput++;
        break;
      case 'T' :
        if (strlen(buffer)>=25)
        {
          strNcpy(tmpstr,&buffer[2],25);
          DOOR_WriteText(tmpstr);
          DOOR_WriteText(ANSI_FG_YELLOW);
          strNcpy(tmpstr,&buffer[27],8);
          DOOR_WriteText(tmpstr);
          DOOR_WriteText(ANSI_FG_WHITE);
          DOOR_WriteText(&buffer[35]);
          DOOR_WriteText("\r\n");
          LinesOutput++;
        }
        break;
      case 'N' :
        if (strlen(buffer)>=25)
        {
          strNcpy(tmpstr,&buffer[2],25);
          DOOR_WriteText(tmpstr);
          DOOR_WriteText(ANSI_FG_GREEN);
          strNcpy(tmpstr,&buffer[27],8);
          DOOR_WriteText(tmpstr);
          DOOR_WriteText(ANSI_FG_WHITE);
          DOOR_WriteText(&buffer[35]);
          DOOR_WriteText("\r\n");
          LinesOutput++;
        }
        break;
    }
  }
}

BOOL ScreenPausePrompt( void )
{
  BOOL retval=TRUE;
  V_BOOL Help;

  if (!NonStop)
  {
    do
    {
      Help=FALSE;
      strcpy(N_ND->CharsAllowed,"YyNnCcAaFfRr?Qq");
      DOOR_WriteText(ANSI_RESET "More "ANSI_FG_YELLOW"["ANSI_FG_WHITE"Y/N/C/A/F/R/?"ANSI_FG_YELLOW"]"ANSI_FG_WHITE " : ");
      DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_USECHARS|GL_IMMEDIATE|GL_NORETURN,'\0',1,0,NULL);
      if (N_ND->OnlineStatus==OS_ONLINE)
      {
        DOOR_WriteText("\r[K"); // erase line
        if (stricmp("F",N_ND->CurrentLine)==0)
        {
          DOOR_WriteText(ANSI_FG_CYAN "Enter Filenames To Tag > "ANSI_FG_WHITE);
          DOOR_GetLine(GL_EDIT|GL_DISPLAY,'\0',0,0,NULL);
          if (N_ND->OnlineStatus==OS_ONLINE)
          {
            RemoveSpaces(N_ND->CurrentLine);
            if (N_ND->CurrentLine[0])
            {
              strcpy(tmpstr,N_ND->CurrentLine);
              DOOR_UserDoor("A",tmpstr);
              Help=TRUE;
            }
          }
        }
        else
        if (stricmp("R",N_ND->CurrentLine)==0)
        {
          DOOR_WriteText(ANSI_FG_CYAN"Enter FileNumbers To Tag > "ANSI_FG_WHITE);
          DOOR_GetLine(GL_EDIT|GL_DISPLAY,'\0',0,0,NULL);
          Help=TRUE;
        }
        else
        if (stricmp("C",N_ND->CurrentLine)==0)
        {
          DOOR_WriteText(ANSI_CLS);
        }
        else
        if ((stricmp("N",N_ND->CurrentLine)==0) || (stricmp("Q",N_ND->CurrentLine)==0))
        {
          retval=FLASE;
        }
        else
        if (stricmp("A",N_ND->CurrentLine)==0)
        {
          NonStop=TRUE;
        }
        if (stricmp("?",N_ND->CurrentLine)==0)
        {
          DOOR_WriteText(ANSI_FG_CYAN
                         "?  -  This Help Page\r\n"
                         "C  -  Clear Screen And Continue\r\n"
                         "N/Q-  No More Please (QUIT)\r\n"
                         "A  -  Display All of remaining files (same as /X's NS)\r\n"
                         "F  -  Flag File By NAME\r\n"
                         "R  -  Flag File By NUMBER\r\n");
          Help=TRUE;
        }
      }
    }
    while ((N_ND->OnlineStatus==OS_ONLINE) && (Help));
  }
  LinesOutput=0;
  return(retval);
}


/*
void GetData( void )
{
  BytesInBuffer=Read(FH,Buffer,BUFFERSIZE);
  BufferOffset=0;
}

void FileList(char *listname)
{
  BOOL Done=FALSE;
  int LinePos;
  char filename[BIG_STR];
  UBYTE LineBuffer[82];

  // *C* Copy File To Ram HERE and update FILENAME with the name of the file in ram:
  strcpy(filename,listname);

  DOOR_WriteText(ANSI_RESET);

  if (FL=Lock(filename,ACCESS_READ))
  {
    if (FH=OpenFromLock(FL))
    {
      // Fetch some data to process..
      GetData();
      if (BytesInBuffer>0) // Got Some ?
      {
        LinesOutput=0;
        while ((N_ND->OnlineStatus==OS_ONLINE) && (!Done) && (!Quit))
        {
          // Ok, get a line of text, not exceeding more than 80 chars long.

          LinePos=0;
          while ((BytesInBuffer>0) && (Buffer[BufferOffset]!='\n') && (LinePos<=81))
          {
            LineBuffer[LinePos++]=Buffer[BufferOffset++];

            // Fetch More Data ?
            if (BufferOffset>=BytesInBuffer)
            {
              GetData();
            }
          }
          if (Buffer[BufferOffset]=='\n')
          {
            BufferOffset++;

            if (BufferOffset>=BytesInBuffer) GetData();
          }

          LineBuffer[LinePos]=0; // Null Terminate

          if (LineBuffer[0]) // Data To Check ?
          {
            PrintLine(LineBuffer);
          }
          if (LinesOutput>=N_ND->User.CallData.LinesPerScreen)
          {
            ScreenPausePrompt();
          }
          if (BytesInBuffer==0) Done=TRUE;
        }
      }
      Close(FH);
    }
    else
    {
      UnLock(FL);
      ErrorOpening();
    }
  }
  else
  ErrorOpening();

  DOOR_WriteText(ANSI_RESET "\r\n");
}

void NewFileList( void )
{
  UBYTE tmpstr[1024];
  ULONG Days=10
  struct Node *node;
  if (N_ND->CurrentConf)
  {
    if (N_ND->CurrentConf->FileLists>0)
    {
      node=GetNode(N_ND->CurrentConf->FileList,N_ND->CurrentConf->FileLists-1);
      // *C* remove..
      sprintf(tmpstr,"Displaying Files in %s From %d days ago..\r\n",node->ln_Name,Days);
      DOOR_WriteText(tmpstr);

      FileList(DIR_FORWARDS,node->ln_Name,Days,0);
    }
  }
}


void ReverseFileList( void )
{
  DOOR_WriteText("Look, how any times do I have to tell you that I've not bloody well\r\n"
                 "programmed this mode yet!!!!\r\n");
}


#define DIR_FORWARD 1
#define DIR_BACKWARD 2

BOOL GetData(ULONG Direction)
{
  LONG CurrentPos=0,seekval;
  BOOL retval=FALSE;

  BytesInBuffer=0;

  if (Direction == DIR_FORWARD)
  {
    BytesInBuffer=Read(FH,Buffer,BUFFERSIZE);
    retval=TRUE;
  }
  if (Direction == DIR_BACKWARD)
  {
    CurrentPos=Seek(FH,0,OFFSET_CURRENT);
    if (CurrentPos>=0)
    {
      if (CurrentPos-BUFFERSIZE < 0)
      {
        seekval=Seek(FH,0,OFFSET_BEGINNING);
      }
      else
      {
        seekval=Seek(FH,0-BUFFERSIZE,OFFSET_CURRENT);
      }
      if (seekval!=-1)
      {
        BytesInBuffer=Read(FH,Buffer,BUFFERSIZE);
        Seek(FH,seekval,OFFSET_BEGINNING); // and seek back again!
        retval=TRUE;
      }
    }
  }
  BufferOffset=0;
  return(retval);
}

void FileList(char *listname,ULONG Direction)
{
  BOOL Done=FALSE;
  int LinePos;
  char filename[BIG_STR];
  UBYTE LineBuffer[82];

  // *C* Copy File To Ram HERE and update FILENAME with the name of the file in ram:
  strcpy(filename,listname);

  DOOR_WriteText(ANSI_RESET);

  if (FL=Lock(filename,ACCESS_READ))
  {
    if (FH=OpenFromLock(FL))
    {
      if (Direction == DIR_BACKWARD)
      {
        // seek to EOF
        if (Seek(FH,0,OFFSET_END)==-1) Done=TRUE;
      }

      // Fetch some data to process..
      GetData();
      if (BytesInBuffer>0) // Got Some ?
      {
        LinesOutput=0;
        while ((N_ND->OnlineStatus==OS_ONLINE) && (!Done) && (!Quit))
        {
          // Ok, get a line of text, not exceeding more than 80 chars long.

          LinePos=0;
          while ((BytesInBuffer>0) && (Buffer[BufferOffset]!='\n') && (LinePos<=81))
          {
            LineBuffer[LinePos++]=Buffer[BufferOffset++];

            // Fetch More Data ?
            if (BufferOffset>=BytesInBuffer)
            {
              GetData();
            }
          }
          if (Buffer[BufferOffset]=='\n')
          {
            BufferOffset++;

            if (BufferOffset>=BytesInBuffer) GetData();
          }

          LineBuffer[LinePos]=0; // Null Terminate

          if (LineBuffer[0]) // Data To Check ?
          {
            PrintLine(LineBuffer);
          }
          if (LinesOutput>=N_ND->User.CallData.LinesPerScreen)
          {
            ScreenPausePrompt();
          }
          if (BytesInBuffer==0) Done=TRUE;
        }
      }
      Close(FH);
    }
    else
    {
      UnLock(FL);
      ErrorOpening();
    }
  }
  else
  ErrorOpening();

  DOOR_WriteText(ANSI_RESET "\r\n");
}

*/

void DisplayHelp( void )
{
  switch(Mode) // display different help depending on the mode!
  {
    case FLM_LIST:
      DOOR_WriteText("Supported options are:\r\n\r\n"
                     "T      [List]    - Scan Todays Files\r\n"
                     "S      [List]    - Scan since last call\r\n"
                     "<days> [List]    - Scan from <days> ago\r\n");
      break;
    case FLM_NEW:
      DOOR_WriteText("Supported options are:\r\n\r\n"
                     "T      [List]    - Scan Todays Files\r\n"
                     "S      [List]    - Scan since last call\r\n"
                     "<days> [List]    - Scan from <days> ago\r\n");
      break;
    case FLM_REVERSE:
      break;
  }
}

void stripCR(UBYTE *String)
{
  ULONG Len;
  if (String && (Len=strlen(String)))
  {
    Len--; // Len now = character index..

    while (Len && (String[Len]=='\r' || String[Len]=='\n'))
    {
      String[Len--]=0;
    }
  }
}

void PrintFileInfo(struct List *FileInfo)
{
  struct Node *node;

  if (FileInfo)
  {
    for (node=FileInfo->lh_Head;node->ln_Succ;node=node->ln_Succ)
    {
//      DOOR_WriteText(node->ln_Name);
//      DOOR_WriteText("\r\n");
      PrintLine(node->ln_Name);
    }
  }
}

struct List *GetFileInfo( void )
{
  UBYTE Buffer[255];
  struct List *FileInfo=NULL;

  BOOL Error=FALSE, Done=FALSE,KeepAdding=FALSE;

  if (FileInfo=HBBS_CreateList())
  {
    do
    {
      if (FGets(FH,Buffer,255))
      {
        stripCR(Buffer);
        switch(Buffer[0])
        {
          case 'F':
            KeepAdding=TRUE;
            // note: the lack of a "break" here!
          case 'T':
          case 'N':
          case 'I':
          case 'U':
          case 'C':
          case 'X':
          case 'P':
            if (KeepAdding)
            {
              if (NewStrNode(Buffer,FileInfo))
              {
                Error=TRUE;
              }
            }
            break;
          default:
            if (KeepAdding) Done=TRUE;
            break;


        }
      }
      else
      {
        // EOF ? or I/O Error ?

        if (IoErr()) Error=TRUE; else Done=TRUE;
      }
    } while (!Error && !Done);


    if (Error || !KeepAdding) // if keep adding is FALSE no lines have been added to the list!
    {
      FreeStrList(FileInfo);
      FileInfo=NULL;
    }
  }
  return(FileInfo);
}

ULONG NodesInList(struct List *list)
{
  struct Node *node;
  ULONG Nodes=0;
  if (FileInfo)
  {
    for (node=list->lh_Head;node->ln_Succ;node=node->ln_Succ)
    {
      Nodes++;
    }
  }
  return(0);
}


void ForwardList(UBYTE *filename)
{
  struct List *FileInfo=NULL;
  BOOL Done=FALSE;

  if (FL=Lock(filename,ACCESS_READ))
  {
    if (FH=OpenFromLock(FL))
    {
      LinesOutput=0;
      while (!Done && FileInfo=GetFileInfo())
      {
        if ((1 + LinesOutput + NodesInList(FileInfo)) > N_ND->User.CallData.LinesPerScreen )
        {
          Done=ScreenPausePrompt();
        }
        PrintFileInfo(FileInfo);
        FreeStrList(FileInfo);
      }
      Close(FH);
    }
    else
    {
      UnLock(FL);
    }
  }
}


void DoorMain( void )
{
  ULONG loop;
  LONG daysago;
  char datestr[LEN_DATESTR];
  ULONG listnum,tmpnum;
  struct Node *node;
  BOOL error=FALSE;

  if (N_ND->User.Acs.Data[ACS_SCANFILES]=='Y')
  {

    if ((listnum=N_ND->CurrentConf->FileLists)>0)
    {
      time(&todaytime);
      todaytr=localtime(&todaytime);

      if (iposition("NEW",N_ND->ActiveDoor->SystemOptions)>=0)
      {
        Mode=FLM_NEW;
      }
      if (iposition("REVERSE",N_ND->ActiveDoor->SystemOptions)>=0)
      {
        Mode=FLM_REVERSE;
      }
      if (iposition("LIST",N_ND->ActiveDoor->SystemOptions)>=0)
      {
        Mode=FLM_LIST;
      }

      fromtime=todaytime;

      if (gargc>=3)
      {
        switch(toupper(gargv[2][0]))
        {
          case '?':
            DisplayHelp();
            error=TRUE;
            break;
          case 'T':
            break;
          case 'S':
            fromtime=N_ND->User.CallData.LastCalledDate;
            break;
          default:

            // "-" is not allowed, "-<n>" and "<n>" are allowed

            if ( ((strlen(gargv[2])==1) && (isdigit(gargv[2][0]))) ||
                 ((strlen(gargv[2])>1 ) && ((gargv[2][0]=='-') || (isdigit(gargv[2][0])) )))
            {
              if (sscanf(gargv[2],"%ld",&daysago))
              {
                daysago=abs(daysago); // -2 is the same as 2 :-)
                fromtime-=(daysago*86400); // 60secs * 60mins * 24hours = 86400 = 1day
              }
            }
            else
            {
              DOOR_WriteText("Invalid 2nd parameter!\r\n");
            }
            break;

        }
        if (gargc>=4)
        {
          // user specified a file list to read from ?
          // other than the default one ?

          if (sscanf(gargv[3],"%ld",&tmpnum))
          {
            listnum=tmpnum;
          }
          else
          {
            // not a number of a file list, perhaps it's an option..
            // *C* do!
          }
        }

      }

      if (!error)
      {
        fromtr=localtime(&fromtime);

        if (fromtr->tm_mday<0) fromtr->tm_mday=0; // can't be less than 01-JAN-1970

        if (listnum>0 && listnum <=N_ND->CurrentConf->FileLists)
        {

          HBBS_GetDateStr(datestr,fromtime);

          node=GetNode(N_ND->CurrentConf->FileList,listnum-1);

          sprintf(outstr,"Searching for files from %s in list %s\r\n",datestr,FilePart(node->ln_Name));
          DOOR_WriteText(outstr);

          switch(Mode)
          {
            case FLM_NEW:
              ForwardList(node->ln_Name);
              break;
            case FLM_REVERSE:
              break;
            case FLM_LIST:
              break;
          }
        }
        else
        {
          DOOR_WriteText("Invalid file list number specified\r\n");
        }

        free(fromtr);
      }
      free(todaytr);
    }
    else
    {
      DOOR_WriteText("No files in this conference\r\n");
    }
  }
  else
  {
    DOOR_WriteText("Access Denied :-)\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("FileLister");

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