
/*

   Mail_Write.HBBS
   ===============

   Door for writing mail.


   todo
   ====

     default access level for public mail, when writing to ALL and EVERYBODY

*/

#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 <utility/date.h>
#include <resources/battclock.h>
#include <clib/battclock_protos.h>
#include <clib/utility_protos.h>

#include <HBBS/ANSI_Codes.h>
#include <HBBS/Defines.h>
#include <HBBS/types.h>
#include <HBBS/Access.h>
#include <HBBS/structures.h>
#include <HBBS/Hbbscommon_protos.h>
#ifdef __SASC
#include <HBBS/hbbscommon_pragmas_sas.h>
#else
#include <HBBS/hbbscommon_pragmas_stc.h>
#endif

#include <HBBS/Hbbsnode_protos.h>
#ifdef __SASC
#include <HBBS/Hbbsnode_pragmas_sas.h>
#else
#include <HBBS/Hbbsnode_pragmas_stc.h>
#endif
#include <HBBS/release.h>
char *versionstr="$VER: Mail_Write "RELEASE_STR;

#include "/Mail_Common.h"

struct Library *HBBSCommonBase=NULL;
struct Library *HBBSNodeBase=NULL;
struct Library *UtilityBase = NULL;
struct Library *BattClockBase; // dont need to close this so skip initialisation

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;

int startparam;

LONG __stack=16384;

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

#include "/maillib.i"

static VOID cleanup(ULONG num)
{
  if (UtilityBase) CloseLibrary(UtilityBase);

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

  if (!(UtilityBase = (struct Library *)OpenLibrary("utility.library",33)))
  {
    cleanup(5);
  }
  if (!(BattClockBase= OpenResource(BATTCLOCKNAME)))
  {
    cleanup(6);
  }

  SetProgramName(name);
}

