#ifdef RCS
static char rcsid[]="$Id: fplrun.c,v 1.1.1.1 2000/11/13 02:42:42 holsta Exp $";
#endif
/******************************************************************************
 *                    Internetting Cooperating Programmers
 * ----------------------------------------------------------------------------
 *
 *  ____    PROJECT
 * |  _ \  __ _ _ __   ___ ___ _ __ 
 * | | | |/ _` | '_ \ / __/ _ \ '__|
 * | |_| | (_| | | | | (_|  __/ |   
 * |____/ \__,_|_| |_|\___\___|_|   the IRC bot
 *
 * All files in this archive are subject to the GNU General Public License.
 *
 * $Source: /cvsroot/dancer/dancer/src/fplrun.c,v $
 * $Revision: 1.1.1.1 $
 * $Date: 2000/11/13 02:42:42 $
 * $Author: holsta $
 * $State: Exp $
 * $Locker:  $
 *
 * ---------------------------------------------------------------------------
 *****************************************************************************/

#include "config.h"
#ifdef HAVE_LIBFPL

#include "FPL.h"
#include "FPL_protos.h"

#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "list.h"
#include "transfer.h"
#include "user.h"
#include "function.h"
#include "fplrun.h"

/* --- Global ----------------------------------------------------- */

extern char cmodes[], chanmodes[], ckey[], chankey[];
extern char channel[], nickname[], servername[];
extern char topic[], topicwho[];

extern bool botop;
extern int numGuests;
extern itemident *current;
extern itemguest *guestHead;
extern itemsplit *splitHead;
extern itemuser *userHead;

itemfpl *fplentry[RUN_LAST][2];

static void *fplkey = NULL; /* FPL anchored data */

itemfplcmd *fcmdHead = NULL;
itemtimefpl *timefplHead = NULL;
itemlabel *labelHead = NULL;

bool Cancel = FALSE; /* cancel the rest of the fpl chained invokes */

struct fpldata {
  char *label;
  runitem item;
};

struct fpldata fplcfg[] =
{
  {"action",        RUN_ACTION}, /* done */
  {"ctcppriv",      RUN_CTCPPRIV}, /* done */
  {"ctcppub",       RUN_CTCPPUB}, /* done */
  {"dcc",           RUN_DCC},
  {"init",          RUN_INIT},   /* done */
  {"input",         RUN_INPUT},
  {"invite",        RUN_INVITE}, /* done */
  {"join",          RUN_JOIN}, /* done */
  {"kick",          RUN_KICK}, /* done */
  {"kickbot",       RUN_KICKBOT}, /* done */
  {"leave",         RUN_LEAVE}, /* done */
  {"mode",          RUN_MODE},
  {"msg",           RUN_MSG},
  {"nick",          RUN_NICK}, /* done */
  {"numeric",       RUN_NUMERIC}, /* done */
  {"offmsg",        RUN_OFFMSG}, /* done */
  {"public",        RUN_PUBLIC}, /* done */
  {"signoff",       RUN_QUIT}, /* done */
  {"topic",         RUN_TOPIC}, /* done */

  {"send_action",   RUN_SEND_ACTION},
  {"send_dcc_chat", RUN_SEND_DCC_CHAT},
  {"send_msg",      RUN_SEND_MSG},
  {"send_notice",   RUN_SEND_NOTICE},
  {"send_public",   RUN_SEND_PUBLIC},

  {"connect",       RUN_CONNECT}, /* done */
  {"disconnect",    RUN_DISCONNECT}, /* done */
  {"error",         RUN_ERROR}, /* done */

  {"alertmode",     RUN_ALERTMODE},
  {"alert",         RUN_ALERT}, /* done */
  {"flood",         RUN_FLOOD},

  {"nethack",       RUN_NETHACK},
  {"netsplit",      RUN_NETSPLIT},
  {"nethead",       RUN_NETHEAD},
  {"netleave",      RUN_NETLEAVE},
  {"netjoin",       RUN_NETJOIN},
};


/* --- FPLAddItemReal --------------------------------------------- */

