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 Dialogic runtime libraries to produce a executable image
// without requiring Dialogic's sources to be supplied so long as each
// each source file so linked contains this exclusion.
//
// 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".

extern "C" {
#include <sys/poll.h>
};

#include "driver.h"
#include "possibilite.h"
#include "reroute.h"

#define     EVENT_BUFFER_SIZE 16

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

char DialogicTrunk::status[600];

DialogicTrunk::DialogicTrunk(int id, devices_t *devif) :
TimerPort(), Trunk(id, 0, devif->span), Thread(0), URLAudio(), AudioService()
{
      TrunkEvent event;
      unsigned long opts;
      short wparm;
      char bparm;
      const char *cp;

      trunk = (Trunk *)this;
      handler = NULL;
      lastring = 0;
      chdev = devif->chdev;
      tsdev = devif->tsdev;
      isdev = devif->isdev;
      isdn = dialogicivr.getISDN(devif->isdev);
      join = NULL;
      faxdev = -1;
      crn = -1;

      if(tsdev > -1)
            interface = devif->iface;
      else
            interface = NT_ANALOG;

      intts.sc_numts = voxts.sc_numts = faxts.sc_numts = 1;
      voxts.sc_tsarrayp = &tsinfo[0];
      intts.sc_tsarrayp = &tsinfo[1];
      faxts.sc_tsarrayp = &tsinfo[2];

      HOLD("trunk init")
      
            routing = true;
            if(dx_getxmitslot(chdev, &voxts))
            {
                  routing = false;
                  postError(chdev, "vox ");
            }                       
            if(faxdev > -1)
            {
                  if(fx_getxmitslot(faxdev, &faxts))
                        postError(faxdev, "fax ");
            }

            if(interface == NT_ANALOG)
            {
                  if(ag_getxmitslot(chdev, &intts) && routing)
                        postError(chdev, "lsi ");
            }
            else if(!isdn)
            {
                  if(dt_getxmitslot(tsdev, &intts) && routing)
                        postError(tsdev, "dti ");
                  if(ATDT_BDMODE(tsdev) == -1)
                        interface = NT_ISDN;
            }

            tsConnect();

            setRing(group->getAnswer());

                if (interface == NT_ANALOG)
                {
                        /* Place the channel on hook */
                        if(dx_sethook(chdev,DL_ONHOOK,EV_SYNC) == -1)
                                postError(chdev,"hook ");
                }
                else
            {
                  if(dt_setidle(tsdev, DTIS_DISABLE))
                        postError(tsdev, "dti ");
                  dt_setsigmod(tsdev, DTM_SIGINS);
                  if(interface == NT_E1)
                  {
                        // if(dt_settssigsim(tsdev, DTB_DON | DTB_COFF | DTB_AON))
                        //    postError(tsdev, "dti settssigsim");
                  }
                  dt_setevtmsk(tsdev, DTG_SIGEVT, DTMM_AOFF | DTMM_AON,  DTA_SETMSK);
            }
            if(isdn)
            {
                  if(cc_SetEvtMsk(tsdev, CCMSK_ALERT | CCMSK_PROCEEDING | CCMSK_PROGRESS | CCMSK_SETUP_ACK, CCACT_ADDMSK) < 0)
                        putISDNError("cc_SetEvtMsk");
                  /* Set the channel parameters to be able to receive IE buffers */
                  if(cc_SetParm(tsdev, RECEIVE_INFO_BUF, 100) < 0)
                        putISDNError("cc_SetParm");
            }
      RELEASE

      pipe(evbuf);
      opts = fcntl(evbuf[1], F_GETFL);
      fcntl(evbuf[1], F_SETFL, opts | O_NONBLOCK);
      digtpt[0].tp_type = IO_CONT;
      digtpt[0].tp_termno = DX_MAXDTMF;
      digtpt[0].tp_length = 1;
      digtpt[0].tp_flags = TF_MAXDTMF;
      digtpt[1].tp_type = IO_CONT;
      digtpt[1].tp_termno = DX_DIGMASK;
      digtpt[1].tp_flags = TF_DIGMASK;
      digtpt[2].tp_type = IO_CONT;
        digtpt[2].tp_termno = DX_MAXSIL;
        digtpt[2].tp_length = 0;
        digtpt[2].tp_flags = TF_10MS;
        digtpt[3].tp_type = IO_CONT;
        digtpt[3].tp_termno = DX_LCOFF;
        digtpt[3].tp_length = 3;
        digtpt[3].tp_flags = TF_LCOFF | TF_10MS;
        digtpt[4].tp_type = IO_EOT;
        digtpt[4].tp_termno = DX_MAXTIME;
        digtpt[4].tp_flags = TF_MAXTIME | TF_10MS;

      iofile.io_type = IO_DEV | IO_UIO | IO_EOT;
      iofile.io_bufp = 0;
      iofile.io_offset = 0;
      iofile.io_length = -1;
      iofile.io_fhandle = id;
      iofile.io_nextp = NULL;

      iotone.io_type = IO_MEM | IO_EOT;
      iotone.io_offset = 0;
      iotone.io_fhandle = 0;
      iotone.io_nextp = NULL;

      if(isdn)
            handler = &DialogicTrunk::idleHandler;
      else
            handler = &DialogicTrunk::hangupHandler;
      event.id = TRUNK_ENTER_STATE;

      HOLD("trunk parms")
            cp = group->getLast("talkoff");
            if(!cp)
                  cp = dialogicivr.getTalkback();
            if(cp)
            {
                  wparm = atoi(cp);
                  if(dx_setparm(chdev, DXCH_DTMFTLK, (void *)&wparm))
                        postError(chdev, "set ");
            }
            cp = group->getLast("debounce");
            if(!cp)
                  cp = dialogicivr.getDebounce();
            if(cp)
            {
                  wparm = atoi(cp);
                  if(dx_setparm(chdev, DXCH_DTMFDEB, (void *)&wparm))
                        postError(chdev, "set ");
            }

            cp = group->getLast("winktimer");
            if(cp)
            {
                  bparm = atoi(cp) / 10;
                  if(dx_setparm(chdev, DXCH_WINKLEN, (void *)&bparm))
                        postError(chdev, "set ");
            }

            cp = group->getLast("winkdelay");
            if(cp)
            {
                  bparm = atoi(cp) / 10;
                  if(dx_setparm(chdev, DXCH_WINKDLY, (void *)&bparm))
                        postError(chdev, "set ");
            }

            cp = group->getLast("minwink");
            if(cp)
            {
                  bparm = atoi(cp) / 10;
                  if(dx_setparm(chdev, DXCH_MINRWINK, (void *)&bparm))
                        postError(chdev, "set ");
            }           

            cp = group->getLast("maxwink");
            if(cp)
            {
                  bparm = atoi(cp) / 10;
                  if(dx_setparm(chdev, DXCH_MAXRWINK, (void *)&bparm))
                        postError(chdev, "set ");
            }
                              
      RELEASE

//    (this->*handler)(&event);
}

