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

#include <dos/dos.h>
#include <exec/types.h>
#include <exec/memory.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.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 "maildoor.h"
#include "mailscan.h"
#include "mailread.h"

BOOL MAILSCAN_CheckConfIsValid( int confnum )
{
  struct ConfData *tmpconf;

  if (confnum>0 && confnum<=BBSGlobal->Conferences)
  {
    tmpconf=(struct ConfData *)GetNode(BBSGlobal->ConfList,confnum-1);

    if (tmpconf->ConfAccess>N_ND->User.CallData.Access)
      return(FALSE);
    else
      return(TRUE);
  }
  return( FALSE );
}

BOOL MAILSCAN_RequestStringFromFile( char *filename, char *buffer, int OffSet )
{
  struct CfgFileData *CfgFile;
  char *NewBuffer = NULL;

  MessageBaseError=0;

  if(CfgFile=HBBS_LoadConfig( filename ) )
  {
    switch( OffSet )
    {
      case MailSys_OFFSET_FirstMessage:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "First", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_LastMessage:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "Last", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageFrom:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "From", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageFor:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "For", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageForIDs:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "ForIDs", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageSubject:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "Subject", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageRead:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "Read", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageDownLoaded:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "Downloaded", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageFilesDL:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "FilesDL", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
      case MailSys_OFFSET_MessageNAttachedFiles:
        HBBS_GetSetting( CfgFile, (void *)&NewBuffer, VTYPE_STRING, "NAttached", OPT_SINGLE );
        strcpy( buffer, NewBuffer );
        break;
    }
    HBBS_FlushConfig( CfgFile );
  }
  return( TRUE );
}

int MAILSCAN_GetFirstMessage( int ConfNum )
{
  int n;
  char *filename, *buffer;
  struct Node *ConfPtr;

  filename = AllocVec( MAX_PATH_LENGTH, MEMF_CLEAR|MEMF_PUBLIC );
  buffer = AllocVec( BUFFER_LENGTH, MEMF_CLEAR|MEMF_PUBLIC );

  ConfPtr = GetNode( BBSGlobal->ConfList, ConfNum-1 );

  sprintf( filename, "%sMail/Mail.DAT\0", ((struct ConfData *)ConfPtr)->ConfPath );

  if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_FirstMessage))
  {
    stripcr( buffer );
    n = atoi( buffer );
  }
  else
    n=0;

  FreeVec( filename );
  FreeVec( buffer );

  return( n );
}

int MAILSCAN_GetLastMessage( int ConfNum )
{
  int n;
  char *filename, *buffer;
  struct Node *ConfPtr;

  filename = AllocVec( MAX_PATH_LENGTH, MEMF_CLEAR|MEMF_PUBLIC );
  buffer = AllocVec( BUFFER_LENGTH, MEMF_CLEAR|MEMF_PUBLIC );

  ConfPtr = GetNode( BBSGlobal->ConfList, ConfNum-1 );

  sprintf( filename, "%sMail/MAIL.DAT\0", ((struct ConfData *)ConfPtr)->ConfPath );

  if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_LastMessage))
  {
    stripcr( buffer );
    n = atoi( buffer );
  }
  else
    n=0;

  FreeVec( filename );
  FreeVec( buffer );

  return( n );
}


// Note : This routine also checks to see if the message is only for the user.
BOOL MAILSCAN_CheckMultiReaderMessage( V_BIGNUM UserID, char *UsersIDs )
{
  char str[BUFFER_LENGTH];
  int  count, i, n;
  V_BIGNUM CID;

  n = strlen( UsersIDs );

  for( count=0,i=0; count < n; count++,i++ )
    if( UsersIDs[count] != ',' ) str[i] = UsersIDs[count];
    else
    {
      str[i]=0;
      CID = atol( str );
      if( CID==UserID )  return( TRUE );
      else i=-1;
    }
  str[i]=0;
  CID = atol( str );
  if( CID == UserID )  return( TRUE );

  return( FALSE );
}

BOOL MAILSCAN_CreateList( V_STRINGLIST *TheList )
{
  if( *TheList = (struct List *)AllocVec( sizeof( struct List ), MEMF_CLEAR|MEMF_PUBLIC ))
  {
    NewList( *TheList );
    return( TRUE );
  }
  return( FALSE );
}