void WriteMail(char mailtype)
{
  char FromHandle[1024];
  char ToHandles[1024];
  char ToIDS[1024];
  BOOL Cancel,Done;
  V_BIGNUM tempval;
  LONG loop;
  char tmphandle[50];
  char tmpmailfile[1024];
  char tmpid[50];
  char datestr[LEN_DATESTR+1],expirydate[LEN_DATESTR+1];
  char *NewMailSubject=NULL;
  int where;
  V_SMALLNUM NewMailType=MSGT_VOID;
  V_BIGNUM NewMailFlags=0;
  BOOL Flag,attachok;
  V_BIGNUM NewMailAccess=0,tmpnum;
  ULONG t;

  struct MailData *NewMail;

  // this bit handles the asking of the username.

  Cancel=FALSE;
  Done=FALSE;

  ToHandles[0]=0;
  strcpy(FromHandle,N_ND->User->CallData->Handle); // the user on-line..

  if (HBBS_CheckAccess(ACS_AUTOEXPIREMSG))
  {
    // get the time and add the default days to it, convert to str and let user edit!
    t=HBBS_GetAmigaTime();
    t+=MailSystemConfig.DefaultExpiryDays*86400; // seconds in a day...
    HBBS_GetDateString(expirydate,t);
  }
  else
  {
    expirydate[0]=0;
  } 
  
  DOOR_WriteText(ANSI_RESET);
  
  switch(mailtype)
  {
    case 'S':
      NewMailType=MSGT_SYSOP;
      DOOR_WriteText("Sysop Comment\r\n");
      break;
    case 'U':
      NewMailType=MSGT_PRIVATE;
      DOOR_WriteText("Private User Mail\r\n");
      break;
    case 'C':
      NewMailType=MSGT_CONFERENCE;
      DOOR_WriteText("Conference Mail\r\n");
      break;
    case 'P':
      NewMailType=MSGT_PUBLIC;
      DOOR_WriteText("Public Mail\r\n");
      break;
    case 'I':
      NewMailType=MSGT_INTERNET;
      DOOR_WriteText("Internet Mail\r\n");
      break;
    case 'F':
      NewMailType=MSGT_FIDONET;
      DOOR_WriteText("Fidonet Mail\r\n");
      break;
  }

  switch(mailtype)
  {
    case 'S':
      strcpy(ToHandles,BBSGlobal->SysopAccount);
      break;
    case 'U':
    case 'C':
    case 'P':
    case 'I':
    case 'F':
      if (gargc>=startparam)
      {
        for (loop=startparam-1;loop<gargc;loop++)
        {
          if (ToHandles[0]!=0) strcat(ToHandles," ");
          strcat(ToHandles,gargv[loop]);
        }
      }
      else
      { 
        if (mailtype=='C' || mailtype=='P')
        {
          sprintf(outstr,ANSI_RESET "%s%sEnter=ALL%s ", N_ND->BBSCols->MenuOpenBracket,N_ND->BBSCols->MenuDefaultOptANSI,N_ND->BBSCols->MenuCloseBracket);
        }
        else                                                                            
          outstr[0]=0;             
        
        sprintf(outstr+strlen(outstr),"%sTo%s",N_ND->BBSCols->MenuTextANSI,N_ND->BBSCols->MenuPromptANSI);
        DOOR_WriteText(outstr);

        DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_HISTORY,'\0',0,0,NULL);
        if (N_ND->OnlineStatus==OS_ONLINE)
        {          
          if (N_ND->CurrentLine[0])
          {
            strcpy(ToHandles,N_ND->CurrentLine);
          }
          else
          {
            strcpy(ToHandles,"ALL");
          } 
        }
        else Cancel=TRUE; // User Lost Carrier.
      }
      break;                                                               
  }
  
  if (!Cancel) DOOR_WriteText(ANSI_RESET);
  if (!Cancel && ToHandles[0])
  { 
    switch(mailtype)
    {
      case 'I': //internet
        // check for the format #?@#?.#?
        // also place the user's return internet address in FromHandle at this point *C*
        ToIDS[0]=0;
        break;
      case 'F': //fidonet
        // check for a correct fido address ( n/n:n.n )
        // also a return fido address needs to be placed in FromHandle *C*
        ToIDS[0]=0;
        break;
      case 'S':
      case 'U':
      case 'C':
      case 'P':
        // Got a user id, now lets check it..
        tempval=CheckUserIDs(ToHandles,ToHandles,ToIDS,TRUE,NewMailType,N_ND->CurrentConf ? N_ND->CurrentConf->ConfNum : 0);
        switch (tempval)
        {
          case CHCKID_OK:      // all valid
            Done=TRUE;
            break;
          case CHCKID_CANCEL:  // cancelled
            DOOR_WriteText("Cancelled!\r\n");
          case CHCKID_NC:      // lost carrier
            Cancel=TRUE;
            break;
        }
        break;
    }
  }

  if (!Cancel && Done)
  {
    // got some valid user names (in ToHandles) , a valid fromname (in FromHandle)
    // and all the user id numbers (in ToIDS) (if applicable)

    sprintf(outstr,ANSI_RESET "%sSubject%s",N_ND->BBSCols->MenuTextANSI,N_ND->BBSCols->MenuPromptANSI);
    DOOR_WriteText(outstr);
    DOOR_GetLine(GL_EDIT|GL_HISTORY|GL_DISPLAY,'\0',40,0,NULL);
    if (N_ND->OnlineStatus==OS_ONLINE)
    { 
      RemoveSpaces(N_ND->CurrentLine);
      if (N_ND->CurrentLine[0]==0)
      {
        DOOR_WriteText(ANSI_RESET "Cancelled!\r\n");
      }
      else
      {
        NewMailSubject=DupStr(N_ND->CurrentLine);

        if (NewMailType==MSGT_CONFERENCE || NewMailType==MSGT_PUBLIC)
        {
          // we can't write private mail to ALL or EVERYONE :-)

          if (!ToEALLType(ToHandles))
          {
            if (DOOR_ContinuePrompt(ANSI_RESET "Private ",DEFAULT_NO|DCP_ADDYN))
            {
              NewMailFlags+=MSGF_PRIVATE;
            }
          }
        }

        sprintf(tmpmailfile,"%sWork/NewMail.TXT",N_ND->NodeLocation);

        strcpy(outstr,tmpmailfile);
        strcat(outstr," MAIL");
        
        DOOR_SystemDoor("EDITOR",outstr);

        if (N_ND->OnlineStatus==OS_ONLINE)
        {
          if (iposition("CANCEL",N_ND->DoorReturn)>=0)
          {
            DOOR_WriteText(ANSI_RESET "Cancelled!\r\n");
            Cancel=TRUE;
          }
          else
          {
            Done=FALSE;
            attachok=FALSE;
            if (N_ND->User->Acs.Data[ACS_ATTACHFILES]=='Y')
            {
              if ((iposition("ALL",ToHandles)>=0) && (N_ND->User->Acs.Data[ACS_ALLOWALLFILES]=='Y'))
              {
                attachok=TRUE;
              }
              else
              {
                if (iposition("EVERYONE",ToHandles)>=0)
                {
                  if (N_ND->User->Acs.Data[ACS_ALLOWALLFILES]=='Y')
                  {
                    attachok=TRUE;
                  }
                  else attachok=FALSE;  // might be set to true if message is to ALL as well.. :-)
                }
                else
                {
                  // message must be to a user (or users)
                  // so allow attachments, enless otherwise..
                  attachok=TRUE;
                  if (N_ND->User->Acs.Data[ACS_ALLOWPRIVATEFILES]=='N' && NewMailFlags & MSGF_PRIVATE)
                  {
                    // otherwise :-)
                    attachok=FALSE;
                  }
                }
              }

              if ((iposition(",",ToHandles)>=0) && (N_ND->User->Acs.Data[ACS_ALLOWMULTIFILES]=='N'))
              {
                // not allowed to attach files to more than one person..
                attachok=FALSE;
              }
            }
            do
            {
              strcpy(N_ND->CharsAllowed,"AaEeDdQqSs");
              if (N_ND->User->CallData->Access>=250)
              {
                DOOR_MenuPrompt("Sysop Options : [M]ust Read, [N]o Delete, [R]emove Files\r\n",' ');
                strcat(N_ND->CharsAllowed,"MmNnRr");
              }

              if (attachok)
              {
                DOOR_MenuPrompt("[X]fer, ",' ');
                strcat(N_ND->CharsAllowed,"Xx");
              }

              DOOR_MenuPrompt("[A]ccess, [E]xpiry, Toggle Auto [D]elete, [Q]uit, [S]ave",'S');
              DOOR_WriteText(N_ND->BBSCols->MenuPromptANSI);
              DOOR_GetLine(GL_HISTORY|GL_EDIT|GL_DISPLAY|GL_USECHARS|GL_IMMEDIATE,'\0',1,0,NULL);
              if (N_ND->OnlineStatus==OS_ONLINE)
              {
                RemoveSpaces(N_ND->CurrentLine);

                if (N_ND->User->CallData->Access>=250) /* *C* make level configurable ? */
                {
                  // process co/sysop options first..

                  switch (toupper(N_ND->CurrentLine[0]))
                  {
                    case 'N': // no delete
                      if (NewMailFlags & MSGF_AUTODELETE)
                      {
                        DOOR_WriteText("Can't set NoDelete if AutoDelete is enabled!\r\n");
                      }
                      else
                      {
                        if (NewMailFlags & MSGF_NODELETE)
                        {
                          NewMailFlags-=MSGF_NODELETE;
                          DOOR_WriteText("Message may be deleted\r\n");
                        }
                        else
                        {
                          NewMailFlags+=MSGF_NODELETE;
                          DOOR_WriteText("Message can't be deleted (except by sysop)\r\n");
                        }
                      }
                      break;
                    case 'M': // must read
                      if (NewMailFlags & MSGF_MUSTREAD)
                      {
                        NewMailFlags-=MSGF_MUSTREAD;
                        DOOR_WriteText("Message can be skipped by mailscan\r\n");
                      }
                      else
                      {
                        NewMailFlags+=MSGF_MUSTREAD;
                        DOOR_WriteText("Message can NOT be skipped by mailscan\r\n");
                      }
                  }
                }
                // followed by user options.

                switch (toupper(N_ND->CurrentLine[0]))
                {
                  case 0:
                  case 'S':
                    Done=TRUE;
                    break;

                  case 'Q':
                    if (DOOR_ContinuePrompt("Are you sure you want to abort this message ? ",DEFAULT_NO|DCP_ADDYN))
                    {
                      Done=TRUE;
                      Cancel=TRUE;
                    }
                    break;

                  case 'E':
                    DOOR_WriteText("Enter Expiry Date (Blank for no expiry, or DD-MMM-YYYY!) > ");
                    DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_HISTORY,'\0',11,0,expirydate); // 12 chars, 0 timeout

                    if (N_ND->OnlineStatus==OS_ONLINE) // *C* check date format is valid and not in the past!
                    {
                      if (!N_ND->CurrentLine[0])
                      {
                        expirydate[0]=0;
                      }
                      else
                      {
                        if (strlen(N_ND->CurrentLine)==11)
                        {
                          strcpy(expirydate,N_ND->CurrentLine);
                        }
                      }
                    }

                    break;
                  case 'X':
                    if (attachok)
                    {
                      DOOR_WriteText("Not Implemented YET!\r\n");
                    }
                    break;

                  case 'D':
                    if (NewMailFlags & MSGF_NODELETE)
                    {
                      DOOR_WriteText("Can't set AutoDelete if NoDelete is enabled!\r\n");
                    }
                    else
                    {
                      if (ToEALLType(ToHandles))
                      {
                        DOOR_WriteText("Cant set autodelete on this type of message (ALL/EALL)\r\n");
                      }
                      else
                      {
                        if (NewMailFlags & MSGF_AUTODELETE)
                        {
                          NewMailFlags-=MSGF_AUTODELETE;
                          DOOR_WriteText("AutoDelete is now OFF\r\n");
                        }
                        else
                        {
                          NewMailFlags+=MSGF_AUTODELETE;
                          DOOR_WriteText("Message Will Self Destruct When Read!\r\n");
                        }
                      }
                    }
                    break;

                  case 'A':
                    strcpy(N_ND->CharsAllowed,"0123456789");
                    
                    sprintf(outstr,"%sSpecify Minimum Access Level%s",N_ND->BBSCols->MenuTextANSI,N_ND->BBSCols->MenuPromptANSI);
                    DOOR_WriteText(outstr);
                    
                    DOOR_GetLine(GL_HISTORY|GL_EDIT|GL_DISPLAY|GL_USECHARS,'\0',3,0,NULL);
                    if (N_ND->OnlineStatus==OS_OFFLINE)
                    {
                      Done=TRUE; //lost carrier.
                    }
                    else
                    {
                      Done=FALSE; // begin temporary use of variable
                      if (sscanf(N_ND->CurrentLine,"%ld",&tmpnum))
                      {
                        if (tmpnum>=0 && tmpnum<=255)
                        {
                          NewMailAccess=tmpnum;
                          Done=TRUE;
                        }
                      }
                      if (!Done)
                      {
                        DOOR_WriteText("Invalid access level, not changed\r\n");
                      }
                      Done=FALSE; // end temporary use of variable

                    }
                    break;
                }
              }
              else Done=TRUE;
            } while (!Done);

            if (Cancel)
            {
              // move attached files to HBBS:LostFiles
              DOOR_WriteText("Message Cancelled\r\n");
            }
            else
            {
              // now save the messages...

              Done=FALSE;
              do
              {
                where=position(",",ToHandles);
                if (where>0)
                {
                  strNcpy(tmphandle,ToHandles,where);
                  strftcpy(ToHandles,ToHandles,where+1,strlen(ToHandles));
                  if (ToHandles[0]==0) Done=TRUE;
                }
                else
                {
                  strcpy(tmphandle,ToHandles);
                  Done=TRUE;
                }

                where=position(",",ToIDS);
                if (where>0)
                {
                  strNcpy(tmpid,ToIDS,where);
                  strftcpy(ToIDS,ToIDS,where+1,strlen(ToIDS));
                }
                else
                {
                  strcpy(tmpid,ToIDS);
                }

                Flag=TRUE;
                if (NewMailType==MSGT_CONFERENCE)
                {
                  if (!(HBBS_CheckConfAccess(tmphandle,N_ND->CurrentConf->ConfNum)))
                  {
                     Flag=FALSE;
                     sprintf(outstr,"%s does not have access to this conference!\r\n",tmphandle);
                     DOOR_WriteText(outstr);
                  }
                }

                if (Flag)
                {
                  sprintf(outstr,"Saving Message to %s ",tmphandle);
                  DOOR_WriteText(outstr);

                  // format our mail structure and call PostNewMail()

                  if (NewMail=AllocVec(sizeof(struct MailData ),MEMF_PUBLIC|MEMF_CLEAR))
                  {
                    NewMail->Type=NewMailType;
                    NewMail->Subject=DupStr(NewMailSubject);

                    NewMail->From=DupStr(FromHandle);
                    NewMail->FromID=N_ND->User->CallData->UserID;

                    NewMail->To=DupStr(tmphandle);
                    sscanf(tmpid,"%d",&NewMail->ToID);

                    HBBS_GetDate(datestr);
                    NewMail->CreateDate=DupStr(datestr);

                    if (expirydate[0])
                    {
                      NewMail->ExpiryDate=DupStr(expirydate);
                    }
                    else
                    {
                      NewMail->ExpiryDate=DupStr("DD-MMM-YYYY");
                    }

                    NewMail->Flags=NewMailFlags;
                    NewMail->AttachedFiles=0;                 // *C* changeme too!
                    NewMail->AccessLevel=NewMailAccess;
                    NewMail->UserAccessLevel=N_ND->User->NormalData->Access; // note the user of NORMALDATA here..

                                             // confnum or 0
                    if (PostNewMail(NewMail,N_ND->CurrentConf ? N_ND->CurrentConf->ConfNum : 0,tmpmailfile))
                    {
                      N_ND->User->MsgsWritten++; //this call
                      N_ND->User->CallData->MessagesWritten++; //ever
                      N_ND->User->NormalData->MessagesWritten++;
                      N_ND->Actions[ACTN_WROTEMAIL]=ACTC_WROTEMAIL;

                    }
                    else
                    {
                      DOOR_WriteText("Failed!\r\n");
                    }

                    FreeMailMessage(NewMail);
                  }
                  DOOR_WriteText("\r[K");
                }
              } while (!Done);
              if (Done) DOOR_WriteText("Done!\r\n");
            }
          }

          if (Cancel)
          {
            DeleteFile(tmpmailfile);
          }
        }
        FreeStr(NewMailSubject);
      }
    }
  }
}

