// --------------------------------------------------------------------
//        S c r i p t . c p p
//                                                                     
//        Layer for FICL.
// --------------------------------------------------------------------
//        Copyright (c) 1998-2000 by Fyodor Ustinov                         
//                                FIDONet 2:5020/79                      
//                                                                     
//        All rights reserved.                                         
// --------------------------------------------------------------------
//
// If you want to compile FTrack without script subsystem
//
// Check points 60*

#include "ficl.h"
#include "script.hpp"
#include "constant.hpp"
#include "vars.hpp"
#include "configure.hpp"

static cMSG *m = NULL;

void stackPushCStr(char *c) {
   if (c == NULL) {
      stackPushPtr(pVM->pStack,NULL); 
      stackPushUNS(pVM->pStack,0);
   } else {
      stackPushPtr(pVM->pStack,c); 
      stackPushUNS(pVM->pStack,strlen(c));
   }
}


// --------------------------------------------------------------------
//        Work with MSG
// --------------------------------------------------------------------

void CheckM(void) {
   if (m == NULL) {
      Log.Level(LOGE) << "Attempt of use of words like MSG.* in script before scandir." << EOL;
      exit(-1);
   }
}


static void fMsgFromAddr(FICL_VM *pVM) {
    CheckM();
    stackPushUNS(pVM->pStack, (UNS32)m->_FromAddr.Point());
    stackPushUNS(pVM->pStack, (UNS32)m->_FromAddr.Node());
    stackPushUNS(pVM->pStack, (UNS32)m->_FromAddr.Net());
    stackPushUNS(pVM->pStack, (UNS32)m->_FromAddr.Zone());
    return;
}

static void fMsgFromAddrA(FICL_VM *pVM) {
    CheckM();
    stackPushUNS(pVM->pStack, (UNS32)&m->_FromAddr);
    return;
}

static void fMsgToAddr(FICL_VM *pVM) {
    CheckM();
    stackPushUNS(pVM->pStack, (UNS32)m->_ToAddr.Point());
    stackPushUNS(pVM->pStack, (UNS32)m->_ToAddr.Node());
    stackPushUNS(pVM->pStack, (UNS32)m->_ToAddr.Net());
    stackPushUNS(pVM->pStack, (UNS32)m->_ToAddr.Zone());
    return;
}

static void fMsgToAddrA(FICL_VM *pVM) {
    CheckM();
    stackPushUNS(pVM->pStack, (UNS32)&m->_ToAddr);
    return;
}

static void fMsgFromName(FICL_VM *pVM) {
    CheckM();
    stackPushPtr(pVM->pStack,m->_FromName);
    stackPushUNS(pVM->pStack,strlen(m->_FromName));
    return;
}

static void fMsgToName(FICL_VM *pVM) {
    CheckM();
    stackPushPtr(pVM->pStack,m->_ToName);
    stackPushUNS(pVM->pStack,strlen(m->_ToName));
    return;
}

static void fMsgSubject(FICL_VM *pVM) {
    CheckM();
    stackPushPtr(pVM->pStack,m->_Subject);
    stackPushUNS(pVM->pStack,strlen(m->_Subject));
    return;
}

static void fMsgBody(FICL_VM *pVM) {
    CheckM();
    stackPushPtr(pVM->pStack,m->_Body);
    stackPushUNS(pVM->pStack,strlen(m->_Body));
    return;
}

static void fMsgLines(FICL_VM *pVM) {
    CheckM();
    stackPushUNS(pVM->pStack,m->Lines());
    return;
}

static void fMsgBytes(FICL_VM *pVM) {
   CheckM();
   stackPushUNS(pVM->pStack,m->Bytes());
   return;
}

static void fMsgKludgeBody(FICL_VM *pVM) {
IndBiList<Kludge>::ElemPtr Klu;
int KluNumber;

   CheckM();
   KluNumber = stackPopINT(pVM->pStack);

   Klu = m->_Klu.GetFirst();
   while (Klu != NULL && KluNumber != 0) {
      Klu++;
      KluNumber--;
   }
   if (Klu == NULL) {
      stackPushPtr(pVM->pStack,NULL);
      stackPushUNS(pVM->pStack,0);
   } else {
      stackPushCStr(Klu->Body());
   }
   return;
}

static void fMsgKludgeName(FICL_VM *pVM) {
IndBiList<Kludge>::ElemPtr Klu;
int KluNumber;

   CheckM();
   KluNumber = stackPopINT(pVM->pStack);

   Klu = m->_Klu.GetFirst();
   while (Klu != NULL && KluNumber != 0) {
      Klu++;
      KluNumber--;
   }
   if (Klu == NULL) {
      stackPushPtr(pVM->pStack,NULL);
      stackPushUNS(pVM->pStack,0);
   } else {
      stackPushCStr(Klu->Name());
   }
   return;
}

static void fMsgKludgeDelete(FICL_VM *pVM) {
IndBiList<Kludge>::ElemPtr Klu;
int KluNumber;

   CheckM();
   KluNumber = stackPopINT(pVM->pStack);

   Klu = m->_Klu.GetFirst();
   while (Klu != NULL && KluNumber != 0) {
      Klu++;
      KluNumber--;
   }
   if (Klu == NULL) {
      vmThrow(pVM,FTR_OUTOFRANGE);
   } else {
      m->_Klu.Remove(Klu);
   }
   return;
}

static void fMsgKludges(FICL_VM *pVM) {

   CheckM();
   stackPushUNS(pVM->pStack,m->_Klu.ElemCount());
   return;
}