void MAILSCAN_NewListNode(struct List *NameVar , V_STRINGLIST list )
{
  struct Node *NewNode;

  if (NewNode=AllocVec(sizeof(struct Node),MEMF_PUBLIC))
  {
    NewNode->ln_Name = (char *)NameVar;
    AddTail(list,NewNode);
  }
}

void MAILSCAN_FreeListList( V_STRINGLIST listlist )
{
  struct Node *node;

  while (listlist->lh_Head->ln_Succ)
  {
    node=listlist->lh_Head;
    Remove(node);
    FreeVec(node);
  }
  FreeVec( listlist );
}

BOOL MAILSCAN_IsMessageForCurrentUser( char *filename )
{
  char buffer[BUFFER_LENGTH], buffer2[BUFFER_LENGTH];
  BOOL           AddMessageToList;

  MessageBaseError=0;

  if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageFor ))
  {
    if( MAILSCAN_RequestStringFromFile( filename, buffer2, MailSys_OFFSET_MessageForIDs ))
    {
      AddMessageToList = FALSE;
      stripcr( buffer );
      if( !(stricmp( buffer, "EAll" )))
      {
        //Message is an 'EAll'
        AddMessageToList = TRUE;
      }
      else
      {
        if( !(stricmp( buffer, "All" )))
        {
          //Message is an 'All'
          AddMessageToList = TRUE;
        }
        else
        {
          if( MAILSCAN_CheckMultiReaderMessage( N_ND->User.CallData.UserID, buffer2 ))
          {
            //Message is a MultiReader® Message
            AddMessageToList = TRUE;
          }
//        else
//        {
//          if( Don't know how to check for groups get!! )
//          {
//          }
//          else
//          {
//            if( Check HERE to see if message is public. )
//            {
//            }
//          }
//        }
        }
      }
    }
  }
  else MessageBaseError = MAILERROR_FileDoesNotExist;
  if( AddMessageToList ) return( TRUE );
  else return( FALSE );
}

V_STRINGLIST MAILSCAN_PrepareConfMessageList( int confnum )
{
  char           filename[MAX_PATH_LENGTH], outstr[BUFFER_LENGTH];
  V_STRINGLIST   ConfMessages=NULL;
  int            CurrentMessage, LastMessage;
  BOOL           AtLeastOne;
  struct Node   *ConfPtr;
  BPTR           lock;

  ConfPtr = GetNode( BBSGlobal->ConfList, confnum-1 );

  AtLeastOne = FALSE;
  ConfMessages = NULL;

  if( MAILSCAN_CreateList( &ConfMessages ) )
  {

    if( MAILSCAN_CheckConfIsValid( confnum ) )
    {
      CurrentMessage = MAILSCAN_GetFirstMessage( confnum );
      LastMessage = MAILSCAN_GetLastMessage( confnum );

      if( LastMessage != 0 )
      {
        while( CurrentMessage <= LastMessage )
        {
          sprintf( filename, "%sMail/Messages/%d.DAT\0", ((struct ConfData *)ConfPtr)->ConfPath, CurrentMessage );

          if( lock = Lock( filename, SHARED_LOCK ))
          {
            UnLock( lock );
            if( MAILSCAN_IsMessageForCurrentUser( filename ) )
            {
              AtLeastOne = TRUE;
              sprintf( outstr, "%d", CurrentMessage );
              NewStrNode( outstr, ConfMessages );
            }
/*C*/     }
          CurrentMessage++;
        }
      }
      if( AtLeastOne == FALSE )
        NewStrNode( "0", ConfMessages );
    }
    else
      NewStrNode( "-1", ConfMessages );
  }

  return( ConfMessages );
}

V_STRINGLIST MAILSCAN_PrepareMessageList( void )
{
  V_STRINGLIST   Messages=NULL;
  V_STRINGLIST   ConfMessages=NULL;
  int            loop;

  if( MAILSCAN_CreateList( &Messages ) )
  {
    for( loop=1; loop <= BBSGlobal->Conferences ; loop++ )
    {
      ConfMessages = MAILSCAN_PrepareConfMessageList( loop );

      MAILSCAN_NewListNode( ConfMessages , Messages );
    }
  }
  return( Messages );
}