void FPLAddItemReal(runitem item, char which, char *prog, char *regex)
{
  itemfpl *f;

  snapshot;
  if (NULL == fplentry[item][(int)which]) {
    fplentry[item][(int)which] = NewList(itemfpl);
  }

  f = NewEntry(itemfpl);
  if (f) {
    InsertLast(fplentry[item][(int)which], f);
    f->prog = StrDuplicate(prog);
    f->regex = (regex && regex[0]) ? StrDuplicate(regex) : NULL;
  }
}

/* --- FreeLabel -------------------------------------------------- */

void FreeLabel(void *v)
{
  itemlabel *l;

  snapshot;
  l = (itemlabel *)v;
  if (l) {
    if (l->name)
      StrFree(l->name);
    if ((l->flags & LAB_STRING) && l->def.str)
      StrFree(l->def.str);
  }
}

/* --- LabelInit -------------------------------------------------- */

void LabelInit(void)
{
  snapshot;
  labelHead = NewList(itemlabel);
}

/* --- LabelCleanup ----------------------------------------------- */

void LabelCleanup(void)
{
  snapshot;
  DeleteList(labelHead, FreeLabel);
}

/* --- LabelFind -------------------------------------------------- */

itemlabel *LabelFind(char *name)
{
  itemlabel *l;

  snapshot;
  for (l = First(labelHead); l; l = Next(l)) {
    if (StrEqual(l->name, name))
      return l;
  }
  return NULL;
}

/* --- LabelRefine ------------------------------------------------ */

static void LabelRefine(itemuserlabel *ulhead, char *name, itemlabel *label)
{
  itemuserlabel *ul;

  snapshot;
  for (ul = First(ulhead); ul; ul = Next(ul)) {
    if (ul->name && StrEqual(ul->name, name)) {
      StrFree(ul->name);
      ul->name = NULL;

      ul->label = label;

      if (0 == (label->flags & LAB_STRING)) {
        if (ul->cont.str) {
          int val = atoi(ul->cont.str);
          StrFree(ul->cont.str);
          ul->cont.val = val;
        }
      }
    }
  }
}

/* --- LabelDefine ------------------------------------------------ */

int LabelDefine(char *name, int flags, void *def)
{
  itemguest *g;
  itemsplit *p;
  itemuser *u;
  itemlabel *l;

  snapshot;
  if (LabelFind(name))
    return 1;

  l = NewEntry(itemlabel);
  if (l) {
    InsertLast(labelHead, l);
    l->name = StrDuplicate(name);
    l->flags = flags;
    if (l->flags & LAB_STRING)
      l->def.str = StrDuplicate((char *)def);
    else
      l->def.val = (int)def;

    /*
     * We must now scan all users to see if they use this stuff properly.
     * (guests + users)
     */
    if (0 == (l->flags & LAB_SOLO)) {

      for (g = First(guestHead); g; g = Next(g))
        LabelRefine(g->ident->label, name, l);

      for (p = First(splitHead); p; p = Next(p))
        for (g = First(p->wholeft); g; g = Next(g))
          LabelRefine(g->ident->label, name, l);

      for (u = First(userHead); u; u = Next(u))
        LabelRefine(u->label, name, l);

    }
  }
  return 0;
}

/* --- FreeUserlabel ---------------------------------------------- */

void FreeUserlabel(void *v)
{
  itemuserlabel *ul;

  snapshot;
  ul = (itemuserlabel *)v;
  if (ul) {
    if (ul->name)
      StrFree(ul->name);
    if (ul->label && (ul->label->flags & LAB_STRING)) {
      if (ul->cont.str)
        StrFree(ul->cont.str);
    }
  }
}

/* --- UserlabelRead ---------------------------------------------- */

void UserlabelRead(char *name, itemuserlabel *ulhead)
{
  itemuserlabel *ul;
  itemlabel *l;

  snapshot;
  for (ul = First(ulhead); ul; ul = Next(ul)) {
    if (ul->label && StrEqual(ul->label->name, name))
      break;
  }

  if (ul) {
    if (ul->label->flags & LAB_STRING)
      fplSendTags(fplkey, FPLSEND_STRING, ul->cont.str, FPLSEND_DONE);
    else
      fplSendTags(fplkey, FPLSEND_INT, ul->cont.val, FPLSEND_DONE);
  }
  else {
    l = LabelFind(name);
    if (l) {
      if (l->flags & LAB_STRING)
        fplSendTags(fplkey, FPLSEND_STRING, l->def.str, FPLSEND_DONE);
      else
        fplSendTags(fplkey, FPLSEND_INT, l->def.val, FPLSEND_DONE);
    }
  }
}