DialogicTrunk::~DialogicTrunk()
{
      terminate();
      HOLD("terminate")
      stopChannel(EV_SYNC);
      tsRelease();      

      if(interface == NT_E1 && !isdn)
      {
            if(dt_settssigsim(tsdev, DTB_BON))
                  postError(tsdev, "dti ");
      }

      if(interface != NT_ANALOG)
            dt_setidle(tsdev, DTIS_ENABLE);
      else
            setHook(false);

      if(tsdev > -1)
      {
            if(isdn)
                  cc_Close(tsdev);
            else
                  dt_close(tsdev);
      }

      dx_close(chdev);
      RELEASE
      ::close(evbuf[0]);
      ::close(evbuf[1]);
}

bool DialogicTrunk::Join(DialogicTrunk *trunk)
{
      int d1, d2, m1, m2, rtn;
      unsigned flags = MD_PCM | PM_SR8;
      SC_TSINFO tsinfo1, tsinfo2, rtsinfo;
      long scts1, scts2, arrayp[32];

      if(interface == NT_ANALOG)
      {
            if(!routing)
                  return false;

            d1 = chdev;
            m1 = SC_LSI;
      }
      else
      {
            d1 = tsdev;
            m1 = SC_DTI;
      }
      if(trunk->interface == NT_ANALOG)
      {
            if(!trunk->routing)
                  return false;
            d2 = trunk->chdev;
            m2 = SC_LSI;
      }
      else
      {
            d2 = trunk->tsdev;
            m2 = SC_DTI;
      }
      HOLD("join")
      if(trunk->join)
      {
            RELEASE
            return false;
      }
      trunk->enterMutex();
        nr_scroute(d1, m1, d2, m2, SC_FULLDUP);
        join = trunk;
        join->join = this;
      trunk->leaveMutex();
      RELEASE
      if(trunk->data.join.recfn)
      {
            switch(getEncoding())
            {
            case mulawAudio:
                  flags = MD_PCM | PM_SR8;
                  break;
            case alawAudio:
                  flags = MD_PCM | PM_ALAW | PM_SR8;
                  break;
            case voxADPCM:
                  flags = MD_ADPCM | PM_SR6;
            }
            tsinfo1.sc_numts = 1;
            tsinfo1.sc_tsarrayp = &scts1;
            switch(m1)
            {
            case SC_LSI:
                  dx_getxmitslot(d1, &tsinfo1);
                  break;
            case SC_DTI:
                  dt_getxmitslot(d1, &tsinfo1);
                  break;
            }
            tsinfo2.sc_numts = 1;
            tsinfo2.sc_tsarrayp = &scts2;
            switch(m2)
            {
            case SC_LSI:
                  dx_getxmitslot(d2, &tsinfo2);
                  break;
            case SC_DTI:
                  dt_getxmitslot(d2, &tsinfo2);
                  break;
            }
            arrayp[0] = scts1;
            arrayp[1] = scts2;
            rtsinfo.sc_numts = 2;
            rtsinfo.sc_tsarrayp = &arrayp[0];   
            HOLD("joinrec")
                  rtn = dx_recm(chdev, &trunk->iofile, dialogicivr.getTPT(),
                        EV_ASYNC | flags, &rtsinfo);
            RELEASE
            if(rtn < 0)
                  postError(chdev, "vox");
      }
      return true;
}

bool DialogicTrunk::Listen(DialogicTrunk *trunk)
{
      int d1, d2, m1, m2, v2;

      if(interface == NT_ANALOG)
      {
            if(!routing)
                  return false;

            d1 = chdev;
            m1 = SC_LSI;
      }
      else
      {
            d1 = tsdev;
            m1 = SC_DTI;
      }
      if(trunk->interface == NT_ANALOG)
      {
            if(!trunk->routing)
                  return false;
            v2 = d2 = trunk->chdev;
            m2 = SC_LSI;
      }
      else
      {
            d2 = trunk->tsdev;
            v2 = trunk->chdev;
            m2 = SC_DTI;
      }

      HOLD("join")

      switch(data.join.direction)
      {
            case JOIN_RECV:
                  nr_scroute(d2, m2, d1, m1, SC_HALFDUP);
                  break;
            case JOIN_XMIT:
                  nr_scroute(v2, SC_VOX, d1, m1, SC_HALFDUP);
                  break;
      }

      join = trunk;
      join->join = NULL;
      RELEASE
      return true;
}

