
/*

   Mail_Scan.HBBS
   ==============

   Door for scanning new mail.


   ideas
   -----
     copy mail to another user
     forward mail to another user
     allow editing of header (from, to etc..)


   todo
   ----

   create a savemsglist() and loadmsg() list

   put routines into a shared lib.


*/

#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 <HBBS/ANSI_Codes.h>
#include <HBBS/Defines.h>
#include <HBBS/access.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: Mail_Scan "RELEASE_STR;

#include "/Mail_Common.h"


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

struct BBSGlobalData *BBSGlobal=NULL;
struct NodeData *N_ND=NULL;
int N_NodeNum=-1;
char outstr[1024]; // temp string for displaying text..

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

LONG __stack=16384;

BOOL LoginMode=FALSE;
struct List *MsgList=NULL;
struct List *MustReadMsgList=NULL;
V_BIGNUM Msgs=0,MustReadMsgs=0;
struct MsgNode *ListNode=NULL;

#include "/maillib.i"

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

#define SCAN_ALL          0
#define SCAN_PUBLIC       1
#define SCAN_USER         2
#define SCAN_CURRENTCONF  3
#define SCAN_SYSOP        4
#define SCAN_ALLCONFS     5
#define SCAN_ACONF        6

struct ScanData
{
  struct Node node;
  LONG LastScanNum;
};

void UpdateScanPointers(struct List *MsgList)
{
  // ooh, no here's a complicated routine! :-)
  // basically we have to determine from a list of messages
  // which ones are the last ones of a type of message
  // and then update the last scanned pointers to match!

  struct MsgNode *ListNode=NULL;
  V_SMALLNUM LastType=MSGT_VOID;
  V_SMALLNUM LastConf=0;
  V_BIGNUM LastNum=0;

  struct List *ScanList;
  struct ScanData *ScanNode;
  LONG loop;

  LONG LastScan[MSGTYPES];

  // create a list with the same amount of nodes as conferences..

  if (ScanList=HBBS_CreateList())
  {
    for (loop=0;loop<BBSGlobal->Conferences;loop++)
    {
      if (ScanNode=(struct ScanData*)HBBS_CreateNode(NULL,sizeof(struct ScanData)))
      {
        ScanNode->LastScanNum=0;
        AddTail(ScanList,(struct Node*)ScanNode);
      }
    }

    for (loop=1;loop<MSGTYPES;loop++) LastScan[loop]=0;

    if (HBBS_NodesInList(ScanList)==BBSGlobal->Conferences)
    {
      for (ListNode=(struct MsgNode *)MsgList->lh_Head ; ListNode->node.ln_Succ ; ListNode=(struct MsgNode*)ListNode->node.ln_Succ)
      {
        if ((LastType!=ListNode->Type) || (LastType==MSGT_CONFERENCE && LastConf != ListNode->ConfNum))
        {
          switch(LastType)
          {
            case MSGT_PUBLIC:
            case MSGT_SYSOP:
            case MSGT_PRIVATE:
            case MSGT_FIDONET:
            case MSGT_INTERNET:
              if (LastNum>LastScan[LastType]) LastScan[LastType]=LastNum;
              break;

            case MSGT_CONFERENCE:
              ScanNode=(struct ScanData *)GetNode(ScanList,LastConf-1); // index start = 0 hence -1
              ScanNode->LastScanNum=LastNum;
              break;
          }
          LastType=ListNode->Type;
          LastConf=ListNode->ConfNum;
        }
        LastNum=ListNode->Number;
      }
      // do this bit again, as the last one in the list won't get caught above..
      switch(LastType)
      {
        case MSGT_PUBLIC:
        case MSGT_SYSOP:
        case MSGT_PRIVATE:
        case MSGT_FIDONET:
        case MSGT_INTERNET:
          if (LastNum>LastScan[LastType]) LastScan[LastType]=LastNum;
          break;

        case MSGT_CONFERENCE:
          ScanNode=(struct ScanData *)GetNode(ScanList,LastConf-1); // index start = 0 hence -1
          ScanNode->LastScanNum=LastNum;
          break;

      }


      for (loop=1;loop<MSGTYPES;loop++)
      {
        switch(loop)
        {
          case MSGT_PUBLIC:
          case MSGT_SYSOP:
          case MSGT_PRIVATE:
            SaveLastScanned(loop,0,LastScan[loop]);
            break;
        }
      }
      for (loop=0;loop<BBSGlobal->Conferences;loop++)
      {
        ScanNode=(struct ScanData *)GetNode(ScanList,loop); // index start = 0 hence -1
        SaveLastScanned(MSGT_CONFERENCE,loop+1,ScanNode->LastScanNum);
      }
    }
    FreeStrList(ScanList);
  }
}

