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

trunk.cpp

// Copyright (C) 2000 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.
//
// As a special exception to the GNU General Public License, permission is
// granted for additional uses of the text contained in its release
// of Bayonne as noted here.
//
// This exception is that permission is hereby granted to link Bayonne 
// with the Aculab telephony libraries to produce a executable image
// without requiring Aculab's sources to be supplied in a free software
// license long as each source file so linked contains this exclusion
// and the unalrtered Aculab source files are also provided.
//
// This exception does not however invalidate any other reasons why
// the resulting executable file might be covered by the GNU General
// public license or invalidate the licensing requirements of any
// other component or library.
//
// This exception applies only to the code released by OST under the
// name Bayonne.  If you copy code from other releases into a copy of
// Bayonne, as the General Public License permits, the exception does not
// apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own to Bayonne, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice, at which
// point the terms of your modification would be covered under the GPL
// as explicitly stated in "COPYING".

#include "driver.h"

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

#define     EVENT_BUFFER_SIZE 16

char AculabTrunk::status[MAXPORT * MAXTIMESLOTS];

AculabTrunk::AculabTrunk(int p, int t) :
Trunk(p * MAXTIMESLOTS + t), TimerPort(), AudioService(), URLAudio()
{
      struct in_xparms in_xparms;
      int rc;

      trunk = (Trunk *)this;
      handler = NULL;
      lastring = 0;
      exittimer = 0;
      port = p;
      ts = t;
      dspChannel=-1;
      mvip_stream=-1;
      mvip_slot=-1;
      Trunk::flags.offhook=false;
      _call_setup=false;

      memset(joinees, 0, sizeof(joinees));

      sprintf(name,"aculab(%d,%d)",port,ts);

      playaudiobufsize=kSMMaxReplayDataBufferSize;
      recordaudiobufsize=kSMMaxRecordDataBufferSize;

      slog(Slog::levelDebug)<<name<<": initializing"<<endl;

      in_xparms.net = port;
      in_xparms.ts = ts;
      in_xparms.cnf = 0;
      rc=call_openin(&in_xparms);
      if (rc) {
            slog(Slog::levelCritical) << name<<": open failed: " <<rc << endl;
            throw((Trunk *)this);
      }

      /* get network/switch type */
      nettype=call_type(port);

      handle = in_xparms.handle;
      channel = call_handle_2_chan(in_xparms.handle);

      aculabivr.setChannel(this);

      slog(Slog::levelDebug)<<name<<": initialized with channel="<<channel<<endl;

      handler=&AculabTrunk::idleHandler;
}

AculabTrunk::~AculabTrunk()
{
  /* XXX TODO XXX - close files, cleanup! */
}

void AculabTrunk::setHandle(int h)
{
      handle=h;
}

void AculabTrunk::setChannel(int c)
{
      channel=c;
}

void AculabTrunk::setTimer(timeout_t t)
{
      TimerPort::setTimer(t);
      aculabivr.timer->notify();
}

void AculabTrunk::getName(char *buffer)
{
      strcpy(buffer,name);
}

void AculabTrunk::exit(void)
{
      slog(Slog::levelDebug) << name << ": trunk exit called"<<endl;

      if(!Trunk::flags.onexit)
            if(redirect("::exit"))
            {
                  autoloop(false);
                  Trunk::flags.onexit = true;
                  return;
            }

      handler = &AculabTrunk::hangupHandler;
}