void DialogicTrunk::Part(void)
{
      TrunkEvent event;
      int d1, d2, m1, m2, v2;

      if(!join)
            return;

      HOLD("part")
      if(interface == NT_ANALOG)
      {
            m1 = SC_LSI;
            d1 = chdev;
      }
      else
      {
            m1 = SC_DTI;
            d1 = tsdev;
      }

      if(join->interface == NT_ANALOG)
      {
            v2 = d2 = join->chdev;
            m2 = SC_LSI;
      }
      else
      {
            d2 = join->tsdev;
            v2 = join->chdev;
            m2 = SC_DTI;
      }

      if(NULL == join->join)
      {
            switch(data.join.direction)
            {
                  case JOIN_RECV:
                        nr_scunroute(d2, m2, d1, m1, SC_HALFDUP);
                        tsConnect();
                        break;
                  case JOIN_XMIT:
                        nr_scunroute(v2, SC_VOX, d1, m1, SC_HALFDUP);
                        tsConnect();
                        break;
            }
      }
      else
      {
            join->enterMutex();
            nr_scunroute(d1, m1, d2, m2, SC_FULLDUP);
            tsConnect();
            join->tsConnect();
            join->join = NULL;
            join->leaveMutex();
            event.id = TRUNK_PART_TRUNKS;
            event.parm.ok = false;
            join->postEvent(&event);
      }
      join = NULL;
      RELEASE
}     

void DialogicTrunk::tsRelease(void)
{
      if(interface == NT_ANALOG)
      {
            if(routing)
                  nr_scunroute(chdev, SC_LSI, chdev, SC_VOX, SC_FULLDUP);
      }
      else
            nr_scunroute(tsdev, SC_DTI, chdev, SC_VOX, SC_FULLDUP);
}

void DialogicTrunk::tsConnect(void)
{
      if(interface == NT_ANALOG)
      {
            if(routing)
            {
                  nr_scunroute(chdev, SC_LSI, chdev, SC_VOX, SC_FULLDUP);
                  nr_scroute(chdev, SC_LSI, chdev, SC_VOX, SC_FULLDUP);
            }
      }
      else
      {
            nr_scunroute(tsdev, SC_DTI, chdev, SC_VOX, SC_FULLDUP);
            nr_scroute(tsdev, SC_DTI, chdev, SC_VOX, SC_FULLDUP);
      }
}

void DialogicTrunk::run(void)
{
      char buf[EVENT_BUFFER_SIZE];
      TrunkEvent *event = (TrunkEvent *)&buf;
      int timeout;
      struct pollfd pfd;

      Thread::sleep(4000 + 20 * id);
      event->id = TRUNK_ENTER_STATE;
      (this->*handler)(event);
      setCancel(cancelImmediate);

      for(;;)
      {
            enterMutex();
            timeout = TimerPort::getTimer();
            if(!timeout)
            {
                  event->id = TRUNK_TIMER_EXPIRED;
                  TimerPort::endTimer();
                  postEvent(event);
                  leaveMutex();
                  continue;
            }

            leaveMutex();           
            if(timeout > 0)
            {
                  pfd.fd = evbuf[0];
                  pfd.events = POLLIN | POLLRDNORM;
                  if(::poll(&pfd, 1, timeout) < 1)
                  {
                        event->id = TRUNK_TIMER_EXPIRED;
                        postEvent(event);
                        continue;
                  }
            }
            
            if(::read(evbuf[0], &buf, sizeof(buf)) != sizeof(buf))
            {
                  slog(Slog::levelError) << "dx(" << id << "): event failure in read" << endl;
                  continue;
            }
            if(event->id != TRUNK_NULL_EVENT)
                  postEvent(event);
      }
}

void DialogicTrunk::putEvent(TrunkEvent *evt)
{
      char buf[EVENT_BUFFER_SIZE];
      TrunkEvent null;

      if(!evt && isThread())
            return;

      if(!evt)
      {
            null.id = TRUNK_NULL_EVENT;
            evt = &null;
      }     
      memcpy(buf, evt, sizeof(TrunkEvent));
      if(::write(evbuf[1], &buf, sizeof(buf)) != sizeof(buf))
            slog(Slog::levelError) << "dx(" << id << "): event overflow" << endl;
}

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

      enterMutex();
      switch(event->id)
      {
      case TRUNK_TIMER_SYNC:
            if(!synctimer)
                  rtn = false;
            synctimer = 0;
            break;
      case TRUNK_TIMER_EXIT:
            if(!exittimer)
                  rtn = false;
            exittimer = 0;
            break;
      case TRUNK_TIMER_EXPIRED:
            if(TimerPort::getTimer() < 0)
                  rtn = false;
            TimerPort::endTimer();
            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) << "dx( " << id << ")";
            slog() << ":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 == &DialogicTrunk::idleHandler)
                        setIdle(false);
                  event->id = TRUNK_ENTER_STATE;
                  goto retry;
            }
            putEvent(NULL);
            leaveMutex();
            return true;
      }

      rtn = true;
      switch(event->id)
      {
      case TRUNK_MAKE_IDLE:
            handler = &DialogicTrunk::idleHandler;
            break;
      case TRUNK_MAKE_BUSY:
      case TRUNK_MAKE_STANDBY:
            handler = &DialogicTrunk::busyHandler;
            break;
      case TRUNK_STOP_STATE:
            TimerPort::endTimer();
            handler = &DialogicTrunk::stepHandler;
            break;
      case TRUNK_EXIT_STATE:
            break;
      case TRUNK_EXIT_SHELL:
            tgi.pid = 0;
            break;
      case TRUNK_RINGING_ON:
            ++rings;
            break;
      case TRUNK_ENTER_STATE:
            if(Trunk::flags.offhook)
                  Trunk::setDTMFDetect();
            else
                  setDTMFDetect(false);
            TimerPort::endTimer();
            break;
      case TRUNK_LINE_WINK:
            if(!Trunk::flags.offhook)
                  break;
      case TRUNK_CPA_DIALTONE:
      case TRUNK_STOP_DISCONNECT:
            if(Trunk::flags.onexit)
                  break;
            if(trunkSignal(TRUNK_SIGNAL_HANGUP))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_SEND_MESSAGE:
            if(recvEvent(event))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_TIMER_EXPIRED:
            trunkSignal(TRUNK_SIGNAL_TIMEOUT);
            event->id = TRUNK_STOP_STATE;
            goto retry;
            break;
      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_CHILD_EXIT:
            if(!ScriptInterp::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;
      default:
            rtn = false;
      }
      if(handler != prior)
      {
            event->id = TRUNK_ENTER_STATE;
            goto retry;
      }
      leaveMutex();     
      putEvent(NULL);
      return rtn;
}