void DisplayHeaders(struct List *MsgList)
{
  V_BIGNUM ListNum=0;
  V_SMALLNUM LastType=MSGT_VOID;
  V_SMALLNUM LastConf=0,loop;
//  char tmpstr[1024];
  struct MsgNode *ListNode=NULL;

  DOOR_WriteText(ANSI_RESET ANSI_CLS);

  DOOR_DisplaySpecialScreen("BANNER_TOP");
  for (ListNode=(struct MsgNode *)MsgList->lh_Head ; ListNode->node.ln_Succ ; ListNode=(struct MsgNode*)ListNode->node.ln_Succ)
  {
    if ((LastType!=ListNode->Type) || (LastType==MSGT_CONFERENCE && LastConf != ListNode->ConfNum))
    {
      LastType=ListNode->Type;
      LastConf=ListNode->ConfNum;
      DOOR_WriteText(ANSI_RESET ANSI_FG_BLUE "----"ANSI_FG_CYAN"-"ANSI_FG_WHITE"- " ANSI_FG_YELLOW);
      switch(LastType)
      {
        case MSGT_SYSOP:
          strcpy(outstr,"Sysop");
          break;
        case MSGT_CONFERENCE:
          strcpy(outstr,HBBS_ListName(BBSGlobal->ConfList,ListNode->ConfNum-1)); // index starts at 0
          break;
        case MSGT_PRIVATE:
          strcpy(outstr,"Private");
          break;
        case MSGT_PUBLIC:
          strcpy(outstr,"Public");
          break;

      }
      strcat(outstr," Mail "ANSI_FG_WHITE "-" ANSI_FG_CYAN "-" ANSI_FG_BLUE);
      for (loop=strlen(outstr);loop<87;loop++) // 87 to compensate for the ansi control sequences
      {
        outstr[loop]='-';
      }
      outstr[loop]='\0';
      strcat(outstr,"\r\n");

      DOOR_WriteText(outstr);
    }

    sprintf(outstr,ANSI_RESET "%s" ANSI_FG_WHITE "%2d) " ANSI_FG_CYAN "From "ANSI_FG_BLUE ": " ANSI_FG_WHITE "%-17.17s " ANSI_FG_CYAN "Subject "ANSI_FG_BLUE": " ANSI_FG_WHITE "%-38.38s",(ListNode->Flags & MSGF_MUSTREAD) ? ANSI_BOLD : "",ListNum,ListNode->From,ListNode->node.ln_Name);
    if (ListNode->ReadIt)
    {
      strcat(outstr,ANSI_FG_YELLOW "R");
    }
    else
    {
      strcat(outstr," ");
    }
    if (ListNode->Flags & MSGF_PRIVATE)
    {
      strcat(outstr,ANSI_FG_YELLOW "P");
    }
    strcat(outstr,ANSI_RESET "\r\n");
    DOOR_WriteText(outstr);

    ListNum++;
  }
  DOOR_DisplaySpecialScreen("BANNER_BOT");
}

V_BIGNUM LoadUnreadList(struct List **MsgList)
{
  char tmpfilename[1024];

  sprintf(tmpfilename,"HBBS:Mail/Users/%ld/UnreadList.CFG",N_ND->User->CallData->UserID);
  return(LoadMsgList(MsgList,tmpfilename));

  // *C* URGENT, all nodes in list must be validated!!! i.e. check msg is still to you, still exists etc...
}


void SaveUnreadList(struct List *MsgList)
{
  char tmpfilename[1024];

  if (!MsgList) return;

  sprintf(tmpfilename,"HBBS:Mail/Users/%ld/UnreadList.CFG",N_ND->User->CallData->UserID);
  SaveMsgList(MsgList,tmpfilename,SML_UNREAD);
}

struct MsgNode *FindMsgNode(struct List *list,V_BIGNUM M_Number,V_BIGNUM M_Type,V_BIGNUM M_ConfNum)
{
  struct MsgNode *ListNode=NULL;