bool AculabTrunk::postEvent(TrunkEvent *event)
{
      bool rtn = true;
      trunkhandler_t prior;

      if (!tryEnterMutex()) {
            slog(Slog::levelDebug) << name<<": event will BLOCK!"<<endl;
            enterMutex();
      }

      slog(Slog::levelDebug) <<name<<": event "<< event->id << " received"<<endl;

      switch(event->id)
      {
      case TRUNK_TIMER_EXPIRED:
            if(!getTimer())
                  rtn = false;

            break;
      case TRUNK_DTMF_KEYUP:
            if(Trunk::flags.offhook)
                  time(&idletime);
            if(!Trunk::flags.dtmf)
                  rtn = false;
            break;
      }
      if(!rtn)
      {
            leaveMutex();
            return false;
      }

      if(!handler)
      {
            slog(Slog::levelWarning) <<name << ": no handler active; event=" << event->id << endl;
            leaveMutex();
            return false;
      }

retry:
      debug->debugEvent(this, event);
      prior = handler;
      rtn = (this->*handler)(event);
      if(rtn)
      {
            if(handler != prior)
            {
                  if(prior == &AculabTrunk::idleHandler)
                        setIdle(false);
                  event->id = TRUNK_ENTER_STATE;
                  goto retry;
            }
            leaveMutex();
            return true;
      }

      // default handler

      rtn = true;
      switch(event->id)
      {
      case TRUNK_RINGING_ON:
      case TRUNK_CALL_DETECT:
            ++rings;
            break;
      case TRUNK_ENTER_STATE:
            if(Trunk::flags.offhook)
                  Trunk::setDTMFDetect();
            else
                  setDTMFDetect(false);
            endTimer();
            break;
      case TRUNK_CPA_DIALTONE:
      case TRUNK_LINE_WINK:
      case TRUNK_CALL_RELEASE:
      case TRUNK_STOP_DISCONNECT:
            if(Trunk::flags.onexit)
                  break;

                if (getScript() == NULL) 
            {
                        slog(Slog::levelDebug) << name << ": disconnect AFTER SCRIPT EXIT" << endl;
                      handler = &AculabTrunk::hangupHandler;
                        break;
                }

            if(trunkSignal(TRUNK_SIGNAL_HANGUP))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_TIMER_EXPIRED:
            if(!trunkSignal(TRUNK_SIGNAL_TIMEOUT))
                  trunkSignal(TRUNK_SIGNAL_STEP);
            event->id = TRUNK_STOP_STATE;
            goto retry;
        case TRUNK_TIMER_SYNC:
                if(trunkSignal(TRUNK_SIGNAL_TIME))
                {
                        event->id = TRUNK_STOP_STATE;
                        goto retry;
                }
                break;
        case TRUNK_TIMER_EXIT:
                if(trunkSignal(TRUNK_SIGNAL_TIME))
                        event->id = TRUNK_STOP_STATE;
                else
                        event->id = TRUNK_STOP_DISCONNECT;
                goto retry;
      case TRUNK_SEND_MESSAGE:
            if(recvEvent(event))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_CHILD_EXIT:
            if(!isActive())
                  break;
            if(trunkSignal(TRUNK_SIGNAL_CHILD))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_DTMF_KEYUP:
            if(digits < MAX_DIGITS)
                  dtmf.bin.data[digits++] = digit[event->parm.dtmf.digit];
            dtmf.bin.data[digits] = 0;
            if(trunkSignal((trunksignal_t)(event->parm.dtmf.digit + TRUNK_SIGNAL_0)))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_EXIT_SHELL:
            tgi.pid = 0;
            break;
      case TRUNK_STOP_STATE:
            endTimer();
            handler = &AculabTrunk::stepHandler;
            break;
      case TRUNK_EXIT_STATE:
            break;
      case TRUNK_MAKE_BUSY:
//          handler = &AculabTrunk::busyHandler;
            break;
      case TRUNK_MAKE_IDLE:
            handler = &AculabTrunk::idleHandler;
            break;
      default:
            rtn = false;
      }
      if(handler != prior)
      {
            event->id = TRUNK_ENTER_STATE;
            goto retry;
      }
      leaveMutex();
      return rtn;
}

unsigned long AculabTrunk::getIdleTime(void)
{
      time_t now;

      time(&now);
      if(handler == &AculabTrunk::idleHandler)
            return now - idletime;

      return 0;
}

/**
 * This is used to determine if the maximum script run-time
 * has been exceeded.
 *
 * @return number of seconds remaining, zero if exceeded, -1 if disabled.
 */
long AculabTrunk::getMaxTime(void)
{
      time_t now;
      if (exittimer == 0) {
            return -1;
      }

      time(&now);
      if (now >= exittimer) {
            exittimer = 0;
            return 0;
      }
      else {
            return exittimer - now;
      }
}

bool AculabTrunk::scrJoin(void)
{
      Trunk *trunk = aculabivr.getTrunkId(getValue(getKeyword("id")));
      const char *mem = getMember();

      if(!trunk) 
      {
            Trunk::error("join-no-port");
            return true;
      }

      if(!mem)
            mem = "duplex";

      data.join.hangup = false;
      data.join.waiting = NULL;

      if(!stricmp(mem, "hangup"))
            data.join.hangup = true;

      mem = getKeyword("count");
      if(mem)
            data.join.count = atoi(mem);
      else
            data.join.count = 0;

      mem = getKeyword("waitTime");
      if(mem)
               data.join.count = getSecTimeout(mem) /
                        keythreads.getResetDelay() + 1;

      data.join.waiting = data.join.trunk = trunk;
      data.join.seq = trunk->getSequence();
      data.join.wakeup = getTimeout("maxTime");
      trunkStep(TRUNK_STEP_JOIN);
      return false;
}

bool AculabTrunk::scrWait(void)
{
      const char *mem = getMember();

      if(mem)
      {
            data.join.waiting = NULL;
            data.join.hangup = false;
            if(!stricmp(mem, "hangup"))
                  data.join.hangup = true;
            else if(!stricmp(mem, "parent"))
                  data.join.waiting = aculabivr.getTrunkId(getSymbol(SYM_PARENT));
      }
      else
      {
            data.join.waiting = NULL;
            data.join.hangup = false;
      }
      data.join.count = 0;
      data.join.trunk = NULL;
      data.join.wakeup = getTimeout("maxTime");
      trunkStep(TRUNK_STEP_JOIN);
      return false;
}

/*
 * Set the maximum run-time for a given script attached
 * to a trunk.
 */
bool AculabTrunk::scrMaxTime(void)
{
      time_t now;
      const char *mem = getMember();

      if(!mem)
            mem = "none";

      if(strnicmp(mem, "max", 3) && stricmp(mem, "exit"))
            return Trunk::scrSync();

      timeout_t dur = getTimeout("time");
      if (dur > 0) {
            time(&now);
            exittimer = starttime + (dur / 1000);
      }
      else {
            /* Disable timer */
            exittimer = 0;
      }
      aculabivr.timer->notify();

      advance();
      return true;
}

#ifdef    CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index