void DialogicTrunk::postError(int dev, const char *msg)
{
      char buffer[33];
      getName(buffer);
      slog(Slog::levelError) << buffer << ": " << msg << ATDV_ERRMSGP(dev) << endl;
}

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

      char buffer[33];
      getName(buffer);
      slog(Slog::levelDebug) << buffer << ": script exiting" << endl;
      handler = &DialogicTrunk::hangupHandler;
}

void DialogicTrunk::getName(char *buffer)
{
      sprintf(buffer, "dx(%0d)", id);
}

unsigned long DialogicTrunk::getIdleTime(void)
{
      time_t now;
      time(&now);
//    if(handler == &DialogicTrunk::idleHandler)
//          return now - idletime;

      return 0;
}

void DialogicTrunk::getDigits(timeout_t timeout)
{
      HOLD("dx_getdig")
            DV_TPT *tpt = getPending(timeout);
            dx_getdig(chdev, tpt, digbuf, EV_ASYNC);
      RELEASE
}

DV_TPT *DialogicTrunk::getPending(timeout_t timeout)
{
      unsigned long mask = getMask();

      if(timeout)
            TimerPort::setTimer(timeout);

      stopChannel(EV_ASYNC);

      if(timeout)
      {
            digtpt[3].tp_type = IO_CONT;
            digtpt[4].tp_length = TimerPort::getTimer() / 10;
      }
      else
            digtpt[3].tp_type = IO_EOT;

      digtpt[2].tp_length = 0;

      if(Trunk::flags.dtmf && (mask & 0x00000ff0))
      {
            digtpt[1].tp_length = 0;
            if(mask & 0x0010)
                  digtpt[1].tp_length |= DM_0;
            if(mask & 0x0020)
                  digtpt[1].tp_length |= DM_1;
            if(mask & 0x0040)
                  digtpt[1].tp_length |= DM_2;
            if(mask & 0x0080)
                  digtpt[1].tp_length |= DM_3;
            if(mask & 0x0100)
                  digtpt[1].tp_length |= DM_4;
            if(mask & 0x0200)
                  digtpt[1].tp_length |= DM_5;
            if(mask & 0x0400)
                  digtpt[1].tp_length |= DM_6;
            if(mask & 0x0800)
                  digtpt[1].tp_length |= DM_7;
            if(mask & 0x1000)
                  digtpt[1].tp_length |= DM_8;
            if(mask & 0x2000)
                  digtpt[1].tp_length |= DM_9;
            if(mask & 0x4000)
                  digtpt[1].tp_length |= DM_S;
            if(mask & 0x8000)
                  digtpt[1].tp_length |= DM_P;
            if(mask & 0x10000)
                  digtpt[1].tp_length |= DM_A;
            if(mask & 0x20000)
                  digtpt[1].tp_length |= DM_B;
            if(mask & 0x40000)
                  digtpt[1].tp_length |= DM_C;
            if(mask & 0x80000)
                  digtpt[1].tp_length |= DM_D;

            return &digtpt[0];
      }
      else
            return &digtpt[2];
}

void DialogicTrunk::setDTMFDetect(bool flag)
{
      Trunk::flags.dtmf = flag;

      HOLD("set dtmf detect")
            if(flag)
                  dx_setevtmsk(chdev, DM_LCOFF|DM_LCON|DM_DIGITS);
            else
            {
                  dx_setevtmsk(chdev, DM_LCOFF|DM_LCON|DM_DIGOFF);
            //    dx_clrdigbuf(chdev);
            }
      RELEASE
}

bool DialogicTrunk::acceptISDN(void)
{
      int rtn;
      LINEDEV ld;

      if(Trunk::flags.offhook)
            return false;

      if(!isdn)
            return false;

      HOLD("accept")
      if(cc_CRN2LineDev(crn, &ld) < 0 || crn == -1)
      {
            RELEASE
            slog(Slog::levelDebug) << "dx(" << id << "): Invalid CRN passed to acceptISDN, crn=" << crn << endl;
            return false;
      }

      rtn = cc_AcceptCall(crn, 0, EV_ASYNC);
      RELEASE

      if(rtn < 0)
            putISDNError("cc_AcceptCall");

      return true;
}