  for (ListNode=(struct MsgNode *)list->lh_Head ; ListNode->node.ln_Succ ; ListNode=(struct MsgNode*)ListNode->node.ln_Succ)
  {
    if ((ListNode->Number == M_Number) && (ListNode->Type == M_Type) && (ListNode->ConfNum == M_ConfNum))
    {
      return(ListNode);
    }
  }
  return(NULL);
}

void PromptUser( void )
{
  char tmpfilename[1024],tmpstr[1024];
  LONG num=-1;
  BOOL Done=FALSE,First=TRUE,KeepFlag=FALSE;
  struct MsgNode *ListNode=NULL,*TmpNode,*TmpNode2;
  char menuprompt[1024];

  DisplayHeaders(MsgList);
  do
  {
//    sprintf(outstr,ANSI_RESET ANSI_FG_YELLOW"[%s"ANSI_FG_WHITE"R"ANSI_RESET ANSI_FG_YELLOW"]"ANSI_FG_WHITE"ead All, "ANSI_FG_YELLOW"[%s"ANSI_FG_WHITE"Q"ANSI_RESET ANSI_FG_YELLOW"]"ANSI_FG_WHITE"uit, "ANSI_FG_YELLOW"["ANSI_FG_WHITE"L"ANSI_FG_YELLOW"]"ANSI_FG_WHITE"ist again, "ANSI_FG_YELLOW"["ANSI_FG_WHITE"M"ANSI_FG_YELLOW"]"ANSI_FG_WHITE"ark all as read, or # of message >",First ? ANSI_BOLD : "",!First ? ANSI_BOLD : "");
//    DOOR_WriteText(outstr);

    strcpy(N_ND->CharsAllowed,"AaSsLl0123456789");

    strcpy(menuprompt,"[A]ll, [L]ist again, [S]et as read");

    if (MustReadMsgs)
    {
      strcat(menuprompt,", [R]equired");
      strcat(N_ND->CharsAllowed,"Rr");
    }
    else
    {
      strcat(menuprompt,", [Q]uit");
      strcat(N_ND->CharsAllowed,"Qq");
    }

    strcat(menuprompt,", or # of message >");

    DOOR_MenuPrompt(menuprompt,First ? 'A' : MustReadMsgs ? 'R' : 'Q');

    DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_USECHARS,'\0',0,0,NULL);
    if (N_ND->OnlineStatus==OS_ONLINE)
    {
      RemoveSpaces(N_ND->CurrentLine); // strip leading/trailing spaces..

      if (N_ND->CurrentLine[0]==0)
      {
        /*
        if (First)
          N_ND->CurrentLine[0]='A'; // read all unread messages
        else
          if (MustReadMsgs)
            N_ND->CurrentLine[0]='R'; // read required messages
          else
            N_ND->CurrentLine[0]='Q'; // skip them
        */

        N_ND->CurrentLine[0]=First ? 'A' : MustReadMsgs ? 'R' : 'Q';
        N_ND->CurrentLine[1]=0; // null terminate
      }

      if (sscanf(N_ND->CurrentLine,"%d",&num))
      {
        if (num>=0 && num<HBBS_NodesInList(MsgList))
        {
          ListNode=(struct MsgNode *)GetNode(MsgList,num);

          // msgnum, type, confnum
          sprintf(tmpstr,"MSG %d %d %d UPDATESCAN MAILSCAN%s",ListNode->Number,ListNode->Type,ListNode->ConfNum,MustReadMsgs ? "NOQUIT" : "");
          DOOR_SystemDoor("MailRead",tmpstr);

          if (iposition("KEEP",N_ND->DoorReturn) >= 0)
          {
            KeepFlag = TRUE;
            DOOR_PausePrompt("Message is to be kept");
          }
          else
          {
            KeepFlag = FALSE;
            ListNode->ReadIt=TRUE;
          }

          // remove the message from the mustread list if the message
          // is a mustread message, or if it is to be kept.

          if ((ListNode->Flags & MSGF_MUSTREAD) || (KeepFlag))
          {
            if (TmpNode = FindMsgNode(MustReadMsgList,ListNode->Number,ListNode->Type,ListNode->ConfNum))
            {
              FreeMsgListNode(MustReadMsgList,TmpNode);
              MustReadMsgs-=1;
            }

            // remove the mustread flag is the message is to be kept.
            if (ListNode->Flags & MSGF_MUSTREAD)
            {
              ListNode->Flags -= MSGF_MUSTREAD;
            }

          }


        }
      }
      else
      {
        switch (toupper(N_ND->CurrentLine[0]))
        {
          case 'A':
            sprintf(tmpfilename,"%sWork/MailTemp.DAT",N_ND->NodeLocation);
            if (SaveMsgList(MsgList,tmpfilename,SML_ALL))
            {
              FreeMsgList(MsgList);
              MsgList=NULL;

              sprintf(tmpstr,"MSGLIST %s SAVELIST MAILSCAN%s",tmpfilename,MustReadMsgs ? "NOQUIT" : "");
              DOOR_SystemDoor("MailRead",tmpstr);
              if (Msgs=LoadMsgList(&MsgList,tmpfilename))
              {
                if (N_ND->OnlineStatus==OS_ONLINE)
                {
                  UpdateScanPointers(MsgList);
                  SaveUnreadList(MsgList);
                }
              }
              DeleteFile(tmpfilename);
            }
            Done=TRUE;
            break;
          case 'R':

            // save the list of messages the user HAS to read
            sprintf(tmpfilename,"%sWork/MailTemp.DAT",N_ND->NodeLocation);
            if (SaveMsgList(MustReadMsgList,tmpfilename,SML_ALL))
            {
              // free the list

              FreeMsgList(MustReadMsgList);
              MustReadMsgList = NULL;

              // call the door, and tell the door to save the list again

              sprintf(tmpstr,"MSGLIST %s SAVELIST MAILSCAN NOQUIT",tmpfilename);
              DOOR_SystemDoor("MailRead",tmpstr);

              // then load the list back in again!
              if (N_ND->OnlineStatus==OS_ONLINE)
              {

                MustReadMsgs=LoadMsgList(&MustReadMsgList,tmpfilename);
                DeleteFile(tmpfilename);

                while (MustReadMsgList->lh_Head->ln_Succ)
                {
                  TmpNode=(struct MsgNode *)MustReadMsgList->lh_Head;

                  // load the list back in, check the list for read messages.
                  // remove the MSGF_MUSTREAD flag from the same message in the MsgList list.
                  // remove the message from this list.


                  if (TmpNode2 = FindMsgNode(MsgList,TmpNode->Number,TmpNode->Type,TmpNode->ConfNum))
                  {
                    if (TmpNode->ReadIt)
                    {
                      // the message has been read, so remove the mustread flag
                      // from the unread message list.

                      if (TmpNode2->Flags & MSGF_MUSTREAD)
                      {
                        TmpNode2->Flags -= MSGF_MUSTREAD;
                      }
                      TmpNode2->ReadIt = TRUE;
                    }
                    else
                    {
                      // was the message KEPT ? (read = FALSE & MSGF_MUSTREAD removed)
                      // if so, then remove the mustread flag from the unreadlist so
                      // that it can be skipped (as the user has actually read it!)

                      // note: if carrier was dropped before the message was read
                      // then the mustread flag would still be set, so we can tell
                      // if the user actually read the message before carrier
                      // was lost.

                      if (!(TmpNode->Flags & MSGF_MUSTREAD))
                      {
                        if (TmpNode2->Flags & MSGF_MUSTREAD)
                        {
                          TmpNode2->Flags -= MSGF_MUSTREAD;
                        }
                      }
                    }
                  }
                  FreeMsgListNode(MustReadMsgList,TmpNode);
                }

                UpdateScanPointers(MsgList);
                SaveUnreadList(MsgList);
              }

            }
            Done=TRUE;
            break;

          case 'Q':
            UpdateScanPointers(MsgList);
            SaveUnreadList(MsgList);
            Done=TRUE;
            break;

          case 'L':
            DisplayHeaders(MsgList);
            break;

          case 'S':
            // this lets the user skip all messages next time, except for the ones they are
            // required to read!


            // parse the message list and set the ReadIt flag on each message except messages
            // with the MSGF_MUSTREAD flag.
            for (TmpNode=(struct MsgNode *)MsgList->lh_Head ; TmpNode->node.ln_Succ ; TmpNode=(struct MsgNode*)TmpNode->node.ln_Succ)
            {
              if (!(TmpNode->Flags & MSGF_MUSTREAD))
              {
                TmpNode->ReadIt=TRUE;
              }
            }

            SaveUnreadList(MsgList);
            UpdateScanPointers(MsgList);
            break;
          default:
            DOOR_WriteText("Invalid Option!\r\n");
            break;

        }
      }
    }
    First=FALSE;
  } while (N_ND->OnlineStatus==OS_ONLINE && !Done);
}