/* --- UserlabelSet ----------------------------------------------- */

void UserlabelSet(char *name, void *set, int flags, itemuserlabel **ulhead)
{
  itemuserlabel *ul;
  itemlabel *l;

  snapshot;
  for (ul = First(*ulhead); ul; ul = Next(ul)) {
    if (ul->label && StrEqual(ul->label->name, name))
      break;
  }

  if (ul) {
    if (ul->label->flags & LAB_STRING) {
      if (ul->cont.str)
        StrFree(ul->cont.str);
      ul->cont.str = StrDuplicate((char *)set);
    }
    else
      ul->cont.val = (int)set;
  }
  else {
    if (NULL == *ulhead) {
      *ulhead = NewList(itemuserlabel);
    }

    ul = NewEntry(itemuserlabel);
    if (ul) {
      InsertLast(*ulhead, ul);

      l = LabelFind(name);
      if (l)
        ul->label = l;
      else
        ul->name = StrDuplicate(name);

      if (flags & LAB_STRING)
        ul->cont.str = StrDuplicate((char *)set);
      else
        ul->cont.val = (int)set;
    }
  }
}

/* --- fTimerInit ------------------------------------------------- */

void fTimerInit(void)
{
  snapshot;
  timefplHead = NewList(itemtimefpl);
}

/* --- fTimerAdd -------------------------------------------------- */

int fTimerAdd(int timeout, char *fpl)
{
  itemtimefpl *f;

  snapshot;
  f = NewEntry(itemtimefpl);
  if (f) {
    InsertLast(timefplHead, f);
    f->fpl = StrDuplicate(fpl);
    f->timeout = time(NULL) + timeout;
  }
  return (int)f;
}

/* --- FreefTimer ------------------------------------------------- */

void FreefTimer(void *v)
{
  itemtimefpl *f;

  snapshot;
  f = (itemtimefpl *)v;
  if (f) {
    if (f->fpl)
      StrFree(f->fpl);
  }
}

/* --- fTimerCheck ------------------------------------------------ */

int fTimerCheck(void)
{
  int now;
  itemtimefpl *f;

  snapshot;
  now = time(NULL);
  for (f = First(timefplHead); f; f = Next(f)) {
    if (f->timeout <= now) {
      fplrunner(f->fpl, "");
      DeleteEntry(timefplHead, f, FreefTimer); /* Removed */
      return 1;
    }
  }
  return 0;
}

/* --- fTimerCleanup ---------------------------------------------- */

void fTimerCleanup(void)
{
  snapshot;
  DeleteList(timefplHead, FreefTimer);
}

/* --- fTimerKill ------------------------------------------------- */

int fTimerKill(int i)
{
  int now;
  itemtimefpl *check;
  itemtimefpl *f;

  snapshot;
  now = time(NULL);
  check = (itemtimefpl *)i;

  for (f = First(timefplHead); f; f = Next(f)) {
    if (f == check) {
      now = f->timeout - now;
      DeleteEntry(timefplHead, f, FreefTimer); /* Removed */
      return now;
    }
  }
  return 0;
}

/* --- fCmdInit --------------------------------------------------- */

void fCmdInit(void)
{
  snapshot;
  fcmdHead = NewList(itemfplcmd);
}

/* --- fCmdAdd ---------------------------------------------------- */

/*
 * int CmdAdd(string name,   // name of new command, preferable specified in
 *                           // uppercase like the rest of the commands
 *                           //  NO, you can't add aliases to this one.
 *            int level,     // level required for use
 *            string syntax, // syntax string
 *            string help,   // help string
 *            string flags,  // flags as below
 *            string fpl)    // complete FPL program to run at invoke in full
 *                           // fpl-invoke style with %-support
 *
 * the flags are strings separated with a '|' letter. Available flags are:
 * showable  - Output can be redirected to another person
 * passwd    - Password protected
 * needcomma - Comma is part of argument, not argument seperator
 * public    - Command can be used in public
 *
 * Example:
 *
 * CmdAdd("TEST",
 *        10,
 *        "[nick]",
 *        "tests <nick>",
 *        "passwd|public",    // publicly available and require password
 *        "mytestfpl(%i);")); // this function must be exported prior to the
 *                            // invoke
 */