bool DialogicTrunk::rejectISDN(void)
{
      int rtn;
      LINEDEV ld;

      if(Trunk::flags.offhook || !isdn)
            return false;

      if(cc_CRN2LineDev(crn, &ld) < 0 || crn == -1)
      {
            slog(Slog::levelDebug) << "dx(" << id << "): Invalid CRN passed to rejectISDN, crn=" << crn << endl;
            return false;
      }

      _disconnecting = true;

      HOLD("reject")
            rtn = cc_DropCall(crn, NORMAL_CLEARING, EV_ASYNC);
      RELEASE

      if(rtn < 0)
            putISDNError("cc_DropCall");

      return true;
}

bool DialogicTrunk::answerISDN(void)
{
      int rtn;
      LINEDEV ld;

      if(Trunk::flags.offhook)
            return false;

      if(!isdn)
      {
            setHook(true);
            return true;
      }

      if(cc_CRN2LineDev(crn, &ld) < 0 || crn == -1)
      {
            slog(Slog::levelDebug) << "dx(" << id << "): Invalid CRN passed to answerISDN, crn=" << crn << endl;
            return false;
      }

      HOLD("answer")
            rtn = cc_AnswerCall(crn, 0, EV_ASYNC);
      RELEASE

      if(rtn < 0)
            putISDNError("cc_AnswerCall");

      Trunk::flags.offhook = true;
      return true;
}

bool DialogicTrunk::hangupISDN(void)
{
      int rtn;
      LINEDEV ld;

      if(!Trunk::flags.offhook)
            return false;

      if(!isdn)
      {
            setHook(false);
            return true;
      }

      stopChannel(EV_ASYNC);

      if(cc_CRN2LineDev(crn, &ld) < 0 || crn == -1)
      {
            slog(Slog::levelDebug) << "dx(" << id << "): Invalid CRN, hangupISDN =" << crn << endl;
            return false;
      }

      _disconnecting = true;

      HOLD("dropcall")
            rtn = cc_DropCall(crn, NORMAL_CLEARING, EV_ASYNC);
      RELEASE
      if(rtn < 0)
            putISDNError("cc_DropCall");

      Trunk::flags.offhook = false;
      return true;
}

void DialogicTrunk::releaseISDN(void)
{
      int rtn;

      HOLD("release")
            rtn = cc_ReleaseCall(crn);
      RELEASE

      _disconnecting = false;
      
      if(rtn < 0)
            putISDNError("cc_ReleaseCall");

      crn = -1;
}

// bool DialogicTrunk::busyISDN(int chanstate)
// {
//    if(Trunk::flags.offhook || !isdn)
//          return false;
//
//    HOLD("busy")
//          cc_SetChanState(tsdev, chanstate, EV_ASYNC);
//    RELEASE
//
//    return true;
// }

void DialogicTrunk::setHook(bool hook)
{
      if(hook == Trunk::flags.offhook)
            return;

      if(isdn)
      {
            if(hook)
                  answerISDN();
            else
                  hangupISDN();
            return;
      }

      HOLD("set hook state")
            if(hook)
                  dx_sethook(chdev, DX_OFFHOOK, EV_ASYNC);
            else
                  dx_sethook(chdev, DX_ONHOOK, EV_ASYNC);
      RELEASE
      Trunk::flags.offhook = hook;
}

void DialogicTrunk::setRing(int rings)
{
      short parm;

      HOLD("set rings")
            if(rings > 0 && interface == NT_ANALOG)
                  dx_setevtmsk(chdev, DM_RINGS | DM_DIGOFF);
            else
                  dx_setevtmsk(chdev, DM_DIGOFF);
            if(interface == NT_ANALOG)
            {
                  if(rings > 1)
                        parm = DX_CALLIDENABLE;
                  else
                        parm = DX_CALLIDDISABLE;
                  dx_setparm(chdev, DXCH_CALLID, (void *)&parm);
            }
            parm = rings;
            if(!isdn)
                  dx_setparm(chdev, DXCH_RINGCNT, (void *)&parm);
            dx_clrdigbuf(chdev);
      RELEASE
}