struct MAIL_Message *MAILSCAN_CreateMailMsgStruct( int ConfNum, char *MessageNumber )
{
  char buffer[BUFFER_LENGTH], filename[MAX_PATH_LENGTH];
  struct MAIL_Message *NewMsg = NULL;
  struct Node *ConfPtr;
  BPTR lock;

  ConfPtr = GetNode( BBSGlobal->ConfList, ConfNum-1 );

  sprintf( filename, "%sMail/Messages/%s.DAT\0", ((struct ConfData *)ConfPtr)->ConfPath, MessageNumber );

  if( lock = Lock( filename, SHARED_LOCK ))
  {
    UnLock( lock );
    if( NewMsg = AllocVec( sizeof( struct MAIL_Message ), MEMF_PUBLIC|MEMF_CLEAR ))
    {

      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageFrom ))
      {
        stripcr( buffer );
        strcpy( NewMsg->MM_From, buffer );
      }
      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageFor ))
      {
        stripcr( buffer );
        strcpy( NewMsg->MM_For, buffer );
      }
      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageSubject ))
      {
        stripcr( buffer );
        strcpy( NewMsg->MM_Subject, buffer );
      }
      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageRead ))
      {
        stripcr( buffer );
        NewMsg->MM_Read = atoi( buffer );
      }
      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageFilesDL ))
      {
        stripcr( buffer );
        NewMsg->MM_FilesDL = atoi( buffer );
      }
      if( MAILSCAN_RequestStringFromFile( filename, buffer, MailSys_OFFSET_MessageNAttachedFiles ))
      {
        stripcr( buffer );
        NewMsg->MM_NAttachedFiles = atoi( buffer );
      }
    }
  }
  else
  {
    return( NULL );
  }
  return( NewMsg );
}

void MAILSCAN_DisplayFullBackLine( char *AnsiBack )
{
  char outstr[BUFFER_LENGTH];

  sprintf( outstr, "%s                                                                                \r\n"ANSI_BG_BLACK, AnsiBack );
  DOOR_WriteText( outstr );
}

BOOL MAILSCAN_ShowMessagesAvailableToUser( struct Node *MessListPtr, int ConfNum )
{
  struct Node *ptr2;
  char outstr[BUFFER_LENGTH];
  int n;

  struct MAIL_Message *Mess;

  if( !( stricmp( ((struct List *)MessListPtr->ln_Name)->lh_Head->ln_Name, "0" )))
  {
    sprintf( outstr, "  "ANSI_FG_CYAN"No messages for you in this conference.\r\n" );
    DOOR_WriteText( outstr );
    return( FALSE );
  }
  else
  {
    DOOR_WriteText( "   "ANSI_FG_YELLOW"#    "ANSI_FG_CYAN"Read#   "ANSI_FG_GREEN"From                 "ANSI_FG_PURPLE"Subject"ANSI_FG_WHITE"\r\n" );
    DOOR_WriteText( ANSI_FG_WHITE" ----- ------- -------------------- ------------------------------------------- \r\n" );

    for( ptr2 = ((struct List *)MessListPtr->ln_Name)->lh_Head; ptr2->ln_Succ; ptr2 = ptr2->ln_Succ )
    {
      n = atoi( ptr2->ln_Name );
      if( Mess = MAILSCAN_CreateMailMsgStruct( ConfNum, ptr2->ln_Name ))
      {
        sprintf( outstr, ANSI_FG_WHITE"|"ANSI_FG_YELLOW"%05d"ANSI_FG_WHITE"|"ANSI_FG_CYAN"%7d"ANSI_FG_WHITE"|"ANSI_FG_GREEN"%-20s"ANSI_FG_WHITE"|"ANSI_FG_PURPLE"%-43s"ANSI_FG_WHITE"|\r\n", n, Mess->MM_Read, Mess->MM_From, Mess->MM_Subject );
        DOOR_WriteText( outstr );
        FreeVec( Mess );
      }
    }
    DOOR_WriteText( ANSI_FG_WHITE" ----- ------- -------------------- ------------------------------------------- \r\n" );
  }
  return( TRUE );
}

