Logo Search packages:      
Sourcecode: bayonne version File versions  Download package

script.cpp

// Copyright (C) 2000-2001 Open Source Telecom Corporation.
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "server.h"

#ifdef      HAVE_SSTREAM
#include <sstream>
#else
#include <strstream>
#endif

#ifdef CCXX_NAMESPACES
namespace ost {
using namespace std;
#endif

static class DTMFProperty : public Script::Property, public Keydata
{
public:
      char dtmfmap[64];
      DTMFProperty();

private:
        void dtmf(char *dp, char *tp, size_t size);
      
      void set(char dig);

        void setProperty(char *dp, char *tp, size_t size)
                {dtmf(dp, tp, size);};
        void getProperty(char *dp, char *tp, size_t size)
                {dtmf(dp, tp, size);};

} dtmf;

DTMFProperty::DTMFProperty() : 
Script::Property("dtmf"), Keydata("/bayonne/dtmf")
{
      unsigned char dig = '0';

        static Keydata::Define keydefs[] = {
        {"2", "abc"},
      {"3", "def"},
      {"4", "ghi"},
      {"5", "jkl"},
      {"6", "mno"},
      {"7", "pqrs"},
      {"8", "tuv"},
      {"9", "wxyz"},
        {NULL, NULL}};

        load(keydefs);

      memset(dtmfmap, 0, sizeof(dtmfmap));

      while(dig <= '9')
            set(dig++);
}

void DTMFProperty::dtmf(char *from, char *to, size_t size)
{
      char dig;
        while(*from && size)
        {
                dig = toupper(*(from++));
            if(dig < 32 || dig > 95)
                  continue;        
            dig -= 32;
            if(!dtmfmap[dig])
                  continue;

            *(to++) = dtmfmap[dig];
        }
        *to = 0;
}

void DTMFProperty::set(char key)
{
      const char *keys;
      char str[2];
      char dig;

      str[0] = key;
      str[1] = 0;
      
      keys = getLast(str);
      if(!keys)
            return;

      while(*keys)
      {
            dig = toupper(*(keys++));
            if(dig < 32 || dig > 95)
                  continue;

            dtmfmap[dig - 32] = key;
      }
}

bool Trunk::scrStatinfo(void)
{
      const char *ref = getKeyword("id");
      Line *line = getScript();
      int argc = 0;
      TrunkGroup *grp;
      char *opt, *var, value[12];

      if(!ref)
            ref = getKeyword("group");

      if(ref)
            grp = getGroup(ref);
      else
            grp = group;            // current trunk group

      if(!grp)
      {
            error("invalid-group-specified");
            return true;
      }

      while(argc < line->argc)
      {
            opt = line->args[argc++];
            if(*opt != '=')
                  continue;

            ++opt;
            var = line->args[argc++];
            if(*var == '&')
                  ++var;

            value[0] = 0;
            if(!stricmp(opt, "capacity") || !stricmp(opt, "size"))
                  snprintf(value, sizeof(value), "%d", grp->capacity);
            else if(!stricmp(opt, "total_incoming"))
                  snprintf(value, sizeof(value), "%d", grp->total.incoming);
            else if(!stricmp(opt, "total_outgoing"))
                  snprintf(value, sizeof(value), "%d", grp->total.outgoing);
            else if(!strnicmp(opt, "avail", 5))
                  snprintf(value, sizeof(value), "%d",
                        grp->capacity - grp->active.incoming - grp->active.outgoing);
            else if(!stricmp(opt, "used"))
                  snprintf(value, sizeof(value), "%d",
                        grp->active.incoming + grp->active.outgoing);
            else if(!stricmp(opt, "incoming"))
                  snprintf(value, sizeof(value), "%d", grp->active.incoming);
            else if(!stricmp(opt, "outgoing"))
                  snprintf(value, sizeof(value), "%d", grp->active.outgoing);
            else if(!stricmp(opt, "max_incoming"))
                  snprintf(value, sizeof(value), "%d", grp->max.incoming);
            else if(!stricmp(opt, "max_outgoing"))
                  snprintf(value, sizeof(value), "%d", grp->max.outgoing);

            if(value[0])
                  setVariable(var, 11, value);
      }
      advance();
      return true;            
}

bool Trunk::scrHuntinfo(void)
{
      const char *ref = getKeyword("id");
      const char *opt, *var;
      Symbol *def, *sym;
      int argc = 0;
      Line *line = getScript();
      char name[256];
      Trunk *trunk;

      if(!ref)
            ref = getValue(NULL);

      if(!ref)
      {
            error("no-hunt-specified");
            return true;
      }

      snprintf(name, sizeof(name), "hunt.%s.id", ref);
      sym = globals.getEntry(name, 0);
      if(!sym || sym->flags.initial)
      {
            error("unknown-hunt");
            return true;
      }

      while(argc < line->argc)
      {
            opt = line->args[argc++];
            if(*opt != '=')
                  continue;

            ++opt;
            var = line->args[argc++];
            if(*var == '&')
                  ++var;

            if(!stricmp(opt, "id"))
                  continue;

            snprintf(name, sizeof(name), "hunt.%s.%s", ref, opt);
            sym = globals.getEntry(name);
            snprintf(name, sizeof(name), "hunt.default.%s", opt);
            def = globals.getEntry(name);
            if(!def)
                  continue;
            if(!sym || sym->flags.initial)
                  opt = def->data;
            else
                  opt = sym->data;
            setVariable(var, def->flags.size, opt);
      }
      advance();
      return true;
}


bool Trunk::scrUserinfo(void)
{
      const char *ref = getKeyword("id");
      const char *opt, *var;
      Symbol *def, *sym;
      int argc = 0;
      Line *line = getScript();
      char name[256];
      Trunk *trunk;

      if(!ref)
            ref = getValue(NULL);

      if(!ref)
      {
            error("no-user-specified");
            return true;
      }

      ref = getExtReference(ref);
      if(!ref)
      {
            error("invalid-session");
            return true;
      }

      if(!isUser(ref))
      {
            error("invalid-user");
            return true;
      }

      while(argc < line->argc)
      {
            opt = line->args[argc++];
            if(*opt != '=')
                  continue;

            ++opt;
            var = line->args[argc++];
            if(*var == '&')
                  ++var;

            if(!stricmp(opt, "id"))
                  continue;

            if(!stricmp(opt, "password"))
                  continue;

            snprintf(name, sizeof(name), "%s.%s", ref, opt);
            sym = globals.getEntry(name);
            snprintf(name, sizeof(name), "default.%s", opt);
            def = globals.getEntry(name);
            if(!def)
                  continue;
            if(!sym || sym->flags.initial)
                  opt = def->data;
            else
                  opt = sym->data;
            setVariable(var, def->flags.size, opt);
      }
      advance();
      return true;
}

bool Trunk::scrExamine(void)
{
      Trunk *trk = NULL;
      Symbol *var;
      const char *pid = NULL;
      unsigned len = 0;

      if(isAdmin())
      {
            pid = getKeyword("extension");
            if(!pid)
                  pid = getKeyword("ext");
            if(pid)
                  trk = driver->getExtNumber(pid);

            if(!pid)
                  pid = getKeyword("trunk");
            if(!pid)
                  pid = getKeyword("trk");
            if(pid)
                  trk = driver->getTrkNumber(pid);

            if(!pid)
                  pid = getKeyword("tie");
            if(pid)
                  trk = driver->getTieNumber(pid);
      }

      if(!pid)
      {
            pid = getKeyword("id");
            if(!pid)
                  pid = getValue("9999");

            if(!isAdmin() && !strchr(pid, '-'))
            {
                  error("admin-required");
                  return true;
            }
            trk = driver->getTrunkId(pid);
      }
      if(!trk)
      {
            error("examine-no-port");
            return true;
      }

      if(trk == this)
      {
            error("examine-self-reference");
            return true;
      }

      pid = getKeyword("var");
      if(!pid)
            pid = getContent(NULL);

      if(!pid)
      {
            error("examine-no-target");
            return true;
      }

      if(*pid == '%')
            ++pid;

      var = getEntry(pid, getSymbolSize());
      if(!var)
      {
            error("examine-no-target");
            return true;
      }

      if(var->flags.readonly)
      {
            error("examine-readonly");
            return true;
      }

      var->data[len] = 0;
      trk->enterMutex();
      while(NULL != (pid = getContent(NULL)) && len < var->flags.size)
      {
            if(*pid == '%')
                  ++pid;

            pid = trk->getSymbol(pid);
            if(!pid)
                  continue;

            if(len)
                  var->data[len++] = ',';

            strncpy(var->data + len, pid, var->flags.size - len);
            var->data[var->flags.size] = 0;
      }
      if(var->flags.commit)
            commit(var);
      trk->leaveMutex();
      advance();
      return true;
}

bool Trunk::scrService(void)
{
      const char *mem = getMember();
      if(!mem)
            mem = "up";

      if(!isAdmin())
      {
            error("admin required");
            return false;
      }

      if(!stricmp(mem, "up"))
            service[0] = 0;
      else
            snprintf(service, sizeof(service), "down::%s", getValue("service"));

      advance();
      return true;
}

bool Trunk::scrBusy(void)
{
      TrunkEvent event;
      Trunk *trk;
      TrunkGroup *grp = NULL;
      const char *mem = getMember();
      unsigned port, tspan;

      if(!mem)
            mem = "self";
      else if(!isAdmin())
      {
            error("admin-required");
            return false;
      }

      if(!stricmp(mem, "port"))
      {
            event.id = TRUNK_MAKE_BUSY;
            mem = getValue(getKeyword("id"));
            trk = driver->getTrunkId(mem);

            if(!trk)
            {
                  error("busy-port-id");
                  return true;
            }

            if(trk == this)
            {
                  error("busy-self-reference");
                  return true;
            }

            trk->postEvent(&event);
            advance();
            return true;
      }

      if(!stricmp(mem, "span"))
      {
            mem = getValue(getKeyword("id"));
            if(!mem)
            {
                  error("busy-span-id");
                  return true;
            }
            tspan = atoi(mem);
            if(!driver->spanEvent(tspan, &event))
                  error("busy-span-invalid");
            else
                  advance();
            return true;
      }

      if(!stricmp(mem, "card"))
      {
            mem = getValue(getKeyword("id"));
            if(!mem)
            {
                  error("busy-card-id");
                  return true;
            }
            tspan = atoi(mem);
            if(!driver->cardEvent(tspan, &event))
                  error("busy-card-invalid");
            else
                  advance();
            return true;
      }

      if(!stricmp(mem, "group"))
      {
            mem = getValue(getKeyword("id"));
            if(mem)
                  grp = getGroup(mem);
            if(!grp)
            {
                  error("busy-group-id");
                  return true;
            }

              for(port = 0; port < driver->getTrunkCount(); ++port)
            {
                  if(driver->getTrunkGroup(port) != grp)
                              continue;

                      trk = driver->getTrunkPort(port);
                    if(!trk || trk == this)
                              continue;

                  event.id = TRUNK_MAKE_BUSY;
                  trk->postEvent(&event);
            }

            advance();
            return true;
      }
      error("busy-self-reference");
      return true;
}

bool Trunk::scrSlog(void)
{
        unsigned id = getId();
        const char *member = getMember();
      const char *file = getKeyword("file");
        char *val;
        Name *obj = getObject();
      char name[32];
      char buffer[256], encode[256];
#ifdef      HAVE_TGI
      tgicmd_t cmd;
#endif

        if(!member)
                member = getKeyword("level");

#ifdef      HAVE_TGI
      if(file)
      {
            buffer[0] = 0;
            while(NULL != (val = getValue(NULL)))
                  strcat(buffer, val);
            val = urlEncode(buffer, encode, sizeof(encode));
            file = urlEncode(file, buffer, sizeof(buffer));
            snprintf(cmd.cmd, sizeof(cmd.cmd), "-log %s %s", file, val);
            cmd.port = id;
            cmd.mode = TGI_EXEC_NORMAL;

            data.sleep.rings = 0;
            data.sleep.loops = 1;
            data.sleep.save = NULL;
            data.sleep.wakeup = getTimeout("maxTime");
            if(!data.sleep.wakeup)
                  data.sleep.wakeup = 30000;
              ::write(tgipipe[1], &cmd, sizeof(cmd));
            trunkStep(TRUNK_STEP_SLEEP);
            return false;
      }
#endif

        if(member)
        {
                if(!strnicmp(member, "err", 3))
                        slog(Slog::levelError);
                else if(!strnicmp(member, "warn", 4))
                        slog(Slog::levelWarning);
                else if(!stricmp(member, "debug"))
                        slog(Slog::levelDebug);
                else if(!strnicmp(member, "crit", 4))
                        slog(Slog::levelCritical);
                else
                        slog(Slog::levelInfo);
        }
        else
                slog(Slog::levelInfo);

      getName(name);


        slog() << name << ": " << obj->name;
        if(id)
                slog() << "(" << id << ")";

        slog() << ": ";
        while(NULL != (val = getValue(NULL)))
                slog() << val;
        slog() << endl;
        advance();
        return true;
}

bool Trunk::scrSend(void)
{
      const char *pid;
      TrunkEvent event;
      Trunk *trk = NULL;
      Symbol *sym;
      int dig;
      const char *opt = getMember();
      const char *val;
      enum
      {
            byId,
            byExt,
            byTrk,
            byTie
      }     by = byId;

      if(!opt)
            opt = "message";

      if(!stricmp(opt, "pickup"))
            pid = getSymbol(SYM_PICKUP);
      else if(!stricmp(opt, "recall"))
            pid = getSymbol(SYM_RECALL);
      else
            pid = getKeyword("id");

      if(!pid)
            pid = getKeyword("gid");

      if(!pid)
      {
            pid = getKeyword("ext");
            if(!pid)
                  pid = getKeyword("extension");
            if(pid)
                  by = byExt;
      }

      if(!pid)
      {
            pid = getKeyword("trk");
            if(!pid)
                  pid = getKeyword("trunk");
            if(pid)
                  by = byTrk;
      }

      if(!pid)
      {
            pid = getKeyword("tie");
            if(pid)
                  by = byTie;
      }

      if(!pid)
            pid = getValue(NULL);

      if(!pid)
      {
            error("send-no-id");
            return true;
      }

      switch(by)
      {
      case byTie:
            trk = driver->getTieNumber(pid);
            break;
      case byTrk:
            trk = driver->getTrkNumber(pid);
            break;
      case byExt:
            trk = driver->getExtNumber(pid);
            break;
      default:
            trk = driver->getTrunkId(pid);
      }
      if(!trk)
      {
            error("send-no-session");
            return true;
      }

      if(trk == this)
      {
            error("send-self-reference");
            return true;
      }

      if(!stricmp(opt, "copy"))
      {
            trk->enterMutex();
            while(NULL != (opt = getOption(NULL)))
            {
                  if(*opt != '%')
                        continue;

                  sym = getEntry(++opt, 0);
                  if(!sym)
                        continue;

                  trk->setVariable(opt, sym->flags.size, sym->data);
            }
            trk->leaveMutex();
      }
      else if(!strnicmp(opt, "dig", 3))
      {
            opt = getKeyword("digits");
            if(!opt)
                  opt = getValue(NULL);
            if(!opt)
            {
                  error("no-digits");
                  return true;
            }
            while(*opt)
            {
                  dig = getDigit(*(opt++));
                  if(dig < 0)
                        continue;
                  event.id = TRUNK_DTMF_KEYUP;
                  event.parm.dtmf.digit = dig;
                  trk->postEvent(&event);
            }
      }
      else if(!stricmp(opt, "post"))
      {
            trk->enterMutex();
            while(NULL != (opt = getOption(NULL)))
            {
                  val = getValue("");
                  if(*opt != '%')
                        continue;

                  sym = trk->getEntry(++opt, 0);
                  if(!sym)
                  {
                        continue;
                  }
                  trk->postSymbol(sym, val);
            }
            trk->leaveMutex();
      }
      else
      {
            event.id = TRUNK_SEND_MESSAGE;
            event.parm.send.seq = seq;
            event.parm.send.src = this;
            event.parm.send.msg = getKeyword("message");
            if(!event.parm.send.msg)
                  event.parm.send.msg = getValue("");
            trk->postEvent(&event);
      }

      advance();
      return true;
}

bool Trunk::scrAssign(void)
{
      const char *var = getKeyword("var");
      const char *value = getKeyword("value");
      const char *size = getKeyword("size");

      if(!value)
            value = "";

      if(!size)
            setVariable(var, getSymbolSize(), value);
      else
            setVariable(var, atoi(size), value);
      advance();
      return true;
}

bool Trunk::scrPolicy(void)
{
      Line *line = getScript();
      char *opt;
      const char *value = NULL, *def;
      const char *member = getMember();
      int argc = 0;
      char local[65];

      while(argc < line->argc)
      {
            opt = line->args[argc++];
                if(*opt != '=')
                        continue;

                if(*(++opt) == '%')
                        ++opt;

            def = line->args[argc++];

                if(member)
                        snprintf(local, sizeof(local), "%s.%s", member, opt);
                else
                        snprintf(local, sizeof(local), "%s", opt);

            if(group)
                  value = group->getLast(opt);

            if(!value)
                  value = def;

            setConst(local, value);
      }
      advance();
      return true;
}

bool Trunk::scrConfig(void)
{
      ScriptImage *img = getImage();

      Name *scr = getObject();
      Line *line = getScript();
      char *opt;
      const char *value, *def;
      const char *member = getMember();
      int argc = 0;
      char buffer[65];
      char appl[65];
      char local[65];

      snprintf(appl, sizeof(appl), "%s", scr->name);
      opt = strstr(appl, "::");
      if(opt)
            *opt = 0;

      while(argc < line->argc)
      {
            opt = line->args[argc++];
                if(*opt != '=')
                        continue;

                if(*(++opt) == '%')
                        ++opt;

            def = line->args[argc++];

                if(member)
            {
                        snprintf(local, sizeof(local), "%s.%s", member, opt);
                  snprintf(buffer, sizeof(buffer), "%s.%s", member, opt);
            }
                else
            {
                        snprintf(local, sizeof(local), "%s", opt);
                  snprintf(buffer, sizeof(buffer), "%s.%s", appl, opt);
            }

            value = img->getLast(buffer);
            if(!value)
                  value = img->getLast(opt);

            if(!value)
                  value = def;

            setConst(local, value);
      }
      advance();
      return true;
}

bool Trunk::scrDummy(void)
{
      error("not-supported");
      return true;
}

bool Trunk::scrRedirect(void)
{
      return scrCleardigits();
}

bool Trunk::scrCleardigits(void)
{
      const char *mem = getMember();
      Line *line = getScript();
      trunksignal_t sig;
      unsigned dig = 0;
      unsigned count;

      if(!mem)
      {
            if(line->method == (Method)&Trunk::scrCleardigits)
                  mem = "all";
            else
                  mem = "none";
      }
      
      if(!stricmp(mem, "all") || !stricmp(mem, "clear"))
      {
            dtmf.bin.data[0] = 0;
            digits = 0;
      }
      else if(!stricmp(mem, "last") && digits)
      {
            dtmf.bin.data[0] = dtmf.bin.data[digits - 1];
            dtmf.bin.data[1] = 0;
            digits = 1;
      }
      else if(atoi(mem) > 0)
      {
            count = atoi(mem);
            if(count > digits)
                  count = digits;

            while(dig < count)
                  dtmf.bin.data[dig++] = '-';
      }
      else if(!stricmp(mem, "pop") && digits)
            dtmf.bin.data[0] = '-';
      else if(stricmp(mem, "trap"))
      {
            dtmf.bin.data[0] = 0;
            digits = 0;
      }
      
      if(line->method == (Method)&Trunk::scrRedirect)
      {
            if(!redirect(getContent(line->args[0])))
                  advance();
      }
      else if(line->argc > 0)
            scrGoto();
      else
            advance();

retry:
      if(!digits)
            return true;

      switch(dtmf.bin.data[0])
      {
      case '*':
            sig = TRUNK_SIGNAL_STAR;
            break;
      case '#':
            sig = TRUNK_SIGNAL_POUND;
            break;
      case 'a':
      case 'A':
            sig = TRUNK_SIGNAL_A;
            break;
      case 'b':
      case 'B':
            sig = TRUNK_SIGNAL_B;
            break;
      case 'c':
      case 'C':
            sig = TRUNK_SIGNAL_C;
            break;
      case 'd':
      case 'D':
            sig = TRUNK_SIGNAL_D;
            break;
      case '0':
            sig = TRUNK_SIGNAL_0;
            break;
      case '1':
            sig = TRUNK_SIGNAL_1;
            break;
      case '2':
            sig = TRUNK_SIGNAL_2;
            break;
      case '3':
            sig = TRUNK_SIGNAL_3;
            break;
      case '4':
            sig = TRUNK_SIGNAL_4;
            break;
      case '5':
            sig = TRUNK_SIGNAL_5;
            break;
      case '6':
            sig = TRUNK_SIGNAL_6;
            break;
      case '7':
            sig = TRUNK_SIGNAL_7;
            break;
      case '8':
            sig = TRUNK_SIGNAL_8;
            break;
      case '9':
            sig = TRUNK_SIGNAL_9;
            break;
      default:
            sig = TRUNK_SIGNAL_STEP;
      }

      if(sig != TRUNK_SIGNAL_STEP)              
            if(trunkSignal(sig))
                  return true;

      dig = 0;
      while(dig < digits)
      {
            dtmf.bin.data[dig] = dtmf.bin.data[dig + 1];
            ++dig;
      }
      dtmf.bin.data[dig] = 0;
      digits = --dig;
      goto retry; 
}

bool Trunk::scrIdle(void)
{
      TrunkEvent event;
      Trunk *trk;
      TrunkGroup *grp = NULL;
      const char *mem = getMember();
      unsigned port, tspan;

      if(!mem)
            mem = "self";
      else if(!isAdmin())
      {
            error("admin-required");
            return true;
      }

      if(!stricmp(mem, "port"))
      {
            event.id = TRUNK_MAKE_IDLE;
            mem = getValue(getKeyword("id"));
            trk = driver->getTrunkId(mem);

            if(!trk)
            {
                  error("idle-port-id");
                  return true;
            }

            if(trk == this)
            {
                  error("idle-self-reference");
                  return true;
            }

            trk->postEvent(&event);
            advance();
            return true;
      }

      if(!stricmp(mem, "span"))
      {
            mem = getValue(getKeyword("id"));
            if(!mem)
            {
                  error("idle-span-id");
                  return true;
            }
            tspan = atoi(mem);
            if(driver->spanEvent(tspan, &event))
                  advance();
            else
                  error("idle-span-invalid");
            return true;
      }

        if(!stricmp(mem, "card"))
        {
                mem = getValue(getKeyword("id"));
                if(!mem)
                {
                        error("idle-card-id");
                        return true;
                }
                tspan = atoi(mem);
                if(driver->cardEvent(tspan, &event))
                        advance();
                else
                        error("idle-card-invalid");
                return true;
        }

      if(!stricmp(mem, "group"))
      {
            mem = getValue(getKeyword("id"));
            if(mem)
                  grp = getGroup(mem);
            if(!grp)
            {
                  error("idle-group-id");
                  return true;
            }

              for(port = 0; port < driver->getTrunkCount(); ++port)
            {
                  if(driver->getTrunkGroup(port) != grp)
                              continue;

                      trk = driver->getTrunkPort(port);
                    if(!trk || trk == this)
                              continue;

                  event.id = TRUNK_MAKE_IDLE;
                  trk->postEvent(&event);
            }

            advance();
            return true;
      }

      idle_timer = atoi(getValue("0"));
      advance();
      return true;
}

bool Trunk::scrSchedule(void)
{
      char cmd[65];

      strcpy(cmd, "schedule ");
      strcat(cmd, getValue(""));
      if(!fifo.command(cmd))
      {
            error("schedule-failed");
            return true;
      }
      advance();
      return true;
}

bool Trunk::scrSignal(void)
{
      Trunk *trunk;
      TrunkEvent event;

      trunk = driver->getTrunkPort(atoi(getValue("-1")));
      if(!trunk)
      {
            error("signal-no-such-trunk");
            return true;
      }

      event.id = TRUNK_SIGNAL_NOTIFY;
      event.parm.error = getKeyword("message");
      if(!event.parm.error)
            event.parm.error = getValue(NULL);
      if(!trunk->postEvent(&event))
      {
            error("signal-not-waiting");
            return true;
      }
      advance();
      return true;
}

bool Trunk::scrModule(void)
{
      Line *line = getScript();
      char *cmd = line->cmd;
      char keybuf[33];
      int len = 0;
      char *kw = keybuf;
      char *cp;

      cp = strchr(cmd, '-');
      if(cp)
            cmd = ++cp;

      while(len++ < 32 && *cmd && *cmd != '.')
            *(kw++) = *(cmd++);
      *kw = 0;

      Module *module = getModule(MODULE_ANY, keybuf);
      char *err;
      unsigned delay;

      if(!module)
      {
            error("module-not-found");
            return true;
      }

#ifdef      XML_SCRIPTS
      switch(module->getType())
      {
      case MODULE_XML:
      case MODULE_SQL:
            if(altimage && altmodule == module)
            {
                  altimage->purge();
                  data.load.image = altimage;
                  break;
            }
            if(altimage)
            {
                  altimage->purge();
                  delete altimage;
                  altimage = NULL;
                  altmodule = NULL;
            }
            altimage = module->getXML();
            if(!altimage)
            {
                  error("no-xml-parser");
                  return true;
            }
            altmodule = module;
            data.load.image = altimage;
      }
#endif

      err = module->dispatch(this);
      if(err)
      {
            error(err);
            return true;
      }

      switch(module->getType())
      {
#ifdef      XML_SCRIPTS
      case MODULE_SQL:
      case MODULE_XML:
              if(!strnicmp(data.load.url, "http:", 5))
                   altimage->setProxy(keyproxy.getHTTPServer(), keyproxy.getHTTPPort());
            else
                  altimage->setProxy(NULL, 0);
            trunkStep(TRUNK_STEP_LOADER);
            return false;
#endif
      case MODULE_THREAD:
            trunkStep(TRUNK_STEP_THREAD);
            return false;
      case MODULE_PLAY:
            trunkStep(TRUNK_STEP_PLAY);
            return false;
      case MODULE_RECORD:
            trunkStep(TRUNK_STEP_RECORD);
            return false;
      }

      delay = module->sleep(this);
      if(!delay)
      {
            advance();
            return true;
      }
      if(delay == (unsigned)-1)
            return module->executePrior(this);

      data.sleep.wakeup = delay * 1000;
      data.sleep.rings = 0;
      data.sleep.loops = 1;
      data.sleep.save = NULL;
      if(thread)
            trunkStep(TRUNK_STEP_THREAD);
      else
            trunkStep(TRUNK_STEP_SLEEP);
      module->commit(this);
      return false;
}


bool Trunk::scrMove(void)
{
      const char *prefix = getPrefixPath();
      char *n1 = getValue(NULL);
      char *n2 = getValue(NULL);
      char buf1[256], buf2[256];
      const char *ext;

      if(!n1 || !n2)
      {
            error("move-no-files");
            return true;
      }

      if(prefix)
      {
            snprintf(buf1, sizeof(buf1) - 5, "%s/%s", prefix, n1);
            snprintf(buf2, sizeof(buf2) - 5, "%s/%s", prefix, n2);
      }
      else
      {
            snprintf(buf1, sizeof(buf1) - 5, "%s", n1);
            snprintf(buf2, sizeof(buf2) - 5, "%s", n2);
      }
      n1 = buf1;
      n2 = buf2;

      ext = strrchr(n1, '/');
      if(ext)
            ext = strchr(ext, '.');
      else
      {
            error("move-invalid-path");
            return true;
      }

      if(!ext)
      {
            ext = getKeyword("extension");
            if(!ext)
                  ext = getSymbol(SYM_EXTENSION);
            if(ext)
                  strcat(n1, ext);
      }     

      ext = strrchr(n2, '/');
      if(ext)
            ext = strchr(ext, '.');
      else
      {
            error("move-invalid-path");
            return true;
      }

      if(!ext)
      {
            ext = getKeyword("extension");
            if(!ext)
                  ext = getSymbol(SYM_EXTENSION);
            if(ext)
                  strcat(n2, ext);
      }

      if(rename(n1, n2))
            error("move-failed");
      else
            advance();
      return true;
}

bool Trunk::scrErase(void)
{
      const char *prefix = getPrefixPath();     
      const char *name = getValue(NULL);
      const char *ext;
      char buffer[128];

      if(!name)
      {
            error("erase-no-file");
            return true;
      }

      if(prefix)
            snprintf(buffer, sizeof(buffer) - 5, "%s/%s", prefix, name);
      else
            snprintf(buffer, sizeof(buffer) - 5, "%s", name);

      ext = strrchr(buffer, '/');
      if(ext)
            ext = strchr(ext, '.');
      else
      {
            error("erase-invalid-path");
            return true;
      }
      if(!ext)
      {
            ext = getKeyword("extension");
            if(!ext)
                  ext = getSymbol(SYM_EXTENSION);
            if(ext)
                  strcat(buffer, ext);
      }
      ::remove(buffer);
      advance();
      return true;
}

bool Trunk::scrSendFax(void)
{
      const char *prefix = getPrefixPath();
      const char *file = getValue(NULL);

      if(!(TRUNK_CAP_SENDFAX & getCapabilities()))
      {
            error("no-fax-send");
            return true;
      }

      if(!file)
      {
            error("no-file-to-send");
            return true;
      }

      if(prefix)
            snprintf(data.fax.pathname, sizeof(data.fax.pathname),
                  "%s/%s", prefix, file);
      else
            snprintf(data.fax.pathname, sizeof(data.fax.pathname),
                  "%s", file);

      data.fax.station = getStation();
      trunkStep(TRUNK_STEP_SENDFAX);
      return false;
}
bool Trunk::scrRecvFax(void)
{
        const char *prefix = getPrefixPath();
        const char *file = getValue(NULL);

        if(!(TRUNK_CAP_RECVFAX & getCapabilities()))
        {
                error("no-fax-recv");
                return true;
        }

        if(!file)
        {
                error("no-file-to-recv");
                return true;
        }

        if(prefix)
                snprintf(data.fax.pathname, sizeof(data.fax.pathname),
                        "%s/%s", prefix, file);
        else
                snprintf(data.fax.pathname, sizeof(data.fax.pathname),
                        "%s", file);

        data.fax.station = getStation();
        trunkStep(TRUNK_STEP_RECVFAX);
        return false;
}

bool Trunk::scrRecord(void)
{
      const char *member = getMember();
      const char *cp;
      const char *prefix = getPrefixPath();
      char *gain = getKeyword("gain");
      char *vol = getKeyword("volume");

      cp = getKeyword("trim");
      if(!cp)
            cp = getSymbol(SYM_TRIM);
      if(!cp)     
            cp = "0";
      data.record.trim = atoi(cp);

      cp = getKeyword("frames");
      if(!cp)
            cp = "0";

      data.record.frames = atoi(cp);
      cp = getKeyword("minSize");
      if(!cp)
            cp = "0";
      data.record.minsize = atoi(cp);

      if(!vol)
            vol = getSymbol(SYM_VOLUME);

      if(!vol)
            vol = "100";

      apppath[0] = 0;

      if(!member)
            member="all";

      data.record.save = getKeyword("save");
      data.record.text = getKeyword("text");
      data.record.name = getValue("");    
      if(!data.record.name)
      {
            error("record-no-file");
            return true;
      }

      if(prefix)
      {
            snprintf(apppath + 1, sizeof(apppath) - 1, "%s/%s",
                  prefix, data.record.name);
            data.record.name = apppath + 1;
      }


      cp = getKeyword("timeout");
      if(cp)
            data.record.timeout = getSecTimeout(cp);
      else              
            data.record.timeout = getTimeout("maxTime");
      data.record.term = getDigitMask("exit");
      data.record.offset = (unsigned long)-1;
      data.record.volume = atoi(vol);
      data.record.silence = 0;
      data.record.encoding = getKeyword("encoding");
      data.record.annotation = getKeyword("annotation");
      data.record.extension = getKeyword("extension");
      
      if(data.record.save)
      {
            cp = strrchr(data.record.save, '.');
            if(!cp)
                  cp = data.record.extension;
            if(!cp)
                  cp = getSymbol(SYM_EXTENSION);
            else
                  cp = "";
      }

      if(prefix && data.record.save)
      {
            snprintf(data.record.altinfo, sizeof(data.record.altinfo),
                  "%s/%s%s", prefix, data.record.save, cp);
            data.record.save = data.record.altinfo;
      }
      else if(data.record.save)
            snprintf(data.record.altinfo, sizeof(data.record.altinfo),
                  "%s%s", data.record.save, cp);

      if(!data.record.encoding)
            data.record.encoding = getDefaultEncoding();

      if(!data.record.annotation)
            data.record.annotation = "";

      if(!data.record.extension)
            data.record.extension = getSymbol(SYM_EXTENSION);

      if(gain)
            data.record.gain = (float)strtod(gain, NULL);
      else
            data.record.gain = 0.0;
      
      data.record.info = false;

      if(!stricmp(member, "append"))
            data.record.append = true;
      else if(!stricmp(member, "info"))
      {
            data.record.append = true;
            data.record.info = true;
      }
      else
            data.record.append = false;
      if(NULL != (cp = getKeyword("offset")))
            data.record.offset = atoi(cp);
      if(NULL != (cp = getKeyword("volume")))
            data.record.volume = atoi(cp);
      if(NULL != (cp = getKeyword("silence")))
            data.record.silence = atoi(cp);

      trunkStep(TRUNK_STEP_RECORD);
      return false;
}

bool Trunk::scrTransfer(void)
{
      unsigned len;
      char *cp = (char *)group->getLast("transfer");
      if(cp)
            strncpy(data.dialxfer.digits, cp, sizeof(data.dialxfer.digits));
      else
            data.dialxfer.digits[0] = 0;
      len = strlen(data.dialxfer.digits);

      while(NULL != (cp = getValue(NULL)) && len < sizeof(data.dialxfer.digits))
      {
            strncpy(data.dialxfer.digits + len, cp, sizeof(data.dialxfer.digits) - len);
            len = strlen(data.dialxfer.digits);
      }

      data.dialxfer.digits[sizeof(data.dialxfer.digits) - 1] = 0;
      data.dialxfer.interdigit = group->getDialspeed();
      data.dialxfer.digit = data.dialxfer.digits;
      data.dialxfer.exit = true;
      data.dialxfer.timeout = 0;
      cp = getKeyword("onhook");
      if(!cp)
            cp = getKeyword("flash");
      if(!cp)
            cp = getValue(group->getLast("flash"));
      data.dialxfer.onhook = getMSTimeout(cp);
      cp = getKeyword("dialtone");
      if(!cp)
            cp = getKeyword("offhook");
      if(!cp)
            cp = getValue(group->getLast("dialtone"));
        data.dialxfer.offhook = getMSTimeout(cp);
      trunkStep(TRUNK_STEP_FLASH);
      return false;
}

bool Trunk::scrHold(void)
{
      const char *cp = group->getLast("hold");
      if(!cp)
            cp = "";

      strcpy(data.dialxfer.digits, cp);
      data.dialxfer.interdigit = group->getDialspeed();
        data.dialxfer.digit = data.dialxfer.digits;
        data.dialxfer.exit = true;
        data.dialxfer.timeout = 0;
      cp = getKeyword("onhook");
      if(!cp)
            cp = getKeyword("flash");
      if(!cp)
            cp = getValue(group->getLast("flash"));
        data.dialxfer.onhook = getMSTimeout(cp);
      cp = getKeyword("offhook");
      if(!cp)
            cp = getKeyword("dialtone");
      if(!cp)
            cp = getValue(group->getLast("dialtone"));
        data.dialxfer.offhook = getMSTimeout(cp);
      trunkStep(TRUNK_STEP_FLASH);
      return false;
}

bool Trunk::scrSpeak(void)
{
      Translator *tts;
      char *err;
      const char *member = getMember();
      const char *gain = getKeyword("gain");
      const char *speed = getKeyword("speed");
      const char *pitch = getKeyword("pitch");
      const char *lang = getKeyword("language");
      const char *voice = getKeyword("voice");
      const char *vol = getKeyword("volume");

      if(!vol)
            vol = getSymbol(SYM_VOLUME);

      if(!vol)
            vol = "100";

      if(voice && !lang)
            lang = keyvoices.getLast(voice);

      if(!lang)
            lang = getSymbol(SYM_LANGUAGE);

      apppath[0] = 0;

      if(!member)
            member="all";

      data.play.text = getKeyword("text");
      if(!stricmp(member, "any"))
            data.play.mode = PLAY_MODE_ANY;
      else
            data.play.mode = PLAY_MODE_NORMAL;

      data.play.term = 0;
      data.play.voice = voice;

      tts = getTranslator(lang);

      if(!tts)
      {
            error("language-unsupported");
            return true;
      }
      err = tts->speak(this);
      if(err)
      {
            error(err);
            return true;
      }
      while(*data.play.name == ',')
            ++data.play.name;

      if(gain)
            data.play.gain = (float)strtod(gain, NULL);
      else
            data.play.gain = 0.0;

      if(!speed)
            speed = "normal";

      if(!stricmp(speed, "fast"))
            data.play.speed = SPEED_FAST;
      else if(!stricmp(speed, "slow"))
            data.play.speed = SPEED_SLOW;
      else
            data.play.speed = SPEED_NORMAL;

      if(pitch)
            data.play.pitch = (float)strtod(pitch, NULL);
      else
            data.play.pitch = 0.0;

      data.play.extension = getKeyword("extension");
      if(!data.play.extension)
            data.play.extension = getSymbol(SYM_EXTENSION);

      data.play.offset = data.play.limit = 0;
      data.play.timeout = 0;
      data.play.maxtime = 0;
      data.play.repeat = 0;
      data.play.lock = false;
      data.play.volume = atoi(vol);
      trunkStep(TRUNK_STEP_PLAY);
      return false;
}
      
bool Trunk::scrCommit(void)
{
      char buffer[80];
      const char *login = getSymbol(SYM_LOGIN);

      if(!login)
      {
            error("not-logged-in");
            return true;
      }
      
      if(!isUser(login))
      {     
            error("not-user");
            return true;
      }

      snprintf(buffer, sizeof(buffer), "save user %s\n", login);
      control(buffer);
      advance();
      return true;
}     

bool Trunk::scrControl(void)
{
      unsigned len = 0;
      char buffer[PIPE_BUF / 2];
      const char *value;
      const char *login = getSymbol(SYM_LOGIN);

#define     WORKSPC ((PIPE_BUF / 2) - 5)

      if(!login)
      {
            error("no-login");
            return true;
      }

      if(stricmp(login, "admin"))
      {
            error("admin-required");
            return true;
      }

      while(len < WORKSPC && NULL != (value = getValue(NULL)))
      {
            if(len > 0)
                  buffer[len++] = ' ';
            while(*value && len < WORKSPC)
                  buffer[len++] = *(value++);
      }
      if(len)
      {
            buffer[len++] = '\n';
            buffer[len] = 0;
            control(buffer);
      }
      advance();
      return true;
}

bool Trunk::scrDial(void)
{
      unsigned len = 0, ilen = 0;
      const char *cp;
      const char *mem = getMember();
      char digits[64];
      char *digbuf = digits;
      char intprefix[5];
      bool intflag = false, natflag = false, soft = false;

      if(!mem)
            mem = "dial";

      data.dialxfer.dialer = DTMF_DIALER;
      if(!stricmp(mem, "dtmf"))
            soft = true;
      else if(!stricmp(mem, "pulse"))
      {
            data.dialxfer.dialer = PULSE_DIALER;
            soft = true;
      }
      else if(!stricmp(mem, "mf"))
      {
            data.dialxfer.dialer = MF_DIALER;
            soft = true;
      }

      cp = getKeyword("offhook");
      if(!cp)
            cp = getKeyword("flash");

      if(cp)
            data.dialxfer.offhook = getMSTimeout(cp);
      else
            data.dialxfer.offhook = 0;

      cp = getKeyword("onhook");
      if(cp)
            data.dialxfer.onhook = getMSTimeout(cp);
      else
            data.dialxfer.onhook = 0;

      while(NULL != (cp = getValue(NULL)) && len < sizeof(digits) - 1)
      {
            if(intflag)
                  intflag = false;
            while(*cp && len < sizeof(digits) - 1)
            {
                  switch(*cp)
                  {
                  case '0':
                  case '1':
                  case '2':
                  case '3':
                  case '4':
                  case '5':
                  case '6':
                  case '7':
                  case '8':
                  case '9':
                        if(intflag && ilen < 4)
                        {
                              intprefix[ilen++] = *cp;
                              break;
                        }
                  case '*':
                  case '#':
                  case ',':
                  case '.':
                  case 'a':
                  case 'A':
                  case 'b':
                  case 'B':
                  case 'c':
                  case 'C':
                  case 'd':
                  case 'D':
                        digits[len++] = *cp;
                        break;
                  case 's':
                  case 'S':
                  case 'k':
                  case 'K':
                        if(soft)
                              digits[len++] = *cp;
            
                        intflag = false;
                        break;      
                  case 't':
                  case 'T':
                  case 'p':
                  case 'P':
                  case '!':
                  case 'f':
                  case 'F':
                  case 'm':
                  case 'M':
                        if(!stricmp(mem, "dial") || soft)
                        {
                              soft = true;
                              digits[len++] = *cp;
                        }
                        intflag = false;
                        break;      
                  case '+':
                        if(!len)
                              intflag = true;
                        break;
                  default:
                        intflag = false;
                        break;
                  }
                  ++cp;
            }
      }
      digits[len] = 0;
      intprefix[ilen] = 0;
      digbuf = digits;

      cp = getKeyword("country");
      if(!cp)
            cp = "1";

      if(ilen)
      {
            if(!stricmp(intprefix, cp))
            {
                  natflag = true;
                  ilen = 0;
                  digbuf += strlen(cp);
            }
      }

      cp = getKeyword("prefix");
      if(!cp)
      {
            if(!strnicmp(mem, "loc", 3))
                  cp = group->getLast("local");
            else if(!strnicmp(mem, "nat", 3))
                  cp = group->getLast("national");
            else if(!stricmp(mem, "cell"))
                  cp = group->getLast("cell");
            else if(!strnicmp(mem, "int", 3))
                  cp = group->getLast("international");
            else if(ilen)
                  cp = group->getLast("international");
            else if(natflag)
                  cp = group->getLast("national");
            else
                  cp = group->getLast("prefix");

            if(cp)
                  if(!strnicmp(digits, cp, sizeof(cp)))
                        cp = "";
      }
      if(!cp)
            cp = "";

      strcpy(data.dialxfer.digits, cp);
      len = strlen(cp);

      strncpy(data.dialxfer.digits + len, digbuf, sizeof(data.dialxfer.digits) - len - 1);
      len += strlen(digbuf);

      cp = getKeyword("suffix");
      if(cp)
      {
            strncpy(data.dialxfer.digits + len, cp, sizeof(data.dialxfer.digits) - len - 1);
            len += strlen(cp);
      }
      data.dialxfer.digits[len] = 0;
      data.dialxfer.callingdigit = getKeyword("origin");
      data.dialxfer.digits[sizeof(data.dialxfer.digits) - 1] = 0;
      data.dialxfer.interdigit = group->getDialspeed();
      data.dialxfer.digittimer = data.dialxfer.interdigit / 2;
      data.dialxfer.digit = data.dialxfer.digits;
      data.dialxfer.exit = false;

      if(soft || !stricmp(mem, "digits"))
            data.dialxfer.timeout = 0;
      else
      {
            cp = getKeyword("maxTime");
            if(cp)
                  data.dialxfer.timeout = getSecTimeout(cp);
            else
                  data.dialxfer.timeout = group->getAnalysis() * 1000;
      }
//    advance();
//    return true;

      if(soft)
            trunkStep(TRUNK_STEP_SOFTDIAL);
      else
            trunkStep(TRUNK_STEP_DIALXFER);
      return false;
}

bool Trunk::scrSay(void)
{
      char *cp;
      const char *prefix = getPrefixPath();
      const char *cache = getKeyword("cache");
      const char *gain = getKeyword("gain");
      const char *speed = getKeyword("speed");
      const char *pitch = getKeyword("pitch");
      const char *vol = getKeyword("volume");
      unsigned len = 0, lc = 0;
      unsigned long sum = 0l, sum1 = 0l;
      const char *mem = getMember();

      if(!mem)
            mem = "text";

      if(!stricmp(mem, "nocache") && !tts)
      {
            advance();
            return true;
      }

      if(!stricmp(mem, "cache") && !tts)
      {
            advance();
            return true;
      }

      if(cache && !tts)
            cache = NULL;

      if(!hasTTS())
      {
            advance();
            return true;
      }

      if(!vol)
            vol = getSymbol(SYM_VOLUME);

      if(!vol)
            vol = "100";

      data.play.list[0] = 0;

      while(NULL != (cp = getValue(NULL)) && len < sizeof(data.play.list))
      {
            if(len)
            {
                  if(tts)
                        data.play.list[len++] = ' ';
                  else
                        data.play.list[len++] = '+';
            }
            strncpy(data.play.list + len, cp, sizeof(data.play.list) - len);
            len += strlen(cp);
      }
      data.play.list[len] = 0;
      if(!data.play.list[0])
      {
            error("tts-no-output");
            return true;
      }


      data.play.text = getKeyword("text");
      if(!data.play.text)
            data.play.text = data.play.list;

      data.play.voice = getKeyword("voice");
      if(!data.play.voice)
            data.play.voice = getSymbol(SYM_VOICE);
      data.play.list[sizeof(data.play.list) - 1] = 0;
#ifdef      HAVE_TGI
      if(!tts)
      {
            libtts(data.play.list, TTS_GATEWAY_TEXT);
            sprintf(data.play.list, "temp/.tts.%d.ul", id);
      }
#else
      if(!tts)
      {
            error("no-tts");
            return true;
      }
#endif
      data.play.name = data.play.list;
      data.play.repeat = 0;
      data.play.lock = false;
      data.play.maxtime = 0;
      data.play.lock = false;
      if(tts)
            data.play.timeout = 0;
      else
            data.play.timeout = getSecTimeout(getSymbol(SYM_PLAYWAIT));
      data.play.volume = atoi(vol);
      data.play.term = 0;
      data.play.mode = PLAY_MODE_TEMP;
      data.play.limit = data.play.offset = 0;
      data.play.extension = NULL;

      if(gain)
            data.play.gain = (float)strtod(gain, NULL);
      else
            data.play.gain = 0.0;

      if(!speed)
            speed = "normal";

      if(!stricmp(speed, "fast"))
            data.play.speed = SPEED_FAST;
      else if(!stricmp(speed, "slow"))
            data.play.speed = SPEED_SLOW;
      else
            data.play.speed = SPEED_NORMAL;

      if(pitch)
            data.play.pitch = (float)strtod(pitch, NULL);
      else
            data.play.pitch = 0.0;

      if(NULL != (cp = getKeyword("offset")))
            data.play.offset = atol(cp);
      if(NULL != (cp = getKeyword("volume")))
            data.play.volume = atoi(cp);
      if(NULL != (cp = getKeyword("timeout")) && !tts)
            data.play.timeout = getSecTimeout(cp);
      if(NULL != (cp = getKeyword("limit")))
            data.play.limit = atol(cp);

      if(!stricmp(mem, "cache") && !cache)
      {
            sprintf(apppath, "cache/-tts-%s-", data.play.voice);
            len = strlen(apppath);
            cp = data.play.list;
            while(*cp)
            {
                  if(*cp != ' ')
                  {
                        ++lc;
                        sum ^= (sum << 3) ^ (*cp & 0x1f);
                        sum1 ^= ((sum >> 29) ^ lc) ^ (*cp & 0x0f);
                  }
                  ++cp;
            }
            cp = data.play.list;
            while(*cp)
            {
                  sum1 = (sum1 << 3) ^ (*cp & 0x1f);
                  ++cp;
            }
            sprintf(apppath + len, "%08lx%08lx", sum, sum1);
            cp = apppath;
            while(*cp)
            {
                  *cp = tolower(*cp);
                  ++cp;
            }
            data.play.cache = apppath;
      }
      else if(cache)
      {
            if(!prefix && !strchr(cache, '/'))
                  prefix = "cache";
            if(prefix)
            {
                  snprintf(apppath, sizeof(apppath), "%s/%s", prefix, cache);
                  cache = apppath;
            }
            data.play.cache = cache;
      }
      else
            data.play.cache = NULL;

      if(tts)
      {
            if(!stricmp(mem, "file"))
                  data.play.mode = PLAY_MODE_FILE;
            else
                  data.play.mode = PLAY_MODE_TEXT;
            trunkStep(TRUNK_STEP_PLAY);
      }
      else
            trunkStep(TRUNK_STEP_PLAYWAIT);
      return false;
}

#ifdef      XML_SCRIPTS
bool Trunk::scrLoad(void)
{
      Module *mod;
      const char *kw = getMember();
      Name *scr = getObject();
      Line *line = getScript();
      int count;
      const char *prefix;
      char *sym;
      char *value;
      char *str;
      char *var;
      char *cp;
      int len;

      if(!kw)
            kw = "put";

      if(!stricmp(kw, "xml"))
      {
            var = getValue("");
            if(altimage)
            {
                  altimage->purge();
                  delete altimage;
                  altimage = NULL;
                  altmodule = NULL;
            }
            mod = getModule(MODULE_XML, var);
            if(mod)
            {
                  altimage = mod->getXML();
                  altmodule = mod;
            }
      }
 
      if(!altimage)
      {
            error("no-xml-parser");
            return true;
      }

      if(!stricmp(kw, "xml"))
      {
            advance();
            return true;
      }

      altimage->purge();
      data.load.attach = false;
      if(!stricmp(kw, "post"))
            data.load.post = true;
      else
            data.load.post = false;
      kw = getKeyword("section");
      if(!kw)
            kw = "#";
      if(*kw != '#')
      {
            var = (char *)altimage->alloc(strlen(kw + 1));
            var[0] = '#';
            strcpy(var + 1, ++kw);
            kw = var;
      }
      data.load.section = kw;
      kw = getKeyword("maxTime");   
      if(!kw)
            kw = "60";
      data.load.image = altimage;
      data.load.timeout = getSecTimeout(kw);
      data.load.parent = NULL;
      data.load.gosub = false;
      count = line->argc + 1;
      data.load.vars = (char **)altimage->alloc(count * sizeof(char *));
      data.load.url = getValue(NULL);
      if(!data.load.url)
      {
            error("no-xml-url");
            return true;
      }

      data.load.userid[0] = 0;
#ifdef      USER_HOSTING
      if(!strnicmp(data.load.url, "~/", 2))
      {
            snprintf(data.load.filepath, 65, "%s", scr->name);
            cp = strchr(data.load.filepath, ':');
            if(cp)
                  *cp = 0;
            if(data.load.filepath[0] == '~')
            {
                  snprintf(data.load.userid, sizeof(data.load.userid), 
                        "%s", data.load.filepath + 1);
                  prefix = keyusers.getLast(data.load.filepath + 1);
            }
            else if(data.load.filepath[0] == '#')
            {
                  prefix = getSymbol(SYM_HOME);
                  if(!prefix)
                        prefix = "";
                  if(*prefix)
                        prefix = keyusers.getLast(prefix);
                  else
                        prefix = "xml";
            }
            else
                  prefix = "xml";
            if(!prefix)
            {
                  error("no-such-user");
                  return true;
            }
            snprintf(data.load.filepath, sizeof(data.load.filepath),
                  "%s/%s", prefix, data.load.url + 2);
            data.load.url = data.load.filepath;
      }
      else if(data.load.url[0] == '~' && NULL != (cp = strchr(data.load.url, '/')))
      {
            strncpy(data.load.filepath, data.load.url, 65);
            str = strchr(data.load.filepath, '/');
            if(str)
                  *str = 0;
            prefix = keyusers.getLast(data.load.filepath + 1);
            if(prefix)
                  ++cp;
            else
            {
                  prefix = "xml";
                  cp = (char *)(data.load.url + 1);
            }
            snprintf(data.load.filepath, sizeof(data.load.filepath),
                  "%s/%s", prefix, cp);
            data.load.url = data.load.filepath;
      }
#endif

      setSymbol(SYM_HOME, data.load.userid);

      if(!strnicmp(data.load.url, "http:", 5))
            altimage->setProxy(keyproxy.getHTTPServer(), keyproxy.getHTTPPort());
      else
            altimage->setProxy(NULL, 0);
            
      count = 0;
      while(NULL != (sym = getOption(NULL)))
      {
            value = getContent(sym);
            if(*sym == '%' || *sym == '@')
                  ++sym;
            len = (strlen(sym) + strlen(value) * 2);
            var = (char *)altimage->alloc(len);
            data.load.vars[count++] = var;
            urlEncode(sym, var, len);
            strcat(var, "=");
            len -= strlen(var);
            var += strlen(var);
            urlEncode(sym, value, len);
      }
      data.load.vars[count] = NULL;
      if(NULL != (kw = getKeyword("timeout")))
            data.load.timeout = atoi(kw) * 1000;            
      trunkStep(TRUNK_STEP_LOADER);
      return false;
}
#endif

bool Trunk::scrAltPlay(void)
{
      if(hasTTS())
      {
            advance();
            return true;
      }
      return scrPlay();
}

bool Trunk::scrAltSpeak(void)
{
      if(hasTTS())
      {
            advance();
            return true;
      }
      return scrSpeak();
}

bool Trunk::scrLogout(void)
{
      Symbol *sym = getEntry(SYM_LOGIN, 0);

      if(!sym)
      {
            error("logout-failed");
            return true;
      }

      strcpy(sym->data, "none");
      if(debug)
            debug->debugLogin(this);
      advance();
      return true;
}

bool Trunk::scrChange(void)
{
      const char *login = getSymbol(SYM_LOGIN);
      const char *id = getKeyword("id");
      const char *value = getKeyword("value");
      char name[80];
      Symbol *sym, *def;
      Line *line = getScript();

      if(!isUser(login))
      {
            error("no-login");
            return true;
      }

      if(!id)
            id = getValue(NULL);

      if(!stricmp(line->cmd, "reset"))
            value = NULL;
      else if(!value)
      {
            value = getValue(NULL);
            if(!value)
                  return "no-value";
      }

      if(!id)
      {
            error("no-property");
            return true;
      }

      if(!stricmp(id, "password") || !stricmp(id, "session"))
      {
            error("invalid-property");
            return true;
      }

      if(!stricmp(id, "port") || !stricmp(id, "type"))
      {
            error("unchangable-property");
            return true;
      }

      snprintf(name, sizeof(name), "default.%s", id);
      def = globals.getEntry(name, 0);
      if(!def)
      {
            error("unknown-property");
            return true;
      }
      
      snprintf(name, sizeof(name), "%s.%s", login, id);
      sym = globals.getEntry(name, def->flags.size);
      if(!sym)
      {
            error("cannot-change");
            return true;
      }
      
      if(value)
      {
            snprintf(sym->data, sym->flags.size + 1, "%s", value);
            sym->flags.initial = false;
      }
      else
            sym->flags.initial = true;
      sym->flags.readonly = true;
      advance();
      return true;
}           

bool Trunk::scrPassword(void)
{
      const char *login = getSymbol(SYM_LOGIN);
      const char *id = NULL;
      const char *pwd = getValue(getKeyword("password"));
      char name[65];
      Symbol *sym, *def = globals.getEntry("default.password");
      
      if(!login)
      {
            error("no-login");
            return true;
      }

      if(!isUser(login))
      {
            error("password-no-login");
            return true;
      }

      if(!pwd)
      {
            error("password-missing");
            return true;
      }

      if(!*pwd)
            pwd = "none";

      if(!stricmp(login, "admin"))
            id = getKeyword("id");

      if(!id)
            id = login;

      snprintf(name, sizeof(name), "%s.password", id);
      sym = globals.getEntry(name, 0);
      if(!sym)
      {
            sym = globals.getEntry(name, def->flags.size);
            if(!sym)
            {
                  error("no-password");
                  return true;
            }
            snprintf(sym->data, sym->flags.size + 1, "%s", pwd);
            sym->flags.initial = false;
            sym->flags.readonly = true;
            advance();
            return true;
      }
      if(sym->flags.initial)
      {
            error("no-password");
            return true;
      }
      if(isalpha(sym->data[0]) && stricmp(sym->data, "none") && stricmp(sym->data, "new"))      
      {
            error("password-inactive");
            return true;
      }

      snprintf(sym->data, sym->flags.size + 1, "%s", pwd);
      sym->flags.initial = false;
      sym->flags.readonly = true;
      advance();
      return true;
}
      
bool Trunk::scrLogin(void)
{
      const char *id = getKeyword("id");
      const char *pwd = getKeyword("password");
      char name[65];
      Symbol *sym = getEntry(SYM_LOGIN, 0);
      Symbol *vrf;

      if(!sym)
      {
            error("login-failed");
            return true;
      }

      if(!id)
            id = getValue(NULL);

      if(!pwd)
            pwd = getValue("none");

      if(!id || !pwd)
      {
            error("login-missing-info");
            return true;
      }

      if(!*pwd)
            pwd = "none";

      if(!isUser(id))
      {
            error("login-invalid-id");
            return true;
      }

      snprintf(name, sizeof(name), "%s.password", id);
      vrf = globals.getEntry(name, 0);
      if(!vrf || vrf->flags.initial)
      {
            error("login-not-found");
            return true;
      }

      if(!vrf->data[0])
            strcpy(vrf->data, "none");

      if(stricmp(vrf->data, pwd))
      {
            error("login-password-invalid");
            return true;
      }

      snprintf(sym->data, sym->flags.size + 1, "%s", id);
      if(debug)
            debug->debugLogin(this);
      advance();
      return true;
}

bool Trunk::scrPlay(void)
{
      Name *scr = getObject();
      char *cp;
      unsigned long mask = 0;
      const char *prefix = getPrefixPath();
      char *gain = getKeyword("gain");
      char *speed = getKeyword("speed");
      char *pitch = getKeyword("pitch");
      char *vol = getKeyword("volume");
      bool feed = false;
      unsigned len = 0;

      snprintf(apppath, sizeof(apppath), "%s", scr->name);
      cp = strstr(apppath, "::");
      if(cp)
            *cp = 0;

      const char *member = getMember();
      if(!member)
            member = "all";

      if(!stricmp(member, "feed"))
            feed = true;

      if(!stricmp(member, "moh"))
      {
            data.play.mode = PLAY_MODE_MOH;
      }
      else if(!stricmp(member, "any"))
            data.play.mode = PLAY_MODE_ANY;
      else if(!stricmp(member, "one"))
            data.play.mode = PLAY_MODE_ONE;
      else if(!stricmp(member, "temp") || !stricmp(member, "tmp"))
            data.play.mode = PLAY_MODE_TEMP;
      /* else if(0 != (mask = getScriptMask(member)))
            data.play.mode = PLAY_MODE_ANY; */
      else
            data.play.mode = PLAY_MODE_NORMAL;

      data.play.text = getKeyword("text");
      data.play.voice = getKeyword("voice");

      if(mask)
      {
            if((mask & scr->mask) != mask)
            {
                  advance();
                  return true;
            }
      }

      data.play.list[0] = 0;
      while(NULL != (cp = getValue(NULL)))
      {
            if(len)
                  data.play.list[len++] = ',';
            if(prefix)
                  snprintf(data.play.list + len, sizeof(data.play.list) - len, "%s/%s", prefix, cp);
            else
                  strncpy(data.play.list + len, cp, sizeof(data.play.list) - len);
            len = strlen(data.play.list);
            if(feed)
                  break;
      }

      if(!vol)
            vol = getSymbol(SYM_VOLUME);
      if(!vol)
            vol = "100";

      data.play.list[sizeof(data.play.list) - 1] = 0;
      data.play.name = data.play.list;
      data.play.volume = atoi(vol);
      data.play.timeout = 0;
      data.play.repeat = 0;
      data.play.lock = false;
      data.play.maxtime = 0;
      data.play.term = 0;
      data.play.lock = false;
      data.play.extension = getKeyword("extension");
      if(!data.play.extension)
            data.play.extension = getSymbol(SYM_EXTENSION);

      if(feed)
            data.play.maxtime = getTimeout("maxTime");

      while(*data.play.name == ',')
            ++data.play.name;
      if(!*data.play.name)
      {
            error("play-no-files");
            return true;
      }

      if(gain)
            data.play.gain = (float)strtod(gain, NULL);
      else
            data.play.gain = 0.0;

      if(!speed)
            speed = "normal";

      if(!stricmp(speed, "fast"))
            data.play.speed = SPEED_FAST;
      else if(!stricmp(speed, "slow"))
            data.play.speed = SPEED_SLOW;
      else
            data.play.speed = SPEED_NORMAL;

      if(pitch)
            data.play.pitch = (float)strtod(pitch, NULL);
      else
            data.play.pitch = 0.0;

      data.play.limit = data.play.offset = 0;

      if(NULL != (cp = getKeyword("offset")))
            data.play.offset = atol(cp);

      if(NULL != (cp = getKeyword("limit")))
            data.play.limit = atol(cp);

      if(NULL != (cp = getKeyword("volume")))
            data.play.volume = atoi(cp);

      trunkStep(TRUNK_STEP_PLAY);
      return false;
}     

bool Trunk::scrFlash(void)
{
      const char *cp = getKeyword("onhook");
      if(!cp)
            cp = getKeyword("flash");
      if(!cp)
            cp = getValue(group->getLast("flash"));
      data.dialxfer.onhook = getMSTimeout(cp);

      cp = getKeyword("offhook");
      if(!cp)
            cp = getKeyword("dialtone");
      if(!cp)
            cp = getValue(group->getLast("dialtone"));

      data.dialxfer.offhook = getMSTimeout(cp);

      data.dialxfer.digit = NULL;
      trunkStep(TRUNK_STEP_FLASH);
      return false;
}

bool Trunk::scrCollect(void)
{
      unsigned copy = 0;
      Symbol *sym = NULL;
      const char *cp = getKeyword("count");
      const char *mem = getMember();
      const char *var = getKeyword("var");
      const char *ignore = getKeyword("ignore");
      const char *term = getKeyword("exit");
      unsigned digpos = 0, digscan;
      bool trim = false;

      if(!ignore)
            ignore = "";

      if(!term)
            term = "";

      if(!mem)
            mem = "all";

      if(!cp)
            cp = getKeyword("digits");

      if(!cp)
            cp = getValue("0");

      if(var)
            if(*var == '&')
                  ++var;

      data.collect.count = atoi(cp);
      if(data.collect.count > MAX_DIGITS)
            data.collect.count = MAX_DIGITS;

      if(var)
            sym = getLocal(var, data.collect.count);

      if(sym)
      {
            if(sym->flags.readonly)
            {
                  error("collect-read-only");
                  return true;
            }
      }

      if(sym)
      {
            copy = sym->flags.size;
            sym->data[0] = 0;
            if(sym->flags.commit)
                  commit(sym);
      }

      if(copy > data.collect.count)
            copy = data.collect.count;          

      data.collect.var = (void *)sym;
      data.collect.map = NULL;      data.collect.timeout = getInterdigit("timeout");
      data.collect.term = getDigitMask("exit");
      data.collect.ignore = getDigitMask("ignore");
      if(!stricmp(mem, "clear"))
      {
            digits = 0;
            dtmf.bin.data[0] = 0;
      }
      else if(!stricmp(mem, "trim"))
            trim = true;
      else if(!stricmp(mem, "input"))
            trim = true;
      
      while(digpos < digits)
      {
            if(strchr(term, dtmf.bin.data[digpos]))
            {
                  if(copy > digpos)
                        copy = digpos;
                  if(sym)
                  {
                        if(copy)
                              strncpy(sym->data, dtmf.bin.data, copy);
                        sym->data[copy] = 0;
                        if(sym->flags.commit)
                              commit(sym);
                        digscan = ++digpos;
                        while(digscan < digits)
                        {
                              dtmf.bin.data[digscan - digpos] = dtmf.bin.data[digscan];
                              ++digscan;
                        }
                        digits = digscan - digpos;
                        dtmf.bin.data[digits] = 0;
                        digits = digscan;
                  }     
                  else
                  {
                        digits = digpos;
                        dtmf.bin.data[digits] = 0;
                  }
                  advance();
                  return true;
            }

            if(strchr(ignore, dtmf.bin.data[digpos]))
            {
                  digscan = digpos;
                  while(digscan < digits)
                  {
                        dtmf.bin.data[digscan] = dtmf.bin.data[digscan + 1];
                        ++digscan;
                  }
                  continue;
            }     

            if(++digpos >= data.collect.count)
            {
                  if(sym)
                  {
                        if(copy)
                              strncpy(sym->data, dtmf.bin.data, copy);
                        sym->data[copy] = 0;
                        if(sym->flags.commit)
                              commit(sym);
                        while(digpos < digits)
                        {
                              dtmf.bin.data[digpos - data.collect.count] = dtmf.bin.data[digpos];
                              ++digpos;
                        }
                        digits = digpos - data.collect.count;
                        dtmf.bin.data[digits] = 0;
                  }
                  else if(trim || *term)
                  {
                        digits = digpos;
                        dtmf.bin.data[digits] = 0;
                  }
                  advance();
                  return true;
            }
      }
      trunkStep(TRUNK_STEP_COLLECT);
      return false;
}

bool Trunk::scrAccept(void)
{
      if (group->getAccept())
      {
            advance();
            return true;
      }

      trunkStep(TRUNK_STEP_ACCEPT);
      return false;
}

bool Trunk::scrReject(void)
{
      trunkStep(TRUNK_STEP_REJECT);
      return false;
}
      
bool Trunk::scrAnswer(void)
{
      const char *kw;

      if(NULL != (kw = getKeyword("maxRing")))
            data.answer.rings = atoi(kw);
      else  
            data.answer.rings = atoi(getValue("0"));
      if(NULL != (kw = getKeyword("maxTime")))
            data.answer.timeout = getSecTimeout(kw);
      else
            data.answer.timeout =  getSecTimeout(getValue(group->getLast("ringtime")));

      data.answer.station = getStation();
      data.answer.fax = getKeyword("fax");

      trunkStep(TRUNK_STEP_ANSWER);
      return false;
}     

bool Trunk::scrHangup(void)
{
      TrunkEvent event;
      Trunk *trk;
      TrunkGroup *grp = NULL;
      const char *mem = getMember();
      unsigned port, tspan;
      const char *id = getKeyword("id");

      if(!mem)
            mem = "self";
      else if(!isAdmin())
      {
            error("admin-required");
            return true;
      }

      if(!stricmp(mem, "port"))
      {
            event.id = TRUNK_STOP_DISCONNECT;
            mem = getValue(id);
            trk = driver->getTrunkId(mem);

            if(!trk)
            {
                  error("hangup-port-id");
                  return true;
            }

            if(trk == this)
            {
                  error("hangup-self-reference");
                  return true;
            }

            trk->postEvent(&event);
            advance();
            return true;
      }

      if(!stricmp(mem, "span"))
      {
            mem = getValue(id);
            if(!mem)
            {
                  error("hangup-span-id");
                  return true;
            }
            tspan = atoi(mem);
            if(driver->spanEvent(tspan, &event))
                  advance();
            else
                  error("hangup-span-invalid");
            return true;                  
      }

        if(!stricmp(mem, "card"))
        {
                mem = getValue(id);
                if(!mem)
                {
                        error("hangup-card-id");
                        return true;
                }
                tspan = atoi(mem);
                if(driver->cardEvent(tspan, &event))
                        advance();
                else
                        error("hangup-card-invalid");
                return true;
        }

      if(!stricmp(mem, "group"))
      {
            mem = getValue(id);
            if(mem)
                  grp = getGroup(mem);
            if(!grp)
            {
                  error("hangup-group-id");
                  return true;
            }

              for(port = 0; port < driver->getTrunkCount(); ++port)
            {
                  if(driver->getTrunkGroup(port) != grp)
                              continue;

                      trk = driver->getTrunkPort(port);
                    if(!trk || trk == this)
                              continue;

                  event.id = TRUNK_STOP_DISCONNECT;
                  trk->postEvent(&event);
            }

            advance();
            return true;
      }
      
      if(id)
      {
            if(!strchr(id, '-') && !isAdmin())
            {
                  error("admin-required");
                  return true;
            }
            trk = driver->getTrunkId(id);
            if(!trk)
            {
                  error("hangup-id-invalid");
                  return true;
            }
            event.id = TRUNK_STOP_DISCONNECT;
            trk->postEvent(&event);
            advance();
            return true;
      }

      if(!ScriptInterp::signal((unsigned int)0))
            scrExit();

      return true;
}

bool Trunk::scrAudit(void)
{
      const char *mem = getMember();
      char buffer[256];
      char overflow[256];
      Line *line = NULL;
      char *tag, *val;
      int argc = 0;
      unsigned len = 0;
      bool post = false;

      if(!mem)
            mem = "set";

      if(!stricmp(mem, "clear"))
            cdrv = NULL;
      else if(!stricmp(mem, "log"))
            line = getScript();
      else if(!stricmp(mem, "post"))
      {
            post = true;
            line = getScript();
      }
      else
            cdrv = getScript();

      if(!line)
      {
            advance();
            return true;
      }

      buffer[0] = 0;
      while(argc < line->argc && len < sizeof(buffer))
      {
            tag = line->args[argc++];
            if(*tag == '%')
                  val = getContent(tag);
            else if(*tag == '=')
                  val = getContent(line->args[argc++]);
            else
                  continue;

            if(!val)
                  continue;

            if(!*val)
                  continue;

            urlEncode(val, overflow, sizeof(overflow));
            if(len)
                  buffer[len++] = ' ';
            snprintf(buffer + len, sizeof(buffer) - len, "%s=%s", ++tag, overflow);
            len = strlen(buffer);
      }
      if(post)
      {
            audit(this, buffer);
            cdrv = NULL;
      }
      else
            alog(this, buffer);
      advance();
      return true;
}

bool Trunk::scrDebug(void)
{
      char buf[256];
      char *value;

      buf[0] = 0;
      while(NULL != (value = getValue(NULL)))
            strcat(buf, value);
      debug->debugScript(this, buf);
      advance();
      return true;
}

bool Trunk::scrSync(void)
{
      const char *cp;
      timeout_t timer = getTimeout("time");
      time_t now;
      const char *mem = getMember();

      if(!mem)
            mem = "none";

      time(&now);


      if(!strnicmp(mem, "max", 3) || !stricmp(mem, "exit"))
      {
            if(timer)
                  exittimer = starttime + (timer / 1000);
            else
                  exittimer = 0;
            advance();
            return true;
      }

      if(!strnicmp(mem, "time", 4) || !stricmp(mem, "start"))
      {
            if(timer)
                  synctimer = starttime + (timer / 1000);
            else
                  synctimer = 0;
            advance();
            return true;
      }

      if(!stricmp(mem, "current"))
      {
            if(timer)
                  synctimer = now + (timer / 1000);
            else
                  synctimer = 0;
            advance();
            return true;
      }

      timer = timer - ((now - starttime) * 1000);
      if(timer < 1)
      {
            advance();
            return true;
      }
      data.sleep.wakeup = timer;
      data.sleep.save = NULL;
      cp = getKeyword("maxRing");
      if(!cp)
            cp = getValue("0");
      data.sleep.rings = atoi(cp);
      data.sleep.loops = 1;
      trunkStep(TRUNK_STEP_SLEEP);
      return false;
}

bool Trunk::scrStart(void)
{
      Trunk *trunk;
      TrunkGroup *grp = NULL;
      TrunkEvent event;
      Symbol *sym;
      int argc = 0;
      char *argv[32];
      char *arg = NULL, *tok;
      const char *login = getSymbol("login");
      const char *var = getKeyword("var");
      const char *submit = getKeyword("submit");
      timeout_t exp = 0;
      bool notify = false;
      bool rtn = true;
      const char *mem = getMember();
      char buffer[256];
      char args[512];
      char content[512];
      unsigned alen = 0;
      unsigned offset = 0, last = 0, span = 0;
      bool start = false;
      bool ports = false;
      Name *scr = getObject();
      const char *cp;

      args[0] = 0;

      if(!mem)
            mem = "none";

      if(!stricmp(mem, "wait"))
      {
            exp = getTimeout("maxTime");
            notify = true;
      }
      else if(!stricmp(mem, "port"))
      {
            arg = getKeyword("first");
            if(arg)
                  offset = atoi(arg);
            else
                  offset = atoi(getValue("0"));
            arg = getKeyword("last");
            if(arg)
                  last = atoi(arg);
            else
                  last = offset;
            ports = true;
      }
      else if(!strnicmp(mem, "ext", 3))
      {
            trunk = driver->getExtNumber(getValue("0"));
            if(!trunk)
            {
                  error("invalid-extension");
                  return true;
            }
            offset = last = trunk->id;
            ports = true;
      }
      else if(!stricmp(mem, "trunk") || !stricmp(mem, "trk"))
      {
            trunk = driver->getTrkNumber(getValue("0"));
            if(!trunk)
            {
                  error("invalid-trunk");
                  return true;
            }
            offset = last = trunk->id;
            ports = true;
      }
      else if(!stricmp(mem, "tie"))
      {
            trunk = driver->getTieNumber(getValue("0"));
            if(!trunk)
            {
                  error("invalid-tie");
                  return true;
            }
            offset = last = trunk->id;
            ports = true;
      }
      else if(!stricmp(mem, "span"))
      {
            span = atoi(getValue("1"));
            offset = 0;
            last = driver->getTrunkCount() - 1;
            ports = true;
      }
      else if(!stricmp(mem, "offset"))
      {
            arg = getKeyword("first");
            if(arg)
                  offset = atoi(arg) + id;
            else
                  offset = atoi(getValue("1")) + id;
            arg = getKeyword("last");
            if(arg)
                  last = id + atoi(arg);
            else
                  last = driver->getTrunkCount() - 1;
            ports = true;
      }
      else if(!stricmp(mem, "group"))
            start = true;
      else
            exp = getTimeout("maxTime");

      if(!ports && !span)
      {
            arg = getKeyword("group");
            if(!arg)
                  arg = getValue("*");

            grp = getGroup(arg);
            if(!grp)
            {
                  error("request-unknown-group");
                  return true;
            }
      }

      if(start)
      {
            if(grp)
                  snprintf(args + alen, sizeof(args) - alen, "start %s ", arg);
            else
                  snprintf(args + alen, sizeof(args) - alen, "start %d ", offset);
            alen = strlen(args);
      }

      arg = getKeyword("script");
      if(!arg)
            arg = getValue(NULL);
      if(!arg)
      {
            error("request-no-script");
            return true;
      }

      if(!strnicmp(arg, "::", 2))
      {
            strcpy(content, scr->name);
            tok = strstr(content, "::");
            if(!tok)
                  tok = content + strlen(content);
            strcpy(tok, arg);
            arg = content;
      }

      strncpy(args + alen, arg, sizeof(args) - alen);
      alen = strlen(args);

      cp = getSymbol(SYM_GID);
      if(cp)
            cp = strchr(cp, '-');
      else
            cp = "none";

      if(start || ports || span)
            snprintf(args + alen, sizeof(args) - alen, " %s=%s", SYM_PARENT, cp);
      alen = strlen(args);

      while(NULL != (arg = getOption(NULL)))
      {
            if(*arg != '%')
                  continue;
            urlEncode(getContent(arg), content, sizeof(content));
            snprintf(args + alen, sizeof(args) - alen, " %s=%s", ++arg, content);
            alen = strlen(args);
      }

        if(submit)
        {
                snprintf(buffer, 255, "%s", submit);
                submit = strtok_r(buffer, ",", &tok);
      }

      while(submit)
        {
                sym = getEntry(submit, 0);
                submit = strtok_r(NULL, ",", &tok);
                if(!sym)
                        continue;

            urlEncode(sym->data, content, sizeof(content));
            snprintf(args + alen, sizeof(args) - alen, " %s=%s", sym->id, content);
            alen = strlen(args);
      }

      if(var || notify)
      {
            if(!exp)
                  exp = 1000;

            data.sleep.save = var;
            data.sleep.wakeup = exp;
              data.sleep.loops = 1;
              data.sleep.rings = 0;
            data.sleep.save = NULL;
            trunkStep(TRUNK_STEP_SLEEP);
            rtn = false;
      }
      else
            advance();

      if(start)
      {
            fifo.command(args);
            return rtn;
      }

      argv[argc++] = strtok_r(args, " ", &tok);
      while(argc < 31)
            argv[argc++] = strtok_r(NULL, " ", &tok);

      argv[argc] = NULL;

      if(!ports && !span)
      {
            request(grp, argv, exp / 1000, NULL, getSymbol(SYM_GID));
            return rtn;
      }

      if(offset > last)
            last = offset;

      while(offset <= last)
      {
            trunk = driver->getTrunkPort(offset++);
            if(!trunk)
                  continue;

            if(span)
                  if(trunk->span != span)
                        continue;

            event.id = TRUNK_START_SCRIPT;
            event.parm.argv = argv;
            if(trunk->postEvent(&event))
            {
                  trunk->enterMutex();
                  sym = trunk->getEntry(SYM_LOGIN, 0);
                  if(sym)
                        snprintf(sym->data, sym->flags.size + 1, "%s", login);                  
                  trunk->leaveMutex();
                  break;
            }
      }

      if(offset > last)
      {
            event.id = TRUNK_CHILD_FAIL;
            postEvent(&event);
      }

      return rtn;
}

bool Trunk::scrOptions(void)
{
      const char *gid;
      const char *lang;
      const char *keys;
      const char *err = NULL;
      char voice[256];

      keys = getKeyword("dtmf");
      if(keys)
      {
            if(!stricmp(keys, "on"))
                  flags.digits = DTMF_MODE_ON;
            else if(!stricmp(keys, "off"))
                  flags.digits = DTMF_MODE_OFF;
            else if(!stricmp(keys, "script"))
                  flags.digits = DTMF_MODE_SCRIPT;
            else if(!stricmp(keys, "line"))
                  flags.digits = DTMF_MODE_LINE;
            else
                  err = "options-dtmf-invalid";
      }
      keys = getKeyword("result");
      if(keys)
      {
            gid = getSymbol(SYM_GID);
            if(gid)
                  gid = strchr(gid, '-');
            if(gid)
                  rpclog.setInfo(++gid, keys);
      }
      keys = getKeyword("logging");
      if(keys)
      {
            if(!stricmp(keys, "notice"))
                  slog.level(Slog::levelNotice);
            else if(!stricmp(keys, "debug"))
                  slog.level(Slog::levelDebug);
            else if(!stricmp(keys, "info"))
                  slog.level(Slog::levelInfo);
            else if(!strnicmp(keys, "err", 3))
                  slog.level(Slog::levelError);
            else if(!strnicmp(keys, "warn", 4))
                  slog.level(Slog::levelWarning);
            else
                  err = "options-logging-invalid";
      }
        keys = getKeyword("language");
        if(keys)
      {
            if(getTranslator(keys) != NULL)
                      setSymbol(SYM_LANGUAGE, keys);
            else
                  err = "options-language-invalid";
      }

      keys = getKeyword("dnd");
      if(keys)
      {
            switch(*keys)
            {
            case '0':
            case 'n':
            case 'N':
            case 'f':
            case 'F':
                  flags.dnd = false;
                  break;
            case 'y':
            case 'Y':
            case 't':
            case 'T':
                  flags.dnd = true;
            }
      }

        keys = getKeyword("voice");
        if(keys)
        {
                snprintf(voice, sizeof(voice), "%s/%s", keypaths.getLast("prompts"), keys);
                if(isDir(voice))
            {
                        setSymbol(SYM_VOICE, keys);
                  lang = keyvoices.getLast(keys);
                  if(lang)
                  {
                        if(getTranslator(lang) != NULL)
                              setSymbol(SYM_LANGUAGE, lang);
                        else
                              err = "options-language-invalid";
                  }
            }
            else
                  err = "options-voice-invalid";
        }

      if(err)
            error(err);
      else
            advance();
      return true;
}

#ifdef      HAVE_TGI
bool Trunk::scrCopy(void)
{
      char *cc;
      tgicmd_t cmd;
      const char *prefix = getPrefixPath();
      const char *src = getValue(NULL);
      const char *dest = getValue(NULL);
      const char *mem = getMember();
      char buf1[65], buf2[65];

      if(!mem)
            mem = "copy";

      if(!stricmp(mem, "append"))
            cc = "-append";
      else
            cc = "-copy";

      if(!src || !dest)
      {
            error("copy-files-missing");
            return true;
      }

      if(*src == '-' || *dest == '-')
      {
            error("copy-files-invalid");
            return true;
      }

      src = urlEncode(src, buf1, 64);
      dest = urlEncode(dest, buf2, 64);

      if(prefix)
            snprintf(cmd.cmd, sizeof(cmd.cmd), "%s %s/%s %s/%s",
                  cc, prefix, src, prefix, dest);
      else
            snprintf(cmd.cmd, sizeof(cmd.cmd), "cc %s %s %s",
                  cc, src, dest);

      data.sleep.wakeup = getTimeout("maxTime");
      if(!data.sleep.wakeup)
            data.sleep.wakeup = 30000;

      data.sleep.rings = 0;
      data.sleep.loops = 1;
      data.sleep.save = NULL;

      cmd.port = id;
      cmd.mode = TGI_EXEC_NORMAL;
      ::write(tgipipe[1], &cmd, sizeof(cmd));
      trunkStep(TRUNK_STEP_SLEEP);
      return false;
}

bool Trunk::scrLibexec(void)
{
      tgicmd_t cmd;
      int argc = 0;
      char *user = NULL;
      char *gain = getKeyword("gain");
      char *speed = getKeyword("speed");
      char *pitch = getKeyword("pitch");
      Line *line = getScript();
      Name *scr = getObject();
      char query[sizeof(cmd.cmd) - 160];
      char urlbuf[sizeof(cmd.cmd) - 160];
#ifdef      HAVE_SSTREAM
      ostringstream str;
      str.str() = "";
#else
      strstream str(cmd.cmd, sizeof(cmd.cmd));
#endif
      unsigned qlen = 0;
      char *qc, *tag, *opt;
      const char *member = getMember();
      char namebuf[64];

      if(!member)
            member="tgi";

      if(!strnicmp(member, "one", 3))
      {
            if(!getOnce())
            {
                  advance();
                  return true;
            }
      }

      if(!stricmp(member, "play"))
            data.sleep.wakeup =  getSecTimeout(getValue(getSymbol(SYM_PLAYWAIT)));
      else
            data.sleep.wakeup = getTimeout("maxTime");
      data.sleep.rings = 0;
      data.sleep.loops = 1;
      data.sleep.save = NULL;

      cmd.port = id;
      cmd.mode = TGI_EXEC_NORMAL;
      cmd.cmd[0] = 0;
      query[0] = 0;

      opt = getValue("--");
      if(!strnicmp(opt, "~/", 2))
      {
            snprintf(namebuf, sizeof(namebuf), "%s", scr->name);
            qc = strchr(namebuf, ':');
            if(qc)
                  *qc = 0;
            if(namebuf[0] == '~')
                  user = namebuf + 1;
            else if(namebuf[0] == '#')
            {
                  user = getSymbol(SYM_HOME);
                  if(!*user)
                        user = NULL;
            }
            opt += 2;
      }

      str << opt;
      while(NULL != (qc = getOption(NULL)) && qlen < sizeof(query))
      {
            if(*qc != '%')
                  continue;

            if(!strnicmp(qc, "%lib.", 5))
                  tag = qc + 5;
            else
                  tag = qc + 1;

            if(qlen)
                  query[qlen++] = *keyserver.getToken();

            qc = getSymbol(qc);
            if(!qc)
                  continue;

            urlbuf[0] = 0;
            urlEncode(qc, urlbuf, sizeof(urlbuf));
            snprintf(query + qlen, sizeof(query) - qlen, "%s=%s", tag, urlbuf);
            qlen = strlen(query);
      }

      while(argc < line->argc && qlen < sizeof(query))
      {
            opt = line->args[argc++];
            if(*opt != '=')
                  continue;

            tag = opt + 1;
            opt = line->args[argc++];

            if(qlen)
                  query[qlen++] = *keyserver.getToken();

            qc = getContent(opt);
            if(!qc)
                  continue;
            urlbuf[0] = 0;
            urlEncode(qc, urlbuf, sizeof(urlbuf));
            snprintf(query + qlen, sizeof(query) - qlen, "%s=%s", tag, urlbuf);
            qlen = strlen(query);
      }

      if(user)
            str << " user=" << user;

      str << " query=" << query;

      if(dtmf.bin.data)
            str << " digits=" << dtmf.bin.data;

      qc = getSymbol(SYM_CALLER);
      if(qc)
            str << " clid=" << qc;

      qc = getSymbol("session.callednaspos");

      if(qc)
            str << " session.callednaspos=" << qc;

      qc = getSymbol("pstn.callednaspos");
      if(qc)
            str << " pstn.callednaspos=" << qc;


      qc = getSymbol(SYM_DIALED);
      if(qc)
            str << " dnid=" << qc;

      if(!data.sleep.wakeup)
            cmd.mode = TGI_EXEC_DETACH;

      if(!stricmp(member, "play"))
      {
            data.play.voice = NULL;
            data.play.timeout = data.sleep.wakeup;
            data.play.repeat = 0;
            data.play.lock = false;
            data.play.name = data.play.list;
            data.play.term = 0;
            data.play.mode = PLAY_MODE_TEMP;
            data.play.limit = data.play.offset = 0;
            data.play.volume = atoi(getSymbol(SYM_VOLUME));
            data.play.extension = NULL;

            if(gain)
                  data.play.gain = (float)strtod(gain, NULL);
            else
                  data.play.gain = 0.0;

            if(!speed)
                  speed = "normal";

            if(!stricmp(speed, "fast"))
                  data.play.speed = SPEED_FAST;
            else if(!stricmp(speed, "slow"))
                  data.play.speed = SPEED_SLOW;
            else
                  data.play.speed = SPEED_NORMAL;

            if(pitch)
                  data.play.pitch = (float)strtod(pitch, NULL);
            else
                  data.play.pitch = 0.0;

            sprintf(data.play.list, "temp/.tmp.%d.%s",
                  id, getSymbol(SYM_EXTENSION));
            str << " audio=" << data.play.name;
      }

#ifdef      HAVE_SSTREAM
      snprintf(cmd.cmd, sizeof(cmd.cmd), "%s", str.str().c_str());
#else
      str << ends;
#endif
      ::write(tgipipe[1], &cmd, sizeof(cmd));

      if(!stricmp(member, "play"))
      {
            trunkStep(TRUNK_STEP_PLAYWAIT);
            return false;
      }

      if(!data.sleep.wakeup)
      {
            advance();
            return true;
      }

      trunkStep(TRUNK_STEP_SLEEP);
      return false;
}

#endif

bool Trunk::scrTone(void)
{
      const char *cp;

        data.tone.recall = false;
        data.tone.dialing = NULL;
        data.tone.tone = NULL;
        data.tone.freq1 = data.tone.freq2 = 0;
        data.tone.ampl1 = data.tone.ampl2 = 0;

      cp = getValue(NULL);
      if(cp)
      {
            data.tone.tone = getphTone(cp);
            if(!data.tone.tone)
            {
                  error("no-tone");
                  return true;
            }
      }
      else
      {
            cp = getKeyword("frequency");
            if(cp)
            {
                  data.tone.freq1 = atoi(cp);
                  cp = getKeyword("amplitude");
                  if(cp)
                        data.tone.ampl1 = atoi(cp);
            }
            else
            {
                  cp = getKeyword("freq1");
                  if(cp)
                        data.tone.freq1 = atoi(cp);

                  cp = getKeyword("ampl1");
                  if(cp)
                        data.tone.ampl1 = atoi(cp);

                  cp = getKeyword("freq2");
                  if(cp)
                        data.tone.freq2 = atoi(cp);

                  cp = getKeyword("ampl2");
                  if(cp)
                        data.tone.ampl2 = atoi(cp);
            }
      }

      cp = getKeyword("timeout");
      if(!cp)
            cp = getValue(NULL);
      if(cp)
            data.tone.wakeup = data.tone.duration = getSecTimeout(cp);
      else
      {
            data.tone.wakeup = data.tone.tone->getPlaytime();
            data.tone.duration = data.tone.tone->getDuration();
      }

      cp = getKeyword("length");
      if(cp)
            data.tone.duration = getMSTimeout(cp);

      if(data.tone.duration > data.tone.wakeup)
            data.tone.duration = data.tone.wakeup;
            
      cp = getKeyword("count");
      if(!cp)
            cp = getValue("1");
      data.tone.loops = atoi(cp);
      trunkStep(TRUNK_STEP_TONE);
      return false;
}

bool Trunk::scrSleep(void)
{
      timeout_t timer = getTimeout("maxTime");

      if(!timer)
      {
            advance();
            return true;
      }

      data.sleep.wakeup = timer;
      data.sleep.loops = 1;
      data.sleep.rings = 0;
      data.sleep.save = NULL;
      trunkStep(TRUNK_STEP_SLEEP);
      return false;
}

#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index