bool DialogicTrunk::dialISDN(char digit[16], int timeout)
{
      MAKECALL_BLK makecall_blk;
      int rtn;
      const char *cp;

      makecall_blk.isdn.BC_xfer_cap=BEAR_CAP_SPEECH;
      makecall_blk.isdn.BC_xfer_mode=ISDN_ITM_CIRCUIT;
      makecall_blk.isdn.BC_xfer_rate=BEAR_RATE_64KBPS;

      // try trunk group first for override by group

      cp = group->getLast("isdnfacility");
      if(!cp)
            cp = dialogicivr.getLast("isdnfacility");
      if(!cp)
            cp = "cpn";

      if(!stricmp(cp, "none"))
            makecall_blk.isdn.facility_coding_value = ISDN_NOTUSED;
      else if(!stricmp(cp, "cpn"))
            makecall_blk.isdn.facility_coding_value = ISDN_CPN;
      else if(!stricmp(cp, "bn"))
            makecall_blk.isdn.facility_coding_value = ISDN_BN;
      else
            makecall_blk.isdn.facility_coding_value = ISDN_CPN;

      makecall_blk.isdn.destination_number_type = EN_BLOC_NUMBER;

      cp = group->getLast("isdnnumbering");
      if(!cp)
            cp = dialogicivr.getLast("isdnnumbering");
      if(!cp)
            cp = "isdn";

      if(!stricmp(cp, "none") || !stricmp(cp, "unknown"))
            makecall_blk.isdn.destination_number_plan = UNKNOWN_NUMB_PLAN;
      else if(!stricmp(cp, "e.164") || !stricmp(cp, "telephony"))
            makecall_blk.isdn.destination_number_plan = TELEPHONY_NUMB_PLAN;
      else if(!strnicmp(cp, "priv", 4))
            makecall_blk.isdn.destination_number_plan = PRIVATE_NUMB_PLAN;
      else
            makecall_blk.isdn.destination_number_plan = ISDN_NUMB_PLAN;

      if(data.dialxfer.callingdigit)
      {
            makecall_blk.isdn.origination_number_type = EN_BLOC_NUMBER;
            makecall_blk.isdn.origination_number_plan = ISDN_NUMB_PLAN;       
            sprintf(makecall_blk.isdn.origination_phone_number,
                  data.dialxfer.callingdigit);
      }
      else
      {
            makecall_blk.isdn.origination_number_type = ISDN_NOTUSED;
            makecall_blk.isdn.origination_number_plan = ISDN_NOTUSED;
            makecall_blk.isdn.origination_sub_number_type = ISDN_NOTUSED;
            makecall_blk.isdn.origination_phone_number[0] = '\0';
      }
      makecall_blk.isdn.facility_feature_service = ISDN_SERVICE;

      cp = group->getLast("isdnencoding");
      if(!cp)
            cp = dialogicivr.getLast("isdnencoding");
      if(!cp)
            cp = "alaw";

      if(!stricmp(cp, "ulaw") || !stricmp(cp, "mulaw"))
            makecall_blk.isdn.usrinfo_layer1_protocol = ISDN_UIL1_G711ULAW;
      else if(!stricmp(cp, "adpcm"))
            makecall_blk.isdn.usrinfo_layer1_protocol = ISDN_UIL1_G721ADCPM;
      else
            makecall_blk.isdn.usrinfo_layer1_protocol = ISDN_UIL1_G711ALAW;
      makecall_blk.isdn.usr_rate = ISDN_NOTUSED;
      makecall_blk.isdn.usrinfo_bufp = NULL;
      makecall_blk.isdn.nsfc_bufp = NULL;
      makecall_blk.isdn.destination_sub_number_type = NAT_NUMBER;
      makecall_blk.isdn.destination_sub_phone_number[0] = '\0';

      HOLD("dial")
            rtn = cc_MakeCall(tsdev, &crn, digit, &makecall_blk, 0, EV_ASYNC);
      RELEASE

      if(rtn < 0)
      {
            putISDNError("cc_MakeCall");
            return false;
      }

      if(timeout)
            TimerPort::setTimer(data.dialxfer.timeout + 120 *strlen(data.dialxfer.digit));

      return true;
}

void DialogicTrunk::stopChannel(int mode = EV_ASYNC)
{
      HOLD("stop channel")
            dx_stopch(chdev, mode);
      RELEASE
}

void DialogicTrunk::playTone(phTone *tone)
{
      iotone.io_bufp = (char *)tone->getSamples();
      iotone.io_length = tone->getDuration() * 8;
      HOLD("tone")
            dx_play(chdev, &iotone, dialogicivr.getTPT(),
                  EV_ASYNC | MD_PCM | PM_SR8);
      RELEASE
}

bool DialogicTrunk::playTone(unsigned f1, unsigned f2, int a1, int a2, timeout_t dur)
{
      TN_GEN tone;
      int rtn;

      dx_bldtngen(&tone, f1, f2, a1, a2, (short)(dur / 10));

      HOLD("tone")
            rtn = dx_playtone(chdev, &tone, dialogicivr.getTPT(), EV_ASYNC);
      RELEASE
      if(rtn < 0)
      {
            postError(chdev, "vox ");
            return false;
      }
      return true;
}

void DialogicTrunk::playAudio(void)
{
      unsigned flags = MD_PCM | PM_SR8;

      switch(getEncoding())
      {
      case mulawAudio:
            flags = MD_PCM | PM_SR8;
            break;
      case alawAudio:
            flags = MD_PCM | PM_ALAW | PM_SR8;
            break;
      case voxADPCM:
            flags = MD_ADPCM | PM_SR6;
            break;
      case pcm16Mono:
            flags = MD_PCM | PM_SR8;
            break;
      }
      HOLD("play")
            dx_play(chdev, &iofile, dialogicivr.getTPT(), 
                  EV_ASYNC | flags);
      RELEASE
}

void DialogicTrunk::recordAudio(void)
{
      unsigned flags = MD_PCM | PM_SR8;
      DV_TPT *rectpt = dialogicivr.getTPT();

      frames = 0;

      switch(getEncoding())
      {
      case mulawAudio:
            flags = MD_PCM | PM_SR8;
            break;
      case alawAudio:
            flags = MD_PCM | PM_ALAW | PM_SR8;
            break;
      case voxADPCM:
            flags = MD_ADPCM | PM_SR6;
      }

      if(data.record.silence)
            rectpt[1].tp_length = data.record.silence * 10;
      else
            rectpt[1].tp_length = 0;

      HOLD("rec")
            dx_rec(chdev, &iofile, rectpt,
                  EV_ASYNC | flags);
      RELEASE
}

int DialogicTrunk::getCallerId(int mode, unsigned char *cid)
{
      int rtn;
      HOLD("cid")
            rtn = dx_gtextcallid(chdev, mode, cid);
      RELEASE
      return rtn;
}