static void fMsgLoopCount(FICL_VM *pVM) {
FICL_UNS count = stackPopUNS(pVM->pStack);
char *cp    = (char *)stackPopPtr(pVM->pStack);
char *tmt;

   CheckM();
   if (count == 0) {
      stackPushUNS(pVM->pStack,0);
      return;
   }
   tmt = (char *) malloc(count+1);
   CheckMem(tmt);
   strncpy(tmt,cp,count);
   tmt[count] = '\0';
   stackPushUNS(pVM->pStack,m->LoopCount(tmt));
   free(tmt);
   return;
}

static void fMsgAttachSize(FICL_VM *pVM) {
   CheckM();
   stackPushUNS(pVM->pStack,m->AttachSize());
   return;
}

static void fMsgWrite(FICL_VM *pVM) {
   CheckM();
   stackPushUNS(pVM->pStack,m->AttachSize());
   return;
}

int ScriptWordExists(char *word) {
FICL_WORD *WordExec;

   WordExec = ficlLookup(word);
   if (WordExec != NULL) return TRUE;
   else return FALSE;
}


// --------------------------------------------------------------------
//        Scandirs...
// --------------------------------------------------------------------

ScrRet DoThisWordRc(char *word) {
   return DoThisWord(word);
}

ScrRet  DoThisWord(char *word) {
FICL_WORD *WordExec;
int i;
   if (LogLevel >= 5) {
      Log.Level(LOGD) << "DoThisWord(\"" << word << "\");" << EOL;
   }
   WordExec = ficlLookup(word);
   if (WordExec != NULL) {
      if ((i = ficlExecXT(pVM,WordExec)) != VM_INNEREXIT) {
         Log.Level(LOGE) << "Error execution word '" << word << "' rc == " << i << EOL;
         return SS_ERROR;
      } else {
         return SS_OK;
      }
   } else {
      return SS_ERROR;
   }
}


void PrepareMsgForScript(cMSG &sm) {
   m = &sm;
}

void buildAddonsToFICL(void)
{
    ficlBuild("MSG.FromAddr",      fMsgFromAddr,      FW_DEFAULT);
    ficlBuild("MSG.FromAddrA",     fMsgFromAddrA,     FW_DEFAULT);
    ficlBuild("MSG.ToAddr",        fMsgToAddr,        FW_DEFAULT);
    ficlBuild("MSG.ToAddrA",       fMsgToAddrA,       FW_DEFAULT);
    ficlBuild("MSG.FromName",      fMsgFromName,      FW_DEFAULT);
    ficlBuild("MSG.ToName",        fMsgToName,        FW_DEFAULT);
    ficlBuild("MSG.Subject",       fMsgSubject,       FW_DEFAULT);
    ficlBuild("MSG.Body",          fMsgBody,          FW_DEFAULT);
    ficlBuild("MSG.Lines",         fMsgLines,         FW_DEFAULT);
    ficlBuild("MSG.Bytes",         fMsgBytes,         FW_DEFAULT);
    ficlBuild("MSG.Kludge.Name",   fMsgKludgeName,    FW_DEFAULT);
    ficlBuild("MSG.Kludge.Body",   fMsgKludgeBody,    FW_DEFAULT);
    ficlBuild("MSG.Kludge.Delete", fMsgKludgeDelete,  FW_DEFAULT);
    ficlBuild("MSG.Kludges",       fMsgKludges,       FW_DEFAULT);
    ficlBuild("MSG.LoopCount",     fMsgLoopCount,     FW_DEFAULT);
    ficlBuild("MSG.AttachSize",    fMsgAttachSize,    FW_DEFAULT);
    ficlBuild("MSG.Write",         fMsgWrite,         FW_DEFAULT);
    return;
}

int InitScriptSystem(void) {
   ficlInitSystem(FICL_SIZE);
   pVM = ficlNewVM();
   buildAddonsToFICL();
   return TRUE;
}

int StopScriptSystem(void) {
   ficlTermSystem();
   return TRUE;
}
int InitScriptValues(void) {
   return TRUE;
}

ScrRet DoSomeWord(char *word) {
	if (ScriptWordExists(word)) {
	   return DoThisWord(word);
   }
   return SS_NOTDEF;
}

ScrRet DoSomeWordRc(char *word) {
	if (ScriptWordExists(word)) {
	   return DoThisWordRc(word);
   }
   return SS_NOTDEF;
}


int _LoadScriptFile(char *fname) {
char Buff[MAXCFGLINE];
FILE *fh;
int LineNum;
char *tmt;


   LineNum = 0;
   Log.Level(LOGI) << "Load script file: '" << fname << "'." << EOL;
   fh = fopen(fname,"r");
   if (fh == NULL) {
      yyerror("Unable to open script file.");
      return (-1);
   }
   while(fgets(Buff,MAXCFGLINE,fh)) {
      LineNum++;
      while ((tmt = strrchr(Buff,'\n')) != NULL) *tmt = '\0';
      while ((tmt = strrchr(Buff,'\r')) != NULL) *tmt = '\0';
      if (strlen(Buff) == 0) continue;
      if (ficlExec(pVM, Buff) != VM_OUTOFTEXT) {
         sprintf(Buff,"Unable parsing script in line %d",LineNum);
         yyerror(Buff);
         fclose(fh);
         return (-1);
      }
   }
   ficlExec(pVM, "");
   fclose(fh);
   return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1