BOOL ScanThisConference( struct ConfData *Conf)
{
  BOOL Result = FALSE;

  if (LoginMode)
  {
    if (Conf->AutoMailScan) Result = TRUE;
  }
  else
  {
    Result = TRUE; // default for now! *C* implement mailscan config.
  }
  return (Result);
}

void ScanMail(int ScanMode,ULONG ConfNum)
{
  V_BOOL ReadThem=TRUE;
  char ScanDir[1024];
  struct ConfData *Conf;

  struct MsgNode *ListNode;
  struct MsgNode *MustReadMsg;
  char donestr[]="\r[K"; // start of line, erase line    (hey, look closely, it says "rock"! :-)


  DOOR_DisplaySpecialScreen("Mail_SCAN");

  Msgs=0;

  Msgs+=LoadUnreadList(&MsgList);


  switch(ScanMode)
  {
    case SCAN_ALL: // BEGIN
    case SCAN_PUBLIC:

      DOOR_WriteText(ANSI_RESET ANSI_FG_CYAN "Scanning Public Mail ");
      Msgs+=CreateMsgList(MAILDIR_PUBLIC,&MsgList,TRUE,MSGT_PUBLIC,0);
      DOOR_WriteText(donestr);
      if (ScanMode!=SCAN_ALL) break;

    case SCAN_USER:
      if (N_ND->User->Valid)
      {
        DOOR_WriteText(ANSI_RESET ANSI_FG_WHITE "Scanning Your Private Mail ");
        sprintf(ScanDir,"%s%ld/",MAILDIR_USER,N_ND->User->CallData->UserID);
        Msgs+=CreateMsgList(ScanDir,&MsgList,TRUE,MSGT_PRIVATE,0);
        DOOR_WriteText(donestr);
      }
      if (ScanMode!=SCAN_ALL) break;

    case SCAN_ALLCONFS:
      if (BBSGlobal->Conferences)
      {
        for (Conf=(struct ConfData *)BBSGlobal->ConfList->lh_Head; Conf->node.ln_Succ ; Conf=(struct ConfData *)Conf->node.ln_Succ)
        {
          if (N_ND->User->CallData->Access>=Conf->ConfAccess)
          {
            if (ScanThisConference(Conf))
            {
              DOOR_WriteText(ANSI_RESET ANSI_FG_CYAN "Scanning for mail in the ");
              DOOR_WriteText(Conf->node.ln_Name);
              DOOR_WriteText(" Conference ");
              sprintf(ScanDir,"%sMail/",Conf->ConfPath);
              Msgs+=CreateMsgList(ScanDir,&MsgList,TRUE,MSGT_CONFERENCE,Conf->ConfNum);
              DOOR_WriteText(donestr);
            }
          }

        }
      }
      if (ScanMode!=SCAN_ALL) break;

    case SCAN_SYSOP:
      // is the user the sysop ?
      if (stricmp(N_ND->User->CallData->Handle,BBSGlobal->SysopAccount)==0)
      {
        DOOR_WriteText(ANSI_RESET ANSI_FG_BLUE "Scanning Sysop Mail ");
        Msgs+=CreateMsgList(MAILDIR_SYSOP,&MsgList,TRUE,MSGT_SYSOP,0);
        DOOR_WriteText(donestr);
      }
      break;

    // SCAN_ALL END!


    case SCAN_CURRENTCONF:
      if (N_ND->CurrentConf)
      {
        DOOR_WriteText(ANSI_RESET ANSI_FG_CYAN "Scanning for mail in the ");
        DOOR_WriteText(N_ND->CurrentConf->node.ln_Name);
        DOOR_WriteText(" Conference ");
        sprintf(ScanDir,"%sMail/",N_ND->CurrentConf->ConfPath);
        Msgs+=CreateMsgList(ScanDir,&MsgList,TRUE,MSGT_CONFERENCE,N_ND->CurrentConf->ConfNum);
        DOOR_WriteText(donestr);
      }
      break;

    case SCAN_ACONF:
      if (BBSGlobal->Conferences)
      {
        Conf=(struct ConfData *)GetNode(BBSGlobal->ConfList,ConfNum);
        if (N_ND->User->CallData->Access>=Conf->ConfAccess)
        {
          DOOR_WriteText(ANSI_RESET ANSI_FG_CYAN "Scanning for mail in the ");
          DOOR_WriteText(Conf->node.ln_Name);
          DOOR_WriteText(" Conference ");
          sprintf(ScanDir,"%sMail/",Conf->ConfPath);
          Msgs+=CreateMsgList(ScanDir,&MsgList,TRUE,MSGT_CONFERENCE,Conf->ConfNum);
          DOOR_WriteText(donestr);
        }
      }

  }

  DOOR_WriteText(ANSI_RESET);

  if (MsgList) // we've got a list to process!
  {
    if (Msgs)
    {
      /* create a list of MustRead messages */

      if (MustReadMsgList = HBBS_CreateList())
      {
        for (ListNode=(struct MsgNode *)MsgList->lh_Head ; ListNode->node.ln_Succ ; ListNode=(struct MsgNode*)ListNode->node.ln_Succ)
        {
          if (ListNode->Flags & MSGF_MUSTREAD)
          {
            if (MustReadMsg=CopyMsgNode(ListNode))
            {
              AddTail(MustReadMsgList,(struct Node*)MustReadMsg);
              MustReadMsgs+=1;
            }
          }
        }
      }

      if (MustReadMsgs)
      {
        DOOR_ContinuePrompt(ANSI_FG_YELLOW "There are messages that you are required to read! [Return]",DEFAULT_NONE|DCP_NODISPLAY|DCP_COLOURIZE);
      }
      else
      {
        if (LoginMode)
        {
          sprintf(outstr,ANSI_FG_YELLOW "Read your %d message%s now ? [Y/n] :",Msgs,Msgs == 1 ? "" : "s");
          ReadThem=DOOR_ContinuePrompt(outstr,DEFAULT_YES);
        }
      }

      if (ReadThem)
      {
        PromptUser();
      }
    }
    else
    {
      DOOR_WriteText(ANSI_RESET ANSI_FG_CYAN "There is no mail waiting!\r\n" ANSI_RESET );
      if (iposition("LOGIN",N_ND->ActiveDoor->SystemOptions)>=0)
      {
        DOOR_PausePrompt(NULL);
      }
    }
    if (MsgList) FreeMsgList(MsgList);
    if (MustReadMsgList) FreeMsgList(MustReadMsgList);
  }
}