int DialogicTrunk::getISDNInfo(int mode, unsigned char *cid)
{
      int rtn;
      int mdig;

      Possibilite *ptPos;

      if(!isdn)
            return getCallerId(mode, cid);

      ptPos = (Possibilite *) cid;

      HOLD("cid")
            switch(mode)
            {
            case MCLASS_DDN:
                  rtn = cc_GetDNIS(crn, (char *)cid);
                  mdig = group->getMinDigits() - strlen((char *)cid);
                  if (mdig > 0) {
                        slog(Slog::levelDebug) << "dx(" << id << "): Getting " << mdig << " more digits" << endl;
                        if (cc_GetMoreDigits(crn, mdig, group->getMDigTimeOut(), EV_SYNC) < 0) {
                              slog(Slog::levelDebug) << "dx(" << id << "): Could not get more digits" << endl;
                        } else {
                              rtn = cc_GetDNIS(crn, (char *)cid + strlen((char *)cid));
                        }
                  }
                  break;
            case MCLASS_DN:
                  rtn = cc_GetANI(crn, (char *)cid);
                  break;
            case MCLASS_POSSIBILITE:
                  //strcpy((char *) cid, callednasposs);
                  strcpy(ptPos->appele, callednasposs);
                  strcpy(ptPos->appelant, callingnasposs);
                  strcpy(ptPos->retour, retourposs);
                  strcpy(ptPos->contexte, contextposs);
                  rtn = 0;
                  break;
            default:
                  rtn = -1;
            }
      RELEASE
      return rtn;
}

char *DialogicTrunk::getContinuation(void)
{
      char *fn;

      if(data.play.mode == PLAY_MODE_ONE || data.play.mode == PLAY_MODE_TEMP)
            return NULL;

retry:
      fn = getPlayfile();
      if(fn && data.play.mode == PLAY_MODE_ANY)
      {
            if(!canAccess(fn))
                  goto retry;
      }
      return fn; 
}