int fCmdAdd(char *name,
            int level,
            char *syntax,
            char *help,
            char *flags,
            char *fpl)
{
  itemfplcmd *f;

  snapshot;
  f = NewEntry(itemfplcmd);
  if (f) {
    InsertLast(fcmdHead, f);
    f->fpl = StrDuplicate(fpl);
    f->help = StrDuplicate(help);
    f->command.name = StrDuplicate(name);
    f->command.level = level;
    f->command.showable = StrSubstring(flags, "show")   ? TRUE : FALSE;
    f->command.needpass = StrSubstring(flags, "pass")   ? TRUE : FALSE;
    f->command.needcomma = StrSubstring(flags, "needc") ? TRUE : FALSE;
    f->command.public = StrSubstring(flags, "public")   ? TRUE : FALSE;
    f->command.syntax = StrDuplicate(syntax);
  }
  return 0;
}

/* --- FreefCmd --------------------------------------------------- */

void FreefCmd(void *v)
{
  itemfplcmd *f;

  snapshot;
  f = (itemfplcmd *)v;
  if (f) {
    if (f->fpl)
      StrFree(f->fpl);
    if (f->help)
      StrFree(f->help);
    if (f->command.name)
      StrFree(f->command.name);
    if (f->command.syntax)
      StrFree(f->command.syntax);
  }
}

/* --- fCmdCleanup ------------------------------------------------ */

void fCmdCleanup(void)
{
  snapshot;
  DeleteList(fcmdHead, FreefCmd);
}

/* --- fCmdFind --------------------------------------------------- */

itemfplcmd *fCmdFind(char *name)
{
  itemfplcmd *f;

  snapshot;
  for (f = First(fcmdHead); f; f = Next(f)) {
    if (StrEqual(f->command.name, name))
      return f;
  }
  return NULL;
}

/* --- fplinterface ----------------------------------------------- */