void DisplayHelp( void )
{
  DOOR_WriteText("Mailscan Help!\r\n"
                 "Options:\r\n"
                 "        ?            -  This Screen\r\n"
                 "        A            -  Scan ALL mail\r\n"
                 "        C [ConfNum]  -  Scan mail in current confererence, or\r\n"
                 "                        specified conference\r\n"
                 "        P            -  Scan PUBLIC Mail\r\n");
  if (N_ND->User->CallData->Access>=250)
  {
    DOOR_WriteText("        S            -  Scan Sysop Mail\r\n");
  }
}

void DoorMain( void )
{
  ULONG ConfNum=0;

  if (iposition("LOGIN",N_ND->ActiveDoor->SystemOptions)>=0) LoginMode=TRUE;

  if (N_ND->OnlineStatus==OS_ONLINE)
  {
    if (gargc>=3)
    {
      if (stricmp(gargv[2],"CFG")==0)
      {
        DOOR_WriteText("There are currently no configuration options!\r\n");
        DOOR_PausePrompt(NULL);
      }
      else
      {
        switch(toupper(gargv[2][0]))
        {
          case '?':
            DisplayHelp();
            break;
          case 'A':
            ScanMail(SCAN_ALL,0);
            break;
          case 'C':
            if (gargc>=4)
            {
              if (sscanf(gargv[3],"%ld",&ConfNum))
              {
                if (ValidConfNum(ConfNum))
                {
                  ScanMail(SCAN_ACONF,ConfNum-1); //offset at 0!
                }
                else
                {
                  DOOR_WriteText("Invalid Conference Number!\r\n");
                }
              }
            }
            else
            {
              ScanMail(SCAN_CURRENTCONF,0);
            }
            break;
          case 'P':
            ScanMail(SCAN_PUBLIC,0);
            break;
          case 'S':
            if (N_ND->User->CallData->Access>=250)
            {
              ScanMail(SCAN_SYSOP,0);
              break;  // note the positioning of break;, if user has no access then they'll get the error message :-)
            }
          default:
            DOOR_WriteText("Unknown Mailscan Mode!\r\n");
            DisplayHelp();
            break;
        }
      }
    }
    else
    {
      // no command line params so scan all
      ScanMail(SCAN_ALL,0);
    }

  }
}

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("Scanning Mail");

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