bool DialogicTrunk::scrJoin(void)
{
      Trunk *trunk = dialogicivr.getTrunkId(getValue(getKeyword("id")));
      const char *mode = getMember();
      const char *cp = getKeyword("record");
 
        if(!trunk)
        {
                Trunk::error("join-no-port");
                return true;
        }                                                                        

      if(!mode)
            mode = "duplex";

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

      if(!stricmp(mode, "receive"))
            data.join.direction = JOIN_RECV;
      else if (!stricmp(mode, "transmit"))
            data.join.direction = JOIN_XMIT;
      else if(!stricmp(mode, "hangup"))
            data.join.hangup = true;

      if(NULL != cp)
      {
            data.join.recfn = (char *)cp;
            data.join.encoding = getKeyword("encoding");
            data.join.annotation = getKeyword("annotation");
            data.join.extension = getKeyword("extension");
            if(!data.join.encoding)
                  data.join.encoding = getDefaultEncoding();
            if(!data.join.extension)
                  data.join.extension = getSymbol(SYM_EXTENSION);
      }
      else
            data.join.recfn = NULL;

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

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

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

bool DialogicTrunk::scrWait(void)
{
      struct stat ino;
      char *fn;
      char *cp;
      const char *mem = getMember();

      if(NULL != (cp = getKeyword("play")))
      {
            sprintf(data.play.list, cp);
            data.play.list[sizeof(data.play.list) - 1] = 0;
            data.play.name = data.play.list;
            data.play.volume = atoi(getSymbol(SYM_VOLUME));
            data.play.timeout = 0;
            data.play.term = 0;
            data.play.mode = PLAY_MODE_NORMAL;
            data.play.limit = data.play.offset = 0;

            if(*data.play.name)
            {
                  fn = getPlayfile();
                  stat(fn, &ino);
                  URLAudio::close();
                  open(fn);
                  if(!isOpen())
                              slog(Slog::levelError) << buffer << ": " << fn << ": cannot open" << endl;
                  else
                        playAudio();
            }
      }

      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 = dialogicivr.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;
}

 
bool DialogicTrunk::scrReroute(void)
{
      const char *option = getMember();
      char *forwarddest = NULL;
      char *backwarddest = NULL;
      char *context = NULL;
      char *backcontext = NULL;

      // Parse the arguments
      Line *line = getScript();
      for (unsigned int argc = 0 ; argc < line->argc ; argc++) {
            if (!strcmp(line->args[argc], "=forwarddest")) {

                  forwarddest = line->args[++argc];
                  if (forwarddest[0] == '%') {
                        forwarddest = getContent(forwarddest);
                  }
                  if (strlen(forwarddest) > sizeof(data.reroute.forwarddest) - 1) {
                        forwarddest[sizeof(data.reroute.forwarddest)] = 0;
                  }
                  strcpy(data.reroute.forwarddest, forwarddest);
            }
            if (!strcmp(line->args[argc], "=backwarddest")) {

                  backwarddest = line->args[++argc];
                  if (backwarddest[0] == '%') {
                        backwarddest = getContent(backwarddest);
                  }
                  if (strlen(backwarddest) > sizeof(data.reroute.backwarddest) - 1) {
                        backwarddest[sizeof(data.reroute.backwarddest)] = 0;
                  }
                  strcpy(data.reroute.backwarddest, backwarddest);
            }

            if (!strcmp(line->args[argc], "=context")) {

                  context = line->args[++argc];
                  if (context[0] == '%') {
                        context = getContent(context);
                  }
                  if (strlen(context) > sizeof(data.reroute.context) - 1) {
                        context[sizeof(data.reroute.context)] = 0;
                  }
                  strcpy(data.reroute.context, context);
            }
            if (!strcmp(line->args[argc], "=backcontext")) {

                  backcontext = line->args[++argc];
                  if (backcontext[0] == '%') {
                        backcontext = getContent(backcontext);
                  }
                  if (strlen(backcontext) > sizeof(data.reroute.backcontext) - 1) {
                        backcontext[sizeof(data.reroute.backcontext)] = 0;
                  }
                  strcpy(data.reroute.backcontext, backcontext);
            }
      }

      // Default behavior
      if (!option) {
            strcpy(data.reroute.option, "1");
      }
      else {
            if (strlen(option) > sizeof(data.reroute.option) - 1) {
                  strncpy(data.reroute.option, option, sizeof(data.reroute.option) - 1);
                  data.reroute.option[sizeof(data.reroute.option) - 1] = 0;
            }
            else {
                  strcpy(data.reroute.option, option);
            }
      }
      slog(Slog::levelDebug) << "scrReroute  option = " << data.reroute.option << endl ;
      {
            reroutage_t r;
            unsigned char trameReroutage[128];
            int len, res;
            IE_BLK    ie_blk;
            
            initReroute(&r);

            // Set forward characteristics :

            switch (atoi(data.reroute.option)) {
                  case 1:
                        setType(&r, REROUTAGE_NAS_GTX); 
                        setNumero(&r, PARAM_NUM,  (unsigned char *) data.reroute.forwarddest );
                        break;
                  case 2:
                        setType(&r, REROUTAGE_NAB_GTX); 
                        setNumero(&r, PARAM_NAB,  (unsigned char *) data.reroute.forwarddest );
                        break;
                  case 3:
                        setType(&r, REROUTAGE_ANNUAIRE); 
                        break;
                  case 4:
                        setType(&r, REROUTAGE_NTR_NAS); 
                        break;
                  case 5:
                        setType(&r, REROUTAGE_INDEFINI); 
                        break;
                  case 6:
                        setType(&r, REROUTAGE_NONTRANSPARENT); 
                        break;
                  default :
                        slog(Slog::levelError) << "Unknown forwarding type - switched to default " << endl ;
                        setType(&r, REROUTAGE_NAS_GTX); 
                        break;
            }

            setCascade(&r, 1); 

            if (context)
                  setContexte(&r, PARAM_CONTEXTE_ASCII, (unsigned char *) data.reroute.context);
            if (backcontext)
                  setRetour(&r, (unsigned char *) data.reroute.backcontext);
            if (backwarddest)
                  setNasRetour(&r, (unsigned char *) data.reroute.backwarddest);

            // Build the packet :
            len = makeTrame(&r, trameReroutage);
            ie_blk.length = len + 7;
            memcpy(ie_blk.data, trameReroutage, len + 7);
            slog(Slog::levelDebug) << "Forward to " << data.reroute.forwarddest << " (" << data.reroute.context << ")" << endl ;
            // and send it :
            res = cc_SndMsg(crn,  SndMsg_Facility , &ie_blk);
            if (res != 0)
                  slog(Slog::levelError) << "cc_SndMsg failure : " << res << endl ;
      }

        trunkStep(TRUNK_STEP_REROUTE);
      return false;
}

bool DialogicTrunk::scrConference(void)
{
      const char *option = getMember();
      char *name = NULL;
      char *size = NULL;
      unsigned int sz = 1;
      char *attr = NULL;
      int attributes = MSPA_NULL;
      unsigned int fixed = 0;
      data.conference.option = CONF_UNKNOWN;

      // Analyze the arguments
      Line *line = getScript();
      for (unsigned int argc = 0 ; argc < line->argc ; argc++) {
            if (!strcmp(line->args[argc], "=name")) {

                  // Name of the conference
                  name = line->args[++argc];
                  if (name[0] == '%') {
                        name = getContent(name);
                  }
                  if (strlen(name) > 255) {
                        name[255] = 0;
                  }
            }
            if (!strcmp(line->args[argc], "=size")) {

                  // Number of conferees
                  size = line->args[++argc];
                  if (size[0] == '%') {
                        size = getContent(size);
                  }
                  if (size != NULL) {
                        sz = (unsigned int)atoi(size);
                        if (sz == 0) sz = 1;
                  }
            }
            if (!strcmp(line->args[argc], "=attr")) {

                  // Attributes
                  attr = line->args[++argc];
                  if (attr[0] == '%') {
                        attr = getContent(attr);
                  }
                  if (attr != NULL) {
                        if (strstr(attr, "ro") != NULL) {
                              attributes |= MSPA_RO;
                        }
                        if (strstr(attr, "periodicTone") != NULL) {
                              attributes |= MSPA_TARIFF;
                        }
                        if (strstr(attr, "fixed") != NULL) {
                              fixed = 1;
                        }
                  }
            }
      }

      // Behavior
      if (!option) {
            data.conference.option = CONF_DEFAULT;
            data.conference.size = sz;
            data.conference.attributes = attributes;
            data.conference.fixed = fixed;
      }
      else
      if (!strcmp(option, "enter")) {
            data.conference.option = CONF_ENTER;
            data.conference.size = sz;
            data.conference.attributes = attributes;
            data.conference.fixed = fixed;
      }
      else
      if (!strcmp(option, "leave")) {
            data.conference.option = CONF_LEAVE;
      }
      else
      if (!strcmp(option, "establish")) {
            data.conference.option = CONF_ESTABLISH;
            data.conference.size = sz;
            data.conference.attributes = attributes;
            data.conference.fixed = fixed;
      }
      else
      if (!strcmp(option, "destroy")) {
            data.conference.option = CONF_DESTROY;
      }
      else {
            data.conference.option = CONF_UNKNOWN;
      }
      if (name ==NULL) data.conference.name[0] = 0;
      else strncpy(data.conference.name, name, 255);
        trunkStep(TRUNK_STEP_CONFERENCE);
      return false;
}

#ifdef CCXX_NAMESPACES
};
#endif


Generated by  Doxygen 1.6.0   Back to index