long fplinterface(struct fplArgument *arg)
{
  int retcode = 0;
  int flags;
  int *retpnt = NULL;
  itemident *ident;
  itemlabel *l;
  itemuserlabel **ul;

  snapshot;
  switch (arg->ID) {

    case FPR_ACTION:
      Action(arg->argv[0]);
      break;

    case FPR_CANCEL:
      retcode = Cancel;
      retpnt = &retcode;
      if (arg->argc)
        Cancel = (bool)((int)arg->argv[0]);
      else
        Cancel = TRUE;
      break;

    case FPR_CHANINFO:
      if (StrEqual((char *)arg->argv[0], "guests")) {
        retcode = numGuests;
        retpnt = &retcode;
      }
      else if (StrEqual((char *)arg->argv[0], "topic"))
        fplSendTags(fplkey, FPLSEND_STRING, topic, FPLSEND_DONE);
      else if (StrEqual((char *)arg->argv[0], "topicwho"))
        fplSendTags(fplkey, FPLSEND_STRING, topicwho, FPLSEND_DONE);
      break;

    case FPR_CMDADD:
      fCmdAdd(arg->argv[0], (int)arg->argv[1], arg->argv[2], arg->argv[3],
              arg->argv[4], arg->argv[5]);
      break;

    case FPR_CTIME:
      retcode = (int)time(0);
      retpnt = &retcode;
      break;

    case FPR_DO:
      WriteServer("%s", arg->argv[0]);
      break;

    case FPL_GENERAL_ERROR:
      {
        char buffer[FPL_ERRORMSG_LENGTH];
        char *name;
        int col;

        fplSendTags(fplkey,
                    FPLSEND_GETVIRLINE, &col,
                    FPLSEND_GETVIRFILE, &name,
                    FPLSEND_DONE);
        Logf(LOGDBUG, "[FPL] '%s' => Line %d in file \"%s\"\n",
             fplGetErrorMsg(fplkey, (long)arg->argv[0], buffer),
             col, name ? name : "unknown");
      }
      break;

    /* Not documented: */
    case FPR_GETUSER:
      retcode = User2ID((char *)arg->argv[0], (arg->argc > 1) ? arg->argv[1] : "");
      retpnt = &retcode;
      break;

    case FPR_HOOK:
      {
        char which = FPLRUN_PRE;
        int i;

        if (arg->argc > 3)
          which = StrEqual((char *)arg->argv[3], "post") ? FPLRUN_POST : FPLRUN_PRE;

        for (i = 0; i < sizeof(fplcfg)/sizeof(fplcfg[0]); i++) {
          if (StrEqual(fplcfg[i].label, (char *)arg->argv[0])) {  /* match */
            FPLAddItemReal(fplcfg[i].item, which,
                           (char *)arg->argv[2],  /* program to run */
                           (char *)arg->argv[1]); /* regex */
            i = -1;
            break;
          }
        }
        retcode = (i >= 0) ? 1 : 0;
        retpnt = &retcode;
      }
      break;

    case FPR_JOIN:
      if (arg->argc) {
        if (StrLength(arg->argv[0]))
          StrCopy(channel, arg->argv[0]);
        if (arg->argc > 1)
          StrCopy(chankey, arg->argv[1]);
      }
      WriteServer("JOIN %s %s", channel, chankey);
      break;

    case FPR_KICK:
      Kick(arg->argv[0], arg->argv[1]);
      break;

    case FPR_LABDEFINE:
      flags = LAB_DEFINED;
      flags |= StrSubstring((char *)arg->argv[1], "save") ? LAB_SAVE : 0;
      flags |= StrSubstring((char *)arg->argv[1], "solo") ? LAB_SOLO : 0;
      flags |= StrSubstring((char *)arg->argv[1], "str") ? LAB_STRING : 0;
      if ('S' == arg->format[2])
        flags |= LAB_STRING;
      LabelDefine((char *)arg->argv[0], flags, arg->argv[2]);
      break;

    case FPR_LABREAD:
      l = LabelFind((char *)arg->argv[0]);
      if (l) {
        if (l->flags & LAB_SOLO) {
          if (l->flags & LAB_STRING)
            fplSendTags(fplkey, FPLSEND_STRING, l->def.str, FPLSEND_DONE);
          else
            fplSendTags(fplkey, FPLSEND_INT, l->def.val, FPLSEND_DONE);
        }
        else {
          ul = NULL;

          if (arg->argc > 1)
            ul = (itemuserlabel **)ID2Label((int)arg->argv[1]);

          if (NULL == ul)
            ul = (itemuserlabel **)&current->label;

          UserlabelRead(arg->argv[0], *ul);
        }
      }
      break;

    case FPR_LABSET:
      l = LabelFind((char *)arg->argv[0]);
      if (l) {
        if (l->flags & LAB_SOLO) {
          if (l->flags & LAB_STRING) {
            if (l->def.str)
              StrFree(l->def.str);
            l->def.str = StrDuplicate((char *)arg->argv[1]);
          }
          else
            l->def.val = (int)arg->argv[1];
        }
        else {
          ul = NULL;

          if (arg->argc > 2)
            ul = (itemuserlabel **)ID2Label((int)arg->argv[2]);

          if (NULL == ul)
            ul = (itemuserlabel **)&current->label;

          UserlabelSet(arg->argv[0], arg->argv[1],
                       ('S' == arg->format[1]) ? LAB_STRING : 0, ul);
        }
      }
      break;

    case FPR_LEAVE:
      WriteServer("PART %s", channel);
      break;

    case FPR_MATCH:
      retcode = Match(arg->argv[0], arg->argv[1]);
      retpnt = &retcode;
      break;

    case FPR_OUTPUT:
      fputs(arg->argv[0], stderr);
      break;

    case FPR_RANDOM:
      retcode = (int)(Rnd()*(int)arg->argv[0]);
      retpnt = &retcode;
      break;

    case FPR_REGEX:
      retcode = PatternExist(arg->argv[0], arg->argv[1]);
      retpnt = &retcode;
      break;

    case FPR_RUNFILE:
      retcode = fplExecuteFile(fplkey, arg->argv[0], NULL);
      retpnt = &retcode;
      break;

    case FPR_SAY:
      Say(arg->argv[0]);
      break;

    case FPR_SEND:
      Send(arg->argv[0], arg->argv[1]);
      break;

    case FPR_TIMERADD:
      retcode = fTimerAdd((int)arg->argv[0], arg->argv[1]);
      retpnt = &retcode;
      break;

    case FPR_TIMERKILL:
      retcode = fTimerKill((int)arg->argv[0]);
      retpnt = &retcode;
      break;

    case FPR_TIME2SECS:
      retcode = ToSeconds((char *)arg->argv[0]);
      retpnt = &retcode;
      break;

    case FPR_USERINFO:
      {
        itemguest *g;

        g = FindNick((char *)arg->argv[0]);
        if (g) {
          if (StrEqual((char *)arg->argv[1], "level"))
            retcode = g->ident->level;
          else if (StrEqual((char *)arg->argv[1], "ircop"))
            retcode = g->flags.ircop ? 1 : 0;
          else if (StrEqual((char *)arg->argv[1], "voice"))
            retcode = g->flags.voice ? 1 : 0;
          else if (StrEqual((char *)arg->argv[1], "chanop"))
            retcode = g->flags.chanop ? 1 : 0;
          else
            retcode = -1;
        }
        else
          retcode = -1;
        retpnt = &retcode;
      }
      break;

    case FPR_BOTINFO:
      if (StrEqual((char *)arg->argv[0], "chanop")) {
        retcode = botop ? 1 : 0;
        retpnt = &retcode;
      }
      else if (StrEqual((char *)arg->argv[0], "nick"))
        fplSendTags(fplkey, FPLSEND_STRING, nickname, FPLSEND_DONE);
      break;

    case FPR_MODE:
      Mode("%s", arg->argv[0]);
      break;

  }

  if (retpnt) {
    fplSendTags(fplkey, FPLSEND_INT, retcode, FPLSEND_DONE);
  }

  return FPL_OK;
}