void MYDOOR_DoMailScan( int argc, char *argv[] )
{
  V_STRINGLIST Messages = NULL;
  struct Node *ptr1, *ConfPtr;
  int confnum=0;
  char outstr[BUFFER_LENGTH];
  BOOL DoAgain,Done=FALSE;

  MYDOOR_DisplayTecLisMailHeader();

  if( Messages = MAILSCAN_PrepareMessageList() )
  {
    for( ptr1 = Messages->lh_Head, (ConfPtr = BBSGlobal->ConfList->lh_Head) ; (ptr1->ln_Succ) && (N_ND->OnlineStatus==OS_ONLINE) && !Done; ptr1 = ptr1->ln_Succ, ConfPtr = ConfPtr->ln_Succ )
    {
      confnum++;

      if( stricmp( ((struct List *)ptr1->ln_Name)->lh_Head->ln_Name, "-1" ))
      {
        sprintf( outstr, ANSI_FG_PURPLE"Messages for you in %s"ANSI_FG_WHITE"\r\n", ConfPtr->ln_Name );
        DOOR_WriteText( outstr );

        if( (MAILSCAN_ShowMessagesAvailableToUser( ptr1 , confnum )) )
        {
          sprintf( outstr, "\r\n"ANSI_FG_GREEN"Options :- "ANSI_FG_YELLOW"(N Q "ANSI_FG_WHITE"Y"ANSI_FG_YELLOW" Z ?)"ANSI_FG_WHITE" :");
          DoAgain = TRUE;
          while( DoAgain )
          {
            DOOR_WriteText( outstr );
            DOOR_GetLine( TRUE, TRUE, 0 );
            if( N_ND->OnlineStatus==OS_ONLINE )
            {
              if( !(stricmp( N_ND->CurrentLine, "Z" )))
              {
                DOOR_WriteText( "        --  Zoom Door Requested!\r\n" );
              }
              else
              {
                if( !(stricmp( N_ND->CurrentLine, "?" )))
                {
                  DOOR_WriteText( "\r\n" );
                  DOOR_WriteText( "Y, <CR> - Read Messages\r\n" );
                  DOOR_WriteText( "N       - Don't Read Messages\r\n" );
                  DOOR_WriteText( "Z       - Launch Zoom Door\r\n" );
                  DOOR_WriteText( "?       - Display Help\r\n" );
                  DOOR_WriteText( "Q       - Quit To MainScan\r\n" );
                  DOOR_WriteText( "\r\n" );

                }
                else
                {
                  if( (!(N_ND->CurrentLine[0]) || (!(stricmp( N_ND->CurrentLine, "Y" )))))
                  {
                    MAILREAD_ReadMessages( (struct List *)ptr1->ln_Name, confnum );
                    DoAgain = FALSE;
                  }
                  else
                  {
                    if( !(stricmp( N_ND->CurrentLine, "N" )))
                    {
                      sprintf( outstr, "%s                                                                \r\n%s", ANSI_UP, ANSI_UP );
                      DOOR_WriteText( outstr );
                      DoAgain = FALSE;
                    }
                    else
                    {
                      if( !(stricmp( N_ND->CurrentLine, "Q" )))
                      {
                        DoAgain=FALSE;
                        Done=TRUE;
                      }
                      else
                      {
                        DOOR_WriteText(ANSI_FG_RED"INVALID RESPONCE!"ANSI_FG_WHITE);
                      }
                    }
                  }
                }
              }
            }
            else
            {
              DoAgain = FALSE;
              Done = TRUE;
            }
          }
        }
//      else
//      {
//        MAILSCAN_DisplayFullBackLine( ANSI_BG_BLUE );
//      }
      }
    }
    DOOR_WriteText( "\r\n" );

    for( ptr1 = Messages->lh_Head; ptr1->ln_Succ; ptr1 = ptr1->ln_Succ )
      FreeStrList( (struct List *)ptr1->ln_Name );
    MAILSCAN_FreeListList( Messages );
  }
  else
  {
    DOOR_WriteText( "Problems with Message Base!\r\n" );
  }
}