void DisplayHelp( void )
{
  DOOR_WriteText("Usage: E [<mailtype>] [<username,username,...>]\r\n"
                 "EG:  E U Hydra,Cruise\r\n"
                 "     E S\r\n"
                 "     E P <user>\r\n"
                 "     E C <user>\r\n"
                 "\r\nThis might default to conference mail if no mail type is selected.\r\n");
}

void DoorMain( void )
{

  BOOL Flag=FALSE;
  UBYTE MenuStr[BIG_STR];

  startparam=gargc;

  LoadMailSystemConfig();

  if (stricmp(N_ND->ActiveDoor->SystemOptions,"COMMENT")==0)
  {
    strcpy(N_ND->CurrentLine,"S");
    Flag=TRUE;
  }
  if (stricmp(N_ND->ActiveDoor->SystemOptions,"PUBLIC")==0)
  {
    strcpy(N_ND->CurrentLine,"P");
    Flag=TRUE;
  }
  if (stricmp(N_ND->ActiveDoor->SystemOptions,"CONFERENCE")==0)
  {
    strcpy(N_ND->CurrentLine,"C");
    Flag=TRUE;
  }
  if (stricmp(N_ND->ActiveDoor->SystemOptions,"USER")==0)
  {
    strcpy(N_ND->CurrentLine,"U");
    Flag=TRUE;
  }
  if (stricmp(N_ND->ActiveDoor->SystemOptions,"INTERNET")==0)
  {
    strcpy(N_ND->CurrentLine,"I");
    Flag=TRUE;
  }
  if (Flag)
  {
    startparam=3;
  }
  else
  {
    startparam=4; // the first param to use will be the bit after the mail type.. (i.e. the handles..)

    if (gargc>=3)
    {
      // put paramater 3 into the current line, then we can use the same routine to
      // check for both command line options and the user typing in a mail type
      strcpy(N_ND->CurrentLine,gargv[2]);
    }
    else
    {
      strcpy(N_ND->CharsAllowed,"SsUuPpCc");
      strcpy(MenuStr,"Type [S]ysop, ");

      if (MailSystemConfig.InternetMail)
      {
        strcat(MenuStr,"[I]nternet, ");
        strcat(N_ND->CharsAllowed,"Ii");
      }

      if (MailSystemConfig.FidoNetMail)
      {
        strcat(MenuStr,"[F]idonet, ");
        strcat(N_ND->CharsAllowed,"Ff");
      }

      strcat(MenuStr,"[U]ser, [P]ublic, [C]onference");
      strcat(MenuStr,N_ND->BBSCols->MenuPromptANSI);

      DOOR_MenuPrompt(MenuStr,'C');
      DOOR_GetLine(GL_EDIT|GL_DISPLAY|GL_USECHARS|GL_IMMEDIATE,'\0',1,0,NULL);
    }
  }

  if (N_ND->OnlineStatus==OS_ONLINE)
  {
    N_ND->CurrentLine[0]=toupper(N_ND->CurrentLine[0]);
    if (N_ND->CurrentLine[0]=='\0') N_ND->CurrentLine[0]='C';
    switch (N_ND->CurrentLine[0])
    {
      case 'S':
      case 'U':
      case 'C':
      case 'P':
      case 'I':
      case 'F':
        WriteMail(N_ND->CurrentLine[0]);
        break;
      default:
        DOOR_WriteText("Invalid Mail Type\r\n");
        DisplayHelp();
        break;
    }
  }

}

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

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