/* --- fplrunner -------------------------------------------------- */

int fplrunner(char *prog, char *input)
{
  char fplprog[BIGONE];
  void *array[MAX_ARGS];
  char *empty = "";
  char *origline;
  int argc = 0;

  snapshot;
  origline = StrDuplicate(prog);
  if (NULL == origline)
    return 0;

  prog = origline;
  while (prog) {
    prog = StrIndex(prog, '%');
    if (prog) {
      switch (*++prog) {
      case '%': /* Just a % */
        break;
      case 'i':
        array[argc++] = input;
        *prog = 's';
        break;
      case 'n':
        array[argc++] = nickname;
        *prog = 's';
        break;
      case 'u':
        if (current)
          array[argc++] = current->nick;
        else
          array[argc++] = "unknown";
        *prog = 's';
        break;
      case 'c':
        array[argc++] = channel;
        *prog = 's';
        break;
      case 't':
        array[argc++] = (void *)time(NULL);
        *prog = 'd'; /* integer */
        break;
      default:
        /* Make this an empty string */
        array[argc++] = empty;
        *prog = 's'; /* string */
        break;
      }
      prog++;
    }
  }

  trio_vsnprintf(fplprog, sizeof(fplprog), origline, array);
  StrFree(origline);

  fprintf(stderr, "%s\n", fplprog);
  {
    char *program1 = fplprog;
    fplExecuteScriptTags(fplkey, &program1, 1, FPLTAG_DONE);
  }
  return 0;
}

/* --- runfpl ----------------------------------------------------- */

bool runfpl(runitem item, char *line, char which)
{
  bool match = FALSE;
  itemfpl *f;

  snapshot;
  Cancel = FALSE;

  if (NULL == fplentry[item][(int)which]) /* No list on this item */
    return 0;

  /* First check condition with the line parameter */
  for (f = First(fplentry[item][(int)which]); f && !Cancel; f = Next(f)) {
    if (f->regex && f->regex[0]) {
      if (PatternExist(line, f->regex))
        match = TRUE;
    }
    else {
      match = TRUE; /* No regex equals match */
    }

    if (match) {
      match = FALSE;
      fplrunner(f->prog, line);
    }
  }

  return Cancel; /* Cancelled state */
}

/* --- FPLAddItem ------------------------------------------------- */

void FPLAddItem(char *line)
{
  char keyword[MINIBUFFER], regex[BIGBUFFER], program[BIGBUFFER];
  char *pointer;
  char hooktype;
  int i;

  snapshot;
  switch (line[0]) {

    case '+':
      hooktype = FPLRUN_POST;
      pointer = &line[1];
      break;

    default:
      hooktype = FPLRUN_PRE;
      pointer = line;
      break;

  }

  if ((3 == StrScan(pointer, "%"MINIBUFFERTXT"[a-zA-Z0-9.] %*[=: ] \"%"BIGBUFFERTXT"[^\"]\" %"BIGBUFFERTXT"[^\n]",
                    keyword, regex, program)) ||
      (3 == StrScan(pointer, "%"MINIBUFFERTXT"[a-zA-Z0-9.] %*[=: ] %"BIGBUFFERTXT"s %"BIGBUFFERTXT"[^\n]",
                    keyword, regex, program))) {

    if ('"' == regex[0])
      regex[0] = (char)0;

    for (i = 0; i < sizeof(fplcfg)/sizeof(fplcfg[0]); i++) {
      if (StrEqual(fplcfg[i].label, keyword))
        FPLAddItemReal(fplcfg[i].item, hooktype, program, regex);
    }
  }
}

/* --- FPLLoad ---------------------------------------------------- */

bool FPLLoad(char *filename)
{
  char line[MAXLINE];
  FILE *f;

  snapshot;
  if ((NULL == filename) || ((char)0 == filename[0]))
    return FALSE;

  /* Set up the FPL invoke lists */
  f = fopen(filename, "r");
  if (f) {
    while (fgets(line, sizeof(line), f)) {
      switch (line[0]) {

        case '#':
        case '\n':
          break;

        default:
          FPLAddItem(line);
          break;
      }
    }
    fclose(f);

    return TRUE;
  }
  return FALSE;
}

/* --- FPLInit ---------------------------------------------------- */

#if defined(AMIGA) && !defined(__GNUC__)
struct Library *FPLBase = NULL;
#endif

struct fffpl {
  char *name;
  fplfunction func;
  char retcode;
  char *param;
};

void FPLInit(void)
{
  extern char fplconf[];
  int i;

  struct fffpl fplcmds[] = {
    {"Action",  FPR_ACTION,  'I', "S"},    /* /me in channel */
    {"Ban",     FPR_BAN,     'I', "S"},    /* nick, *nick or pattern */
    {"BanInfo", FPR_BANINFO, 'O', "So"},   /* info, <new value> */
    {"BotInfo", FPR_BOTINFO, 'O', "So"},   /* info, <new value> */
    {"Cancel",  FPR_CANCEL,  'I', "i"},    /* 1-cancel, 0-don't */
    {"ChanInfo", FPR_CHANINFO, 'O', "S"},  /* info */
    {"CmdAdd",  FPR_CMDADD,   'I', "SISSSS"},
    {"CurrentTime", FPR_CTIME,'I', NULL},  /* Get the current time */
    {"Do",      FPR_DO,      'I', "S"},
    {"GetUser", FPR_GETUSER, 'I', "Ss"},   /* nick, <flags> */
    {"Hook",    FPR_HOOK,    'I', "SSSs"}, /* name, regex, program, [pre/post] */
    {"Join",    FPR_JOIN,    'I', "ss"},   /* channel (or default channel if not
                                              specified), chankey */
    {"Kick",    FPR_KICK,    'I', "SS"},   /* nick, message */
    {"LabelDefine", FPR_LABDEFINE, 'I', "Sso"},
    {"LabelRead", FPR_LABREAD, 'O', "Si"},
    {"LabelSet", FPR_LABSET, 'I', "SOi"},
    {"Leave",   FPR_LEAVE,   'I', NULL},   /* just leave current channel */
    {"Match",   FPR_MATCH,   'I', "SS"},   /* string, wildcard */
    {"Output",  FPR_OUTPUT,  'I', "S"},    /* to stderr */
    {"Regex",   FPR_REGEX,   'I', "SS"},   /* string, regex */
    {"Rnd",     FPR_RANDOM,  'I', "I"},    /* max value */
    {"Runfile", FPR_RUNFILE, 'I', "S"},    /* file name */
    {"Say",     FPR_SAY,     'I', "S"},    /* string */
    {"Send",    FPR_SEND,    'I', "SS"},   /* nick, string */
    {"TimerAdd", FPR_TIMERADD,'I', "IS"},  /* time, program RETURNS timerid*/
    {"TimerKill", FPR_TIMERKILL,'I', "I"}, /* timerid RETURNS time left */
    {"TimeToSecs", FPR_TIME2SECS, 'I', "S"}, /* convert XX:XX:XX to seconds */
    {"Topic",   FPR_TOPIC,   'I', "S"},    /* topic string */
    {"Unban",   FPR_UNBAN,   'I', "S"},    /* banid, nick or pattern */
    {"UserInfo", FPR_USERINFO, 'O', "SSo"}, /* nick, info, [new value] */
    {"WarnAdd", FPR_WARNADD,  'I', "SSi"}, /* nick, decr, <flag> */
    {"WarnInfo", FPR_WARNINFO, 'O', "S"},  /* info */
    {"Mode", FPR_MODE, 'I', "S"},          /* modes */
  };

  snapshot;
#if defined(AMIGA) && !defined(__GNUC__)
  FPLBase = OpenLibrary("fpl.library", 13);
  if (NULL == FPLBase) {
    /*
     * This is probably not a critical error, in fact Dancer
     * could very well continue w/o it. Theoritically.
     */
    Log(LOG, "Unable to open fpl.library!");
    restart = FALSE;
    Cleanup();
    return;
  }
#endif

  LabelInit();  /* Init list of fpl added labels */
  fCmdInit();   /* Init the list of FPL-added commands */
  fTimerInit(); /* Init timed FPL actions */

  fplkey = fplInitTags(fplinterface,
                       FPLTAG_CACHEALLFILES, FPLCACHE_EXPORTS,
                       FPLTAG_REREAD_CHANGES, TRUE,
#if 0
                       FPLTAG_INTERVAL, (unsigned long)inter, /* interval func */
                       FPLTAG_USERDATA, (unsigned long)&count, /* user data */
                       FPLTAG_INTERNAL_DEALLOC, (unsigned long)MyFree,
                       FPLTAG_INTERNAL_ALLOC, (unsigned long)MyAlloc,
                       FPLTAG_MINSTACK, 7000,
                       FPLTAG_IDENTITY, argv[0], /* identify us! */
                       FPLTAG_DEBUG, TRUE,  /* run in debug mode! */
/*                     FPLTAG_AUTOCOMPILE, TRUE, */
#endif
                       FPLTAG_DONE);

  /* We better add some functions to play with */
  for (i = 0; i < sizeof(fplcmds)/sizeof(fplcmds[0]); i++) {
    fplAddFunction(fplkey, fplcmds[i].name, fplcmds[i].func, fplcmds[i].retcode,
                   fplcmds[i].param, NULL);
  }

  FPLLoad(fplconf);

#if 0
  fplentry[RUN_INIT].line = "Runfile(\"dancer.fpl\");";
  fplentry[RUN_PUBLIC].line = "mytest(\"%c\", \"%i\"); ";
#endif

  runfpl(RUN_INIT, "", FPLRUN_PRE);
}

/* --- FPLCleanup ------------------------------------------------- */

void FPLCleanup(void)
{
  snapshot;
  if (fplkey) {
    fplFree(fplkey); /* Clean up fpl usage */
    fplkey = NULL;
  }

  fTimerCleanup(); /* Clean away timed FPL actions */
  fCmdCleanup();   /* Clean away fpl-added commands */
  LabelCleanup();  /* Clean up labels */

#if defined(AMIGA) && !defined(__GNUC__)
  if (FPLBase) {
    CloseLibrary(FPLBase);
    FPLBase = NULL;
  }
#endif
}

#endif /* HAVE_LIBFPL */


syntax highlighted by Code2HTML, v. 0.9.1