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

connection.cpp

/*  @file connection.cpp
    @brief Contains Connection - Encapsulates a CAPI connection with all its states and methods.

    @author Gernot Hillier <gernot@hillier.de>
    $Revision: 1.17 $
*/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "../../config.h"
#include <fstream>
#include <stdexcept> // for out_of_range
#include <pthread.h>
#include <errno.h> // for errno
#include <iconv.h> // for iconv(), iconv_open(), iconv_close()
#include "capi.h"
#include "callinterface.h"
#include "connection.h"

#define conf_send_buffers 4

using namespace std;

00031 Connection::Connection (_cmsg& message, Capi *capi, unsigned short DDILength, unsigned short DDIBaseLength, std::vector<std::string> DDIStopNumbers):
      call_if(NULL),capi(capi),plci_state(P2),ncci_state(N0), buffer_start(0), buffers_used(0),
      file_for_reception(NULL), file_to_send(NULL), received_dtmf(""), keepPhysicalConnection(false),
      disconnect_cause(0),debug(capi->debug), debug_level(capi->debug_level), error(capi->error),
      our_call(false), disconnect_cause_b3(0), fax_info(NULL), DDILength(DDILength), 
      DDIBaseLength(DDIBaseLength), DDIStopNumbers(DDIStopNumbers) 
{
      pthread_mutex_init(&send_mutex, NULL);
      pthread_mutex_init(&receive_mutex, NULL);

      plci=CONNECT_IND_PLCI(&message); // Physical Link Connection Identifier
      call_from = getNumber(CONNECT_IND_CALLINGPARTYNUMBER(&message),true);
      if (DDILength)
            call_to=""; // we enable the CalledParty InfoElement when using DDI and will get the number later again
      else
            call_to=getNumber(CONNECT_IND_CALLEDPARTYNUMBER(&message),false);

      if (debug_level >= 1) {
            debug << prefix() << "Connection object created for incoming call PLCI " << plci;
            debug << " from " << call_from << " to " << call_to << " CIP 0x" << hex << CONNECT_IND_CIPVALUE(&message) << endl;
      }
      switch (CONNECT_IND_CIPVALUE(&message)) {
            case 1:
            case 4:
            case 16:
                  service=VOICE;
            break;
            case 17:
                  service=FAXG3;
            break;
            default:
                  service=OTHER;
            break;
      }
      connect_ind_msg_nr=message.Messagenumber; // this is needed as connect_resp is given later
}

00068 Connection::Connection (Capi* capi, _cdword controller, string call_from, bool clir, string call_to, service_t service, string faxStationID, string faxHeadline)  throw (CapiExternalError, CapiMsgError)
      :call_if(NULL),capi(capi),plci_state(P01),ncci_state(N0),plci(0),service(service),  
      buffer_start(0), buffers_used(0), file_for_reception(NULL), file_to_send(NULL), 
      call_from(call_from), call_to(call_to), connect_ind_msg_nr(0), disconnect_cause(0), 
      debug(capi->debug), debug_level(capi->debug_level), error(capi->error), keepPhysicalConnection(false),
      our_call(true), disconnect_cause_b3(0), fax_info(NULL), DDILength(0), DDIBaseLength(0) 
{
      pthread_mutex_init(&send_mutex, NULL);
      pthread_mutex_init(&receive_mutex, NULL);

      if (debug_level >= 1) {
            debug << prefix() << "Connection object created for outgoing call from " << call_from << " to " << call_to
              << " service " << dec << service << endl;
      }
      if (debug_level >= 2) {
            debug << prefix() << "using faxStationID " << faxStationID << " faxHeadline " << faxHeadline << " CLIR " << clir << endl;
      }
      _cstruct B1config=NULL, B2config=NULL, B3config=NULL, calledPartyNumber=NULL, callingPartyNumber=NULL;
      _cword B1proto,B2proto,B3proto;

      try {
            _cword CIPvalue;
            switch (service) {
                  case VOICE:
                        CIPvalue=16;
                  break;
                  case FAXG3:
                        CIPvalue=17;
                  break;
                  default:
                        throw CapiExternalError("unsupported service given","Connection::Connection()");
                  break;
            }

            buildBconfiguration(controller, service, faxStationID, faxHeadline, B1proto, B2proto, B3proto, B1config, B2config, B3config);

            if (!call_to.size())
                  throw CapiExternalError("calledPartyNumber is required","Connection::Connection()");

            calledPartyNumber=new unsigned char [1+1+call_to.size()]; //struct length, number type/number plan, number
            calledPartyNumber[0]=1+call_to.size(); // length
            calledPartyNumber[1]=0x80;  // as suggested by CAPI spec (unknown number type, unknown number plan, see ETS 300 102-1)
            for (unsigned j=0;j<call_to.size();j++)
                  calledPartyNumber[j+2]=call_to[j];

            callingPartyNumber=new unsigned char [1+2+call_from.size()];
            callingPartyNumber[0]=2+call_from.size(); // length
            callingPartyNumber[1]=0x00; // as suggested by CAPI spec (unknown number type, unknown number plan, see ETS 300 102-1)
            if (clir)
                  callingPartyNumber[2]=0xA0; // suppress calling id presentation (CLIR)
            else
                  callingPartyNumber[2]=0x80; // allow calling id presentation (CLIP)
            for (unsigned j=0;j<call_from.size();j++)  // TODO: does this really work when no number is given?!
                  callingPartyNumber[j+3]=call_from[j];

            plci_state=P01;
            capi->connect_req(this,controller,CIPvalue, calledPartyNumber, callingPartyNumber,B1proto,B2proto,B3proto,B1config, B2config, B3config);
      } catch (...) {
            if (B1config)
                  delete[] B1config;
            if (B2config)
                  delete[] B2config;
            if (B3config)
                  delete[] B3config;
            if (calledPartyNumber)
                  delete[] calledPartyNumber;
            if (callingPartyNumber)
                  delete[] callingPartyNumber;
            throw;
      }
      if (B1config)
            delete[] B1config;
      if (B2config)
            delete[] B2config;
      if (B3config)
            delete[] B3config;
      if (calledPartyNumber)
            delete[] calledPartyNumber;
      if (callingPartyNumber)
            delete[] callingPartyNumber;
}

00150 Connection::~Connection()
{
      stop_file_transmission();
      stop_file_reception();

      if (getState()!=DOWN) {
            error << prefix() << "WARNING: please disconnect yourself before deleting connection object!!" << endl;
            disconnectCall(PHYSICAL_ONLY);
            while (getState()!=DOWN)
                  ;
      }
      plci_state=P0;

      pthread_mutex_lock(&send_mutex);  // assure the lock is free before destroying it
      pthread_mutex_unlock(&send_mutex);
      pthread_mutex_destroy(&send_mutex);

      pthread_mutex_lock(&receive_mutex); // assure the lock is free before destroying it
      pthread_mutex_unlock(&receive_mutex);
      pthread_mutex_destroy(&receive_mutex);

      if (fax_info)
            delete fax_info;

      if (debug_level >= 1) {
            debug << prefix() << "Connection object deleted" <<  endl;
      }
}

void
00180 Connection::registerCallInterface(CallInterface *call_if_in)
{
      call_if=call_if_in;
}

void
00186 Connection::changeProtocol(service_t desired_service, string faxStationID, string faxHeadline) throw (CapiMsgError, CapiExternalError, CapiWrongState)
{
      if (debug_level >= 2) {
            debug << prefix() << "Protocol change to " << desired_service << " requested" <<  endl;
      }

      if (ncci_state!=N0 || plci_state!=PACT)
            throw CapiWrongState("wrong state for changeProtocol","Connection::changeProtocol()");

      if (desired_service!=service) {
            _cstruct B1config=NULL, B2config=NULL, B3config=NULL;
            _cword B1proto,B2proto,B3proto;

            try {
                  buildBconfiguration(plci & 0xff, desired_service, faxStationID, faxHeadline, B1proto, B2proto, B3proto, B1config, B2config, B3config);

                  capi->select_b_protocol_req(plci,B1proto,B2proto,B3proto,B1config, B2config, B3config);
            } catch (...) {
                  if (B1config)
                        delete[] B1config;
                  if (B2config)
                        delete[] B2config;
                  if (B3config)
                        delete[] B3config;
                  throw;
            }
            if (B1config)
                  delete[] B1config;
            if (B2config)
                  delete[] B2config;
            if (B3config)
                  delete[] B3config;

            service=desired_service;
      }
}

void
00224 Connection::connectWaiting(service_t desired_service, string faxStationID, string faxHeadline) throw (CapiWrongState,CapiExternalError,CapiMsgError)
{
      if (debug_level >= 1) {
            debug << prefix() << "accepting with service " << desired_service <<  endl;
      }
      if (debug_level >= 2) {
            debug << prefix() << "using faxStationID " << faxStationID << " faxHeadline " << faxHeadline <<  endl;
      }
      if (plci_state!=P2)
            throw CapiWrongState("wrong state for connectWaiting","Connection::connectWaiting()");

      if (our_call)
            throw (CapiExternalError("can't accept an outgoing call","Connection::connectWaiting()"));

      _cstruct B1config=NULL, B2config=NULL, B3config=NULL;
      _cword B1proto,B2proto,B3proto;

      try {
            buildBconfiguration(plci & 0xff, desired_service, faxStationID, faxHeadline, B1proto, B2proto, B3proto, B1config, B2config, B3config);

            plci_state=P4;
            capi->connect_resp(connect_ind_msg_nr,plci,0,B1proto,B2proto,B3proto,B1config, B2config, B3config);
      } catch (...) {
            if (B1config)
                  delete[] B1config;
            if (B2config)
                  delete[] B2config;
            if (B3config)
                  delete[] B3config;
            throw;
      }
      if (B1config)
            delete[] B1config;
      if (B2config)
            delete[] B2config;
      if (B3config)
            delete[] B3config;
      service=desired_service;
}

void
00265 Connection::rejectWaiting(_cword reject) throw (CapiWrongState, CapiMsgError, CapiExternalError)
{
      if (debug_level >= 1) {
            debug << prefix() << "rejecting with cause " << reject <<  endl;
      }
      if (plci_state!=P2)
            throw CapiWrongState("wrong state for reject","Connection::reject()");
      if (our_call)
            throw (CapiExternalError("can't reject an outgoing call","Connection::rejectWaiting()"));
      if (!reject)
            throw CapiExternalError("reject cause must not be zero","Connection::reject()");

      plci_state=P5;
      capi->connect_resp(connect_ind_msg_nr,plci,reject,0,0,0,NULL,NULL,NULL); // can throw CapiMsgError. Propagate
}

void
00282 Connection::acceptWaiting() throw (CapiMsgError, CapiWrongState)
{
      if (plci_state!=P2)
            throw CapiWrongState("wrong state for acceptWaiting","Connection::acceptWaiting()");
      capi->alert_req(plci);
}

string
00290 Connection::getCalledPartyNumber()
{
      return call_to;
}

string
00296 Connection::getCallingPartyNumber()
{
      return call_from;
}

string
00302 Connection::prefix()
{
      stringstream s;
      time_t t=time(NULL);
      char* ct=ctime(&t);
      ct[24]='\0';
      s << ct << " Connection " << hex << this << ": ";
      return (s.str());
}

void
00313 Connection::debugMessage(string message, unsigned short level)
{
      if (debug_level >= level)
            debug << prefix() << message << endl;
}

void
00320 Connection::errorMessage(string message)
{
      error << prefix() << message << endl;
}

Connection::service_t
00326 Connection::getService()
{
      return service;
}

Connection::fax_info_t*
00332 Connection::getFaxInfo()
{
      return fax_info;
}

Connection::connection_state_t
00338 Connection::getState()
{
      if (plci_state==PACT && ncci_state==NACT)
            return UP;
      else if (plci_state==P2 && ncci_state==N0)
            return WAITING;
      else if (plci_state==P0 && ncci_state==N0)
            return DOWN;
      else
            return OTHER_STATE;
}

_cword
00351 Connection::getCause()
{
      return disconnect_cause;
}

_cword
00357 Connection::getCauseB3()
{
      return disconnect_cause_b3;
}

void
00363 Connection::connect_active_ind(_cmsg& message) throw (CapiWrongState, CapiMsgError)
{
      if (plci_state!=P4 && plci_state!=P1) {
            throw CapiWrongState("CONNECT_ACTIVE_IND received in wrong state","Connection::connect_active_ind()");
      } else {
            try {
                  capi->connect_active_resp(message.Messagenumber,plci);
            }
            catch (CapiMsgError e) {
                  error << prefix() << "WARNING: error detected when trying to send connect_active_resp. Message was:" << e << endl;
            }

            if (plci_state==P1) { // this is an outgoing call, so we have to initiate B3 connection
                  ncci_state=N01;
                  try {
                        capi->connect_b3_req(plci);
                  }
                  catch (CapiMsgError) {
                        plci_state=PACT;
                        ncci_state=N0;
                        throw;  // this is critical, so propagate
                  }
            }
            plci_state=PACT;
      }
}

void
00391 Connection::connect_b3_ind(_cmsg& message) throw (CapiWrongState, CapiMsgError)
{
      if (ncci_state!=N0) {
            throw CapiWrongState("CONNECT_B3_IND received in wrong state","Connection::connect_b3_ind()");
      } else {
            ncci=CONNECT_B3_IND_NCCI(&message);

            // 0 = we'll accept any call, NULL=no NCPI necessary
            // this can throw CapiMsgError. Propagate.
            ncci_state=N2;
            capi->connect_b3_resp(message.Messagenumber,ncci,0,NULL);
      }
}

void
00406 Connection::connect_b3_active_ind(_cmsg& message) throw (CapiError,CapiWrongState, CapiExternalError)
{
      if (ncci_state!=N2) {
            throw CapiWrongState("CONNECT_B3_ACTIVE_IND received in wrong state","Connection::connect_b3_active_ind()");
      } else {
            if (ncci!=CONNECT_B3_ACTIVE_IND_NCCI(&message))
                  throw CapiError("CONNECT_B3_ACTIVE_IND received with wrong NCCI","Connection::connect_b3_active_ind()");
            try {
                  capi->connect_b3_active_resp(message.Messagenumber,ncci);
            }
            catch (CapiMsgError e) {
                  error << prefix() << "WARNING: Error deteced when sending connect_b3_active_resp. Message was: " << e << endl;
            }
            ncci_state=NACT;

            if (service==FAXG3 && CONNECT_B3_ACTIVE_IND_NCPI(&message)[0]>=9) {
                  _cstruct ncpi=CONNECT_B3_ACTIVE_IND_NCPI(&message);
                  if (!fax_info)
                        fax_info=new fax_info_t;
                  fax_info->rate=ncpi[1]+(ncpi[2]<<8);
                  fax_info->hiRes=((ncpi[3] & 0x01) == 0x01);
                  fax_info->format=((ncpi[4] & 0x04) == 0x04);
                  fax_info->pages=ncpi[7]+(ncpi[8]<<8);
                  fax_info->stationID.assign(reinterpret_cast<char*>(&ncpi[10]),static_cast<int>(ncpi[9])); // indx 9 helds the length, string starts at 10
                  if (debug_level >= 2) {
                        debug << prefix() << "fax connected with rate " << dec << fax_info->rate
                          << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->format ? ", JPEG" : "")
                          << ", ID: " << fax_info->stationID << endl;
                  }
            }

            if (call_if)
                  call_if->callConnected();
            else
                  throw CapiExternalError("no call control interface registered!","Connection::connect_b3_active_ind()");
      }
}

void
00445 Connection::disconnect_b3_ind(_cmsg& message) throw (CapiError,CapiWrongState)
{
      if (ncci_state!=NACT && ncci_state!=N1 && ncci_state!=N2 && ncci_state!=N3 && ncci_state!=N4) {
            throw CapiWrongState("DISCONNECT_B3_IND received in wrong state","Connection::disconnect_b3_ind()");
      } else {
            if (ncci!=DISCONNECT_B3_IND_NCCI(&message))
                  throw CapiError("DISCONNECT_B3_IND received with wrong NCCI","Connection::disconnect_b3_ind()");

            disconnect_cause_b3=DISCONNECT_B3_IND_REASON_B3(&message);

            if (service==FAXG3 && CONNECT_B3_ACTIVE_IND_NCPI(&message)[0]>=9) {
                  _cstruct ncpi=CONNECT_B3_ACTIVE_IND_NCPI(&message);
                  if (!fax_info)
                        fax_info=new fax_info_t;
                  fax_info->rate=ncpi[1]+(ncpi[2]<<8);
                  fax_info->hiRes=((ncpi[3] & 0x01) == 0x01);
                  fax_info->format=((ncpi[4] & 0x04) == 0x04);
                  fax_info->pages=ncpi[7]+(ncpi[8]<<8);
                  fax_info->stationID.assign(reinterpret_cast<char*>(&ncpi[10]),static_cast<int>(ncpi[9])); // indx 9 helds the length, string starts at 10
                  if (debug_level >= 2) {
                        debug << prefix() << "fax finished with rate " << dec << fax_info->rate
                          << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->format ? ", JPEG" : "")
                          << ", ID: " << fax_info->stationID << ", " << fax_info->pages << " pages" << endl;
                  }
            }

            pthread_mutex_lock(&send_mutex);
            buffers_used=0; // we'll get no DATA_B3_CONF's after DISCONNECT_B3_IND, see Capi 2.0 spec, 5.18, note for DATA_B3_CONF
            pthread_mutex_unlock(&send_mutex);

            stop_file_transmission();
            stop_file_reception();

            bool our_disconnect_req= (ncci_state==N4) ? true : false;

            ncci_state=N5;

            if (call_if)
                  call_if->callDisconnectedLogical();

            try {
                  ncci_state=N0;
                  capi->disconnect_b3_resp(message.Messagenumber,ncci);
            }
            catch (CapiMsgError e) {
                  error << prefix() << "WARNING: Can't send disconnect_b3_resp. Message was: " << e << endl;
            }

            if (our_disconnect_req && !keepPhysicalConnection) { // this means *we* initiated disconnect of logical connection with DISCONNECT_B3_REQ before
                  try {
                        plci_state=P5;
                        capi->disconnect_req(plci);  // so we'll continue with the disconnect of physical connection
                  }
                  catch (CapiMsgError e) {
                        // in this application this is fatal. Panic please.
                        throw CapiError("Can't disconnect. Please file a bug report. Error message: "+e.message(),"Connection::disconnect_b3_ind()");
                  }
            } else
                  keepPhysicalConnection=false;
      }
}

void
00508 Connection::disconnect_ind(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (ncci_state!=N0 || (plci_state!=P1 && plci_state!=P2 && plci_state!=P3 && plci_state!=P4 && plci_state!=P5 && plci_state!=PACT)) {
            throw CapiWrongState("DISCONNECT_IND received in wrong state","Connection::disconnect_ind()");
      } else {
            if (plci!=DISCONNECT_IND_PLCI(&message))
                  throw CapiError("DISCONNECT_IND received with wrong PLCI","Connection::disconnect_ind()");

            disconnect_cause=DISCONNECT_IND_REASON(&message);

            plci_state=P0;
            capi->disconnect_resp(message.Messagenumber,plci);
            capi->unregisterConnection(plci);

            if (call_if)
                  call_if->callDisconnectedPhysical();
      }
}

void
00528 Connection::data_b3_ind(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (ncci_state!=NACT && ncci_state!=N4)
            throw CapiWrongState("DATA_B3_IND received in wrong state","Connection::data_b3_ind()");

      if (ncci!=CONNECT_B3_IND_NCCI(&message))
            throw CapiError("DATA_B3_IND received with wrong NCCI","Connection::data_b3_ind()");

      pthread_mutex_lock(&receive_mutex);
      if (file_for_reception) {
            for (int i=0;i<DATA_B3_IND_DATALENGTH(&message);i++)
                  (*file_for_reception) << DATA_B3_IND_DATA(&message)[i];
      }
      pthread_mutex_unlock(&receive_mutex);

      if (call_if)
            call_if->dataIn(DATA_B3_IND_DATA(&message),DATA_B3_IND_DATALENGTH(&message));

      capi->data_b3_resp(message.Messagenumber,ncci,DATA_B3_IND_DATAHANDLE(&message));
}

void
00550 Connection::facility_ind_DTMF(_cmsg &message) throw (CapiError,CapiWrongState)
{
      if (plci_state!=PACT)
            throw CapiWrongState("FACILITY_IND received in wrong state","Connection::facility_ind_DTMF()");

      if (plci!=(FACILITY_IND_PLCI(&message) & 0xFFFF) ) // this *should* be PLCI, but who knows - so mask NCCI part if it's there...
            throw CapiError("FACILITY_IND received with wrong PLCI","Connection::facility_ind_DTMF()");

      try {
            capi->facility_resp(message.Messagenumber,plci,1);
      }
      catch (CapiMsgError e) {
            error << prefix() << "WARNING: Can't send facility_resp. Message was: " << e << endl;
      }

      _cstruct facilityIndParam=FACILITY_IND_FACILITYINDICATIONPARAMETER(&message);
      received_dtmf.append(reinterpret_cast<char*>(facilityIndParam+1),static_cast<size_t>(facilityIndParam[0]));  //string, length
      if (debug_level >= 2) {
            debug << prefix() << "received DTMF buffer " << received_dtmf << endl;
      }

      if (call_if)
            call_if->gotDTMF();
}

void
00576 Connection::info_ind_alerting(_cmsg &message) throw (CapiError,CapiWrongState)
{
      if (plci_state!=P01 && plci_state!=P1)
            throw CapiWrongState("INFO_IND for ALERTING received in wrong state","Connection::info_ind_alerting()");

      if (plci!=INFO_IND_PLCI(&message))
            throw CapiError("INFO_IND received with wrong PLCI","Connection::info_ind_alerting()");

      try {
            capi->info_resp(message.Messagenumber,plci);
      }
      catch (CapiMsgError e) {
            error << prefix() << "WARNING: Can't send info_resp. Message was: " << e << endl;
      }

      if (call_if)
            call_if->alerting();
}

bool
00596 Connection::info_ind_called_party_nr(_cmsg &message) throw (CapiError,CapiWrongState)
{
      if (plci_state!=P2)
            throw CapiWrongState("INFO_IND for CalledPartyNr received in wrong state",
              "Connection::info_ind_called_party_nr()");

      if (plci!=INFO_IND_PLCI(&message))
            throw CapiError("INFO_IND received with wrong PLCI",
              "Connection::info_ind_called_party_nr()");
      try {
            capi->info_resp(message.Messagenumber,plci);
      }
      catch (CapiMsgError e) {
            error << prefix() << "WARNING: Can't send info_resp. Message was: " << 
              e << endl;
      }

      call_to+=getNumber(INFO_IND_INFOELEMENT(&message),false);
      
      string currDDI;
      try {
            currDDI=call_to.substr(DDIBaseLength);
      }
      catch (std::out_of_range e) {
            throw CapiError("DDIBaseLength too big - configuration error?",
              "Connection::info_ind_called_party_nr()");
      }
      for (int i=0;i<DDIStopNumbers.size();i++)
          if (DDIStopNumbers[i]==currDDI) {
                  if (debug_level >= 1)
                        debug << prefix() << "got DDI, nr is now " << call_to << " (complete,stop_nr)" << endl;
                  return true;
          }

      if (call_to.length()>=DDIBaseLength+DDILength) {
            if (debug_level >=1)
                  debug << prefix() << "got DDI, nr is now " << call_to << " (complete)" << endl;
            return true;
      } else {
            if (debug_level >=1)
                        debug << prefix() << "got DDI, nr is now " << call_to << " (incomplete)" << endl;
                return false;
      }
}

void
00642 Connection::connect_conf(_cmsg& message) throw (CapiWrongState, CapiMsgError)
{
      if (plci_state!=P01)
            throw CapiWrongState("CONNECT_CONF received in wrong state","Connection::connect_conf()");

      if (CONNECT_CONF_INFO(&message))
            throw CapiMsgError(CONNECT_CONF_INFO(&message),"CONNECT_CONF received with Error (Info)","Connection::connect_conf()");
            // TODO: do we have to delete Connection here if Info!=0 or is a DISCONNECT_IND initiated then (think not ...)

      plci=CONNECT_CONF_PLCI(&message);
      if (debug_level >= 2) {
            debug << prefix() << "got PLCI " << plci << endl;
      }

      plci_state=P1;
}

void
00660 Connection::connect_b3_conf(_cmsg& message) throw (CapiWrongState, CapiMsgError)
{
      if (ncci_state!=N01)
            throw CapiWrongState("CONNECT_B3_CONF received in wrong state","Connection::connect_b3_conf()");

      if (CONNECT_B3_CONF_INFO(&message)) {
            ncci_state=N0;
            throw CapiMsgError(CONNECT_B3_CONF_INFO(&message),"CONNECT_B3_CONF received with Error (Info)","Connection::connect_b3_conf()");
      }

      ncci=CONNECT_B3_CONF_NCCI(&message);

      ncci_state=N2;
}

void
00676 Connection::select_b_protocol_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (plci_state!=PACT || ncci_state!=N0)
            throw CapiWrongState("SELECT_B_PROTOCOL_CONF received in wrong state","Connection::select_b_protocol_conf()");

      if (plci!=SELECT_B_PROTOCOL_CONF_PLCI(&message))
            throw CapiError("SELECT_B_PROTOCOL_CONF received with wrong PLCI","Connection::select_b_protocol_conf()");

      if (SELECT_B_PROTOCOL_CONF_INFO(&message))
            throw CapiMsgError(SELECT_B_PROTOCOL_CONF_INFO(&message),"SELECT_B_PROTOCOL_CONF received with Error (Info)","Connection::select_b_protocol_conf()");

      if (our_call) {
            try {
                  ncci_state=N01;
                  capi->connect_b3_req(plci);
            }
            catch (CapiMsgError) {
                  ncci_state=N0;
                  throw;  // this is critical, so propagate
            }
      }
}

void
00700 Connection::alert_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (plci_state!=P2 && plci_state!=P5)
            throw CapiWrongState("ALERT_CONF received in wrong state","Connection::alert_conf()");

      if (plci!=ALERT_CONF_PLCI(&message))
            throw CapiError("ALERT_CONF received with wrong PLCI","Connection::alert_conf()");

      if (ALERT_CONF_INFO(&message) && ALERT_CONF_INFO(&message)!=0x0003) // 0x0003 = another application sent ALERT_REQ earlier -> no problem for us
            throw CapiMsgError(ALERT_CONF_INFO(&message),"ALERT_CONF received with Error (Info)","Connection::alert_conf()");
}

void
00713 Connection::data_b3_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError,CapiExternalError)
{
      if (ncci_state!=NACT)
            throw CapiWrongState("DATA_B3_CONF received in wrong state","Connection::data_b3_conf()");

      if (ncci!=DATA_B3_CONF_NCCI(&message))
            throw CapiError("DATA_B3_CONF received with wrong NCCI","Connection::data_b3_conf()");

      if (DATA_B3_CONF_INFO(&message))
            throw CapiMsgError(DATA_B3_CONF_INFO(&message),"DATA_B3_CONF received with Error (Info)","Connection::data_b3_conf()");

      pthread_mutex_lock(&send_mutex);

      try {
            if ( (!buffers_used) || (DATA_B3_CONF_DATAHANDLE(&message)!=buffer_start) )
                  throw CapiError("DATA_B3_CONF received with invalid data handle","Connection::data_b3_conf()");
            // free one buffer
            buffers_used--;
            buffer_start=(buffer_start+1)%7;
            while (file_to_send && (buffers_used < conf_send_buffers) )
                  send_block();
      }
      catch (...) {
            pthread_mutex_unlock(&send_mutex);
            throw;
      }
      pthread_mutex_unlock(&send_mutex);
}

void
00743 Connection::facility_conf_DTMF(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (plci_state!=PACT)
            throw CapiWrongState("FACILITY_CONF for DTMF received in wrong state","Connection::facility_conf_DTMF()");

      if (plci!=(FACILITY_CONF_PLCI(&message) & 0xFFFF)) // this *should* be the PLCI but to be sure we mask out NCCI part
            throw CapiError("FACILITY_CONF received with wrong PLCI","Connection::facility_conf_DTMF()");

      if (FACILITY_CONF_INFO(&message))
            throw CapiMsgError(FACILITY_CONF_INFO(&message),"FACILITY_CONF received with Error (Info)","Connection::facility_conf_DTMF()");

      _cstruct facilityConfParameter=FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&message);
      if ((facilityConfParameter[0]==2) && facilityConfParameter[1])
            throw CapiMsgError(FACILITY_CONF_INFO(&message),"FACILITY_CONF received with DTMF Error (DTMF information)","Connection::facility_conf_DTMF()");
}

void
00760 Connection::disconnect_b3_conf(_cmsg& message) throw (CapiError,CapiWrongState, CapiMsgError)
{
      if (ncci_state!=N4)
            throw CapiWrongState("DISCONNECT_B3_CONF received in wrong state","Connection::disconnect_b3_conf()");

      if (ncci!=DISCONNECT_B3_CONF_NCCI(&message))
            throw CapiError("DISCONNECT_B3_CONF received with wrong NCCI","Connection::disconnect_b3_conf()");

      if (DISCONNECT_B3_CONF_INFO(&message))
            throw CapiMsgError(DISCONNECT_B3_CONF_INFO(&message),"DISCONNECT_B3_CONF received with Error (Info)","Connection::disconnect_b3_conf()");
}

void
00773 Connection::disconnect_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError)
{
      if (plci_state!=P5)
            throw CapiWrongState("DISCONNECT_CONF received in wrong state","Connection::disconnect_conf()");

      if (plci!=DISCONNECT_CONF_PLCI(&message))
            throw CapiError("DISCONNECT_CONF received with wrong PLCI","Connection::disconnect_conf()");

      if (DISCONNECT_CONF_INFO(&message))
            throw CapiMsgError(DISCONNECT_CONF_INFO(&message),"DISCONNECT_CONF received with Error (Info)","Connection::disconnect_conf()");
}

void
00786 Connection::disconnectCall(disconnect_mode_t disconnect_mode) throw (CapiMsgError)
{
      if (debug_level >= 1) {
            debug << prefix() << "disconnect initiated" << endl;
      }
      if ((ncci_state==N1 || ncci_state==N2 || ncci_state==N3 || ncci_state==NACT) && (disconnect_mode==ALL || disconnect_mode==LOGICAL_ONLY) ) {  // logical connection up
            ncci_state=N4;
            capi->disconnect_b3_req(ncci); // can throw CapiMsgError. Fatal here. Propagate
            if (disconnect_mode==LOGICAL_ONLY)
                  keepPhysicalConnection=true;
      } else if ((plci_state==PACT || plci_state==P1 || plci_state==P2 || plci_state==P3 || plci_state==P4) && (disconnect_mode==ALL || disconnect_mode==PHYSICAL_ONLY) ) { // physical connection up
            plci_state=P5;
            capi->disconnect_req(plci); // can throw CapiMsgError. Fatal here. Propagate
      }
      // otherwise do nothing
}

void
00804 Connection::send_block() throw (CapiError,CapiWrongState,CapiExternalError,CapiMsgError)
{
      if (ncci_state!=NACT)
            throw CapiWrongState("unable to send file because connection is not established","Connection::send_block()");

      if (!file_to_send)
            throw CapiError("unable to play file because no input file is open","Connection::send_block()");

      if (buffers_used>=7)
            throw CapiError("unable to send file snippet because buffers are full","Connection::send_block()");

      bool file_completed=false;

      unsigned short buff_num=(buffer_start+buffers_used)%7; // buffer to store the next item

      int i=0;
      while (i<2048 && !file_completed) {
            if (!file_to_send->get(send_buffer[buff_num][i]))
                  file_completed=true;
            else
                  i++;
      }

      try {
            if (i>0) {
                  capi->data_b3_req(ncci,send_buffer[buff_num],i,buff_num,0); // can throw CapiMsgError. Propagate.
                  buffers_used++;
            }
      }
      catch (CapiMsgError e) {
            error << prefix() << "WARNING: Can't send data_b3_req. Message was: " << e << endl;
            if (file_completed) {
                  file_to_send->close();
                  delete file_to_send;
                  file_to_send=NULL;
            }
      }

      if (file_completed) {
            file_to_send->close();
            delete file_to_send;
            file_to_send=NULL;
            if (call_if)
                  call_if->transmissionComplete();
            else
                  throw CapiExternalError("no call control interface registered!","Connection::send_block()");
      }
}

void
00854 Connection::start_file_transmission(string filename) throw (CapiError,CapiWrongState,CapiExternalError,CapiMsgError)
{
      if (debug_level >= 2) {
            debug << prefix() << "start_file_transmission " << filename << endl;
      }
      if (ncci_state!=NACT)
            throw CapiWrongState("unable to send file because connection is not established","Connection::start_file_transmission()");

      if (file_to_send)
            throw CapiExternalError("unable to send file because transmission is already in progress","Connection::start_file_transmission()");

      file_to_send=new ifstream(filename.c_str());

      if (! (*file_to_send)) { // we can't open the file
            delete file_to_send;
            file_to_send=NULL;
            throw CapiExternalError("unable to open file to send ("+filename+")","Connection::start_file_transmission()");
      } else {
            pthread_mutex_lock(&send_mutex);
            try {
                  while (file_to_send && buffers_used<conf_send_buffers)
                        send_block();
            }
            catch (...) {
                  pthread_mutex_unlock(&send_mutex);
                  throw;
            }
            pthread_mutex_unlock(&send_mutex);
      }
}

void
00886 Connection::stop_file_transmission()
{
      if (debug_level >= 2) {
            debug << prefix() << "stop_file_transmission initiated" << endl;
      }
      pthread_mutex_lock(&send_mutex);
      if (file_to_send) {
            file_to_send->close();
            delete file_to_send;
            file_to_send=NULL;
      }
      pthread_mutex_unlock(&send_mutex);

      timespec delay_time;
      delay_time.tv_sec=0; delay_time.tv_nsec=100000000;  // 100 msec
      while (buffers_used) // wait until all packages are transmitted
            nanosleep(&delay_time,NULL);
      if (debug_level >= 2) {
            debug << prefix() << "stop_file_transmission finished" << endl;
      }
}

void
00909 Connection::start_file_reception(string filename) throw (CapiWrongState, CapiExternalError)
{
      if (debug_level >= 2) {
            debug << prefix() << "start_file_reception " << filename << endl;
      }
      if (ncci_state!=NACT)
            throw CapiWrongState("unable to receive file because connection is not established","Connection::start_file_reception()");

      if (file_for_reception)
            throw CapiExternalError("file reception is already active","Connection::start_file_reception()");

      file_for_reception=new ofstream(filename.c_str());
      if (! (*file_for_reception)) { // we can't open the file
            delete file_for_reception;
            file_for_reception=NULL;
            throw CapiExternalError("unable to open file for reception ("+filename+")","Connection::start_file_reception()");
      }
}

void
00929 Connection::stop_file_reception()
{
      pthread_mutex_lock(&receive_mutex);

      if (file_for_reception) {
            file_for_reception->close();
            delete file_for_reception;
            file_for_reception=NULL;
      }

      pthread_mutex_unlock(&receive_mutex);
      if (debug_level >= 2) {
            debug << prefix() << "stop_file_reception finished" << endl;
      }
}

void
00946 Connection::enableDTMF() throw (CapiWrongState, CapiMsgError)
{
      if (plci_state!=PACT)
            throw CapiWrongState("unable to enable DTMF because connection is not established","Connection::enableDTMF()");

      _cstruct facilityRequestParameter=new unsigned char[1+2+2+2+1+3];
      int i=0;
      facilityRequestParameter[i++]=2+2+2+1+3; // total length
      facilityRequestParameter[i++]=1; facilityRequestParameter[i++]=0;  // start DTMF listen
      facilityRequestParameter[i++]=40; facilityRequestParameter[i++]=0;  // default value for tone-duration
      facilityRequestParameter[i++]=40; facilityRequestParameter[i++]=0;  // default value for gap-duration
      facilityRequestParameter[i++]=0; // we don't want to send DTMF now (=empty struct)
      facilityRequestParameter[i++]=2; // now let's start substruct DTMF Characteristics (length)
      facilityRequestParameter[i++]=0; facilityRequestParameter[i++]=0;  // default value for DTMF Selectivity

      try {
            capi->facility_req(plci,1,facilityRequestParameter);
      }
      catch  (CapiMsgError) {
            delete[] facilityRequestParameter;
            throw;
      }
      delete[] facilityRequestParameter;
}

void
00972 Connection::disableDTMF() throw (CapiWrongState, CapiMsgError)
{
      if (plci_state!=PACT)
            throw CapiWrongState("unable to disable DTMF because connection is not established","Connection::disableDTMF()");

      _cstruct facilityRequestParameter=new unsigned char[1+2+2+2+1+1];
      int i=0;
      facilityRequestParameter[i++]=2+2+2+1+1; // total length
      facilityRequestParameter[i++]=2; facilityRequestParameter[i++]=0;  // stop DTMF listen
      facilityRequestParameter[i++]=40; facilityRequestParameter[i++]=0;  // default value for tone-duration
      facilityRequestParameter[i++]=40; facilityRequestParameter[i++]=0;  // default value for gap-duration
      facilityRequestParameter[i++]=0; // we don't want to send DTMF now (=empty struct)
      facilityRequestParameter[i++]=0; // no DTMF Characteristics

      try {
            capi->facility_req(plci,1,facilityRequestParameter);
      }
      catch (CapiMsgError) {
            delete[] facilityRequestParameter;
            throw;
      }
      delete[] facilityRequestParameter;
}

string
00997 Connection::getDTMF()
{
      return received_dtmf;
}

void
01003 Connection::clearDTMF()
{
#ifdef HAVE_STRING_CLEAR
      received_dtmf.clear();
#else
      received_dtmf="";
#endif
}

string
01013 Connection::getNumber(_cstruct capi_input, bool isCallingNr)
{
// CallingNr: byte 0: length (w/o byte 0), Byte 1+2 see ETS 300 102-1, Chapter 4.5, byte 3-end: number (w/o leading "0" or "00")
// CalledNr:  byte 0: length (w/o byte 0), Byte 1 see ETS 300 102-1, Chapter 4, byte 2-end: number w/o leading "0" or "00"
      int length=capi_input[0];

      if (!length) // no info element given
            return "-";

      char *nr=new char[length];
      memcpy (nr,&capi_input[2],length-1); // copy only number
      nr[length-1]='\0';                   // add \0
      string a(nr);
      if (isCallingNr)
            a=a.substr(1);

      // if we are looking at a CallingPartyNumber and it is an international number or a national number
      // (see ETS 300 102-1, chapter 4.5), we'll add the prefix "0" or "+"

      if (a.empty()) {
            a="-";
      } else if (isCallingNr && ((capi_input[1] & 0x70) == 0x20)) {  // national number
            a='0'+a;
      } else if (isCallingNr && ((capi_input[1] & 0x70) == 0x10)) { // international number
            a='+'+a;
      }
      return a;
}

void
01043 Connection::buildBconfiguration(_cdword controller, service_t service, string faxStationID, string faxHeadline, _cword& B1proto, _cword& B2proto, _cword& B3proto, _cstruct& B1config, _cstruct& B2config, _cstruct& B3config) throw (CapiExternalError)
{
      switch (service) {
            case VOICE:
                  if (!capi->profiles[controller-1].transp)
                        throw (CapiExternalError("controller doesn't support voice (transparent) services","Connection::buildBconfiguration()"));
                  B1proto=1;  // bit-transparent
                  B2proto=1;  // Transparent
                  B3proto=0;  // Transparent
                  B1config=NULL; // no configuration for bit-transparent available
                  B2config=NULL; // no configuration for transparent available
                  B3config=NULL; // no configuration for transparent available
            break;

            case FAXG3: {
                  B1proto=4; // T.30 modem for Fax G3
                  B2proto=4; // T.30 for Fax G3
                  if (capi->profiles[controller-1].faxExt)
                        B3proto=5; // T.30 for Fax G3 Extended
                  else if (capi->profiles[controller-1].fax)
                        B3proto=4; // T.30 for Fax G3
                  else
                        throw (CapiExternalError("controller doesn't support fax services","Connection::buildBconfiguration()"));

                  B1config=NULL; // default configuration (adaptive maximum baud rate, default transmit level)
                  B2config=NULL; // no configuration available

                  if (faxStationID.size()>20) // stationID mustn't exceed 20 characters
                        faxStationID=faxStationID.substr(0,20);
                  if (faxHeadline.size()>254)  // if the string would be longer the struct must be coded different, but I think a header > 254 bytes has no sence
                        faxHeadline=faxHeadline.substr(0,254);

                  // convert faxHeadline to CP437 for AVM drivers as they expect the string in this format
                  if (capi->profiles[controller-1].manufacturer.find("AVM")!=std::string::npos)
                        convertToCP437(faxHeadline);

                  B3config=new unsigned char [1+2+2+1+faxStationID.size()+1+faxHeadline.size()]; // length + 1 byte for the length itself
                  int i=0;
                  B3config[i++]=2+2+1+faxStationID.size()+1+faxHeadline.size();  // length
                  B3config[i++]=0; B3config[i++]=0; // resolution = standard
                  B3config[i++]=0; B3config[i++]=0; // format: SFF
                  B3config[i++]=faxStationID.size();
                  for (unsigned j=0;j<faxStationID.size();j++)
                        B3config[i++]=faxStationID[j];
                  B3config[i++]=faxHeadline.size();
                  for (unsigned j=0;j<faxHeadline.size();j++)
                        B3config[i++]=faxHeadline[j];
            } break;

            default:
                  throw CapiExternalError("unsupported service given by application","Connection::buildBconfiguration()");
            break;
      }
}

void
01099 Connection::convertToCP437(string &text)
{
      size_t from_length=text.size()+1;
      size_t to_length=from_length;

      char* from_buf=new char[from_length];
      char* from_buf_tmp=from_buf; // as pointer is changed by iconv()
      char* to_buf = new char[to_length];
      char* to_buf_tmp=to_buf; // as pointer is changed by iconv()

      strncpy(from_buf,text.c_str(),from_length);

      iconv_t conv=iconv_open("CP437","Latin1");

      if (conv==(iconv_t)-1) {
            error << prefix() << "WARNING: string conversion to CP437 not supported by iconv" << endl;
            return;
      }

      if (iconv(conv,&from_buf_tmp,&from_length,&to_buf_tmp,&to_length)==(size_t)-1) {
            char msg[200];
            error << prefix() << "WARNING: error during string conversion (iconv): " << strerror_r(errno,msg,200) << endl;
            return;
      }

      if (iconv_close(conv)!=0)
            throw CapiExternalError("error during string conversion (iconv_close)","Connection::convertToCP437");

      text=to_buf;
        delete[] from_buf;
        delete[] to_buf;
}


/*  History

$Log: connection.cpp,v $
Revision 1.11.2.5  2003/11/06 18:32:15  gernot
- implemented DDIStopNumbers

Revision 1.11.2.4  2003/11/02 14:58:16  gernot
- use DDI_base_length instead of DDI_base
- added DDI_stop_numbers option
- use DDI_* options in the Connection class
- call the Python script if number is complete

Revision 1.11.2.3  2003/11/01 22:59:33  gernot
- read CalledPartyNr InfoElements

Revision 1.11.2.2  2003/10/26 16:52:55  gernot
- begin implementation of DDI; get DDI info elements

Revision 1.11.2.1  2003/07/20 19:08:44  gernot
- added missing include of errno.h

Revision 1.11  2003/06/29 06:18:13  gernot
- don't take a wrong character too serious...

Revision 1.10  2003/06/28 12:49:47  gernot
- convert fax headline to CP437, so that german umlauts and other special
  characters will work now

Revision 1.9  2003/05/25 13:38:30  gernot
- support reception of color fax documents

Revision 1.8  2003/05/24 13:48:54  gernot
- get fax details (calling station ID, transfer format, ...), handle PLCI

Revision 1.7  2003/04/17 10:39:42  gernot
- support ALERTING notification (to know when it's ringing on the other side)
- cosmetical fixes in capi.cpp

Revision 1.6  2003/04/17 10:36:29  gernot
- fix another typo which could probably lead to errors in sending own number...

Revision 1.5  2003/04/10 21:29:51  gernot
- support empty destination number for incoming calls correctly (austrian
  telecom does this (sic))
- core now returns "-" instead of "??" for "no number available" (much nicer
  in my eyes)
- new wave file used in remote inquiry for "unknown number"

Revision 1.4  2003/04/04 09:17:59  gernot
- buildBconfiguration() now checks the abilities of the given controller
  and throws an error if it doesn't support the service
- it also sets the fax protocol setting now the highest available ability
  (fax G3 or fax G3 extended) of the controller, thus preparing fax polling
  and *working around a severe bug in the AVM drivers producing a kernel
  oops* with some analog fax devices. AVM knows about this and analyzes it.

Revision 1.3  2003/03/21 23:09:59  gernot
- included autoconf tests for gcc-2.95 problems so that it will compile w/o
  change for good old gcc-2.95 and gcc3

Revision 1.2  2003/02/28 21:36:51  gernot
- don't allocate new B3config in buildBconfiguration(), fixes bug 532
- limit stationID to 20 characters

Revision 1.1.1.1  2003/02/19 08:19:53  gernot
initial checkin of 0.4

Revision 1.44  2003/02/10 14:20:52  ghillie
merged from NATIVE_PTHREADS to HEAD

Revision 1.43  2003/02/09 15:16:29  ghillie
- fixed some delete calls to delete[]

Revision 1.42.2.1  2003/02/10 14:10:27  ghillie
- use pthread_mutex_* instead of CommonC++ semaphores

Revision 1.42  2003/01/31 16:33:13  ghillie
- callingParty wasn't set

Revision 1.41  2003/01/31 11:27:50  ghillie
- wrong initialization of debug_level for outgoing connections fixed

Revision 1.40  2003/01/19 16:50:27  ghillie
- removed severity in exceptions. No FATAL-automatic-exit any more.
  Removed many FATAL conditions, other ones are exiting now by themselves

Revision 1.39  2003/01/13 21:30:23  ghillie
- FIX: removed erroneous checking of connect_ind_msg_nr in rejectWaiting()
  and checked for our_call instead (oops, overlooked this one ;-) )

Revision 1.38  2003/01/04 16:08:22  ghillie
- log improvements: log_level, timestamp
- added methods debugMessage(), errorMessage(), removed get*Stream()
- added some additional debug output for connection setup / finish

Revision 1.37  2002/12/18 14:46:07  ghillie
- removed debug output

Revision 1.36  2002/12/18 14:45:13  ghillie
- moved *_state=XY actions direct in front of messages sent to CAPI, so that
  parallel executed threads don't see a wrong state (hopefully)
- removed test for connect_ind_msg_nr!=0 in connectWaiting(). Don't know
  what I intended with this (sigh)
- added missing "{" in select_b_protocol_conf() :-(
- removed unnecessary plci_state=PACT in select_b_protocol_conf

Revision 1.35  2002/12/16 15:05:47  ghillie
- FIX: corrected disconnect behaviour (physical connection is now disconnected
  correctly)

Revision 1.34  2002/12/16 13:13:47  ghillie
- added getCauseB3 to return B3 cause

Revision 1.33  2002/12/13 11:46:19  ghillie
- new attribute our_call to inidicate that we initiated a connection
- send CONNECT_B3_REQ after receiving SELECT_B_PROTOCOL_CONF for outgoing calls

Revision 1.32  2002/12/13 09:57:44  ghillie
- error message formatting done by exception classes now

Revision 1.31  2002/12/11 13:38:43  ghillie
- FIX: added missing init of keepPhysicalConnection in outgoing constructor
- use quick disconnect (PHYSICAL_ONLY) in destructor
- disconnectCall(): added support for PHYSICAL_ONLY disconnect

Revision 1.30  2002/12/10 15:06:15  ghillie
- new methods get*Stream() for use in capisuitemodule

Revision 1.29  2002/12/09 15:42:07  ghillie
- saves debug and error stream in own attributes now
- debug output improvements, error output included
- unregistering at Capi now done as soon as DISCONNECT_IND is received

Revision 1.28  2002/12/06 15:25:39  ghillie
- cleaned up and fixed destructor (wrong order of some calls)
- new return value for getState(): WAITING

Revision 1.27  2002/12/06 13:06:44  ghillie
- added support for saving disconnect cause
- ~Connection does busy wait for disconnect to prevent Connection objects
  going away while the corresponding call is still active
- added error checking for connect_ind_msg_nr
- new methods getState() and getCause()

Revision 1.26  2002/12/05 15:04:29  ghillie
- Capi::connect_req() gets this now
- call capi->unregisterConnection(plci) in destructor
- connect_conf() sets plci attribute
- connect_b3_conf() sets ncci attribute

Revision 1.25  2002/12/04 10:43:43  ghillie
- small FIX in getNumber(): added missing parantheses in if condition -> national number & international number work now

Revision 1.24  2002/12/02 12:31:10  ghillie
- renamed Connection::SPEECH to Connection::VOICE

Revision 1.23  2002/11/29 10:25:01  ghillie
- updated comments, use doxygen format now

Revision 1.22  2002/11/27 16:02:54  ghillie
- added missing throw() declaration in changeProtocol()
- added missing state check in acceptWaiting()
- data_b3_ind and disconnect_ind propagate CapiMsgError now
- DTMF handling routines and select_b_protocol_conf test for state of physical connection instead of logical connection now

Revision 1.21  2002/11/25 11:51:45  ghillie
- removed the unhandy CIP parameters from the interface to the application layer, use service type instead
- rejectWaiting() tests against cause!=0 now
- removed isUp() method

Revision 1.20  2002/11/22 15:13:44  ghillie
- new attribute keepPhysicalConnection which prevents disconnect_b3_ind() from sending disconnect_req()
- moved the ugly B*configuration, B*protocol settings from some methods to private method buildBconfiguration
- new methods changeProtocol(), select_b_protocol_conf(), clearDTMF()
- disconnect_b3_ind sets ncci_state to N0 before calling the callbacks
- added parameter disconnect_mode to disconnectCall()
- getDTMF() does non-destructive read now

Revision 1.19  2002/11/21 15:28:12  ghillie
- removed ALERT_REQ sending from constructor - this is now done by the python functions connect_*()
- new method Connection::acceptWaiting() - sends ALERT_REQ for use by the above mentioned python functions
- connectWaiting changes cipValue now

Revision 1.18  2002/11/20 17:24:58  ghillie
- added check if call_if is set in data_b3_ind before it's called (ouch!)
- changed impossible error to ::FATAL in send_block()

Revision 1.17  2002/11/19 15:57:18  ghillie
- Added missing throw() declarations
- phew. Added error handling. All exceptions are caught now.

Revision 1.16  2002/11/18 14:24:09  ghillie
- moved global severity_t to CapiError::severity_t
- added throw() declarations

Revision 1.15  2002/11/18 12:23:17  ghillie
- fix: set buffers_used to 0 in critical section in Connection::disconnect_b3_ind()
- disconnectCall() doesn't throw exception any more (does nothing if we have wrong state),
  so we can call it w/o knowledge if connection is still up

Revision 1.14  2002/11/17 14:40:47  ghillie
- improved exception throwing, different exception kinds are used now
- added isUp()

Revision 1.13  2002/11/15 15:25:53  ghillie
added ALERT_REQ so we don't loose a call when we wait before connection establishment

Revision 1.12  2002/11/15 13:49:10  ghillie
fix: callmodule wasn't aborted when call was only connected/disconnected physically

Revision 1.11  2002/11/14 17:05:19  ghillie
major structural changes - much is easier, nicer and better prepared for the future now:
- added DisconnectLogical handler to CallInterface
- DTMF handling moved from CallControl to Connection
- new call module ConnectModule for establishing connection
- python script reduced from 2 functions to one (callWaiting, callConnected
  merged to callIncoming)
- call modules implement the CallInterface now, not CallControl any more
  => this freed CallControl from nearly all communication stuff

Revision 1.10  2002/11/13 08:34:54  ghillie
moved history to the bottom

Revision 1.9  2002/11/12 15:51:12  ghillie
minor fixes (avoid deadlock, don't wait for DATA_B3_CONF after DISCONNECT_B3_IND) in file_transmission code
added dataIn handler
minor fixes (and reformatting) in getNumber()

Revision 1.8  2002/11/10 17:05:18  ghillie
changed to support multiple buffers -> deadlock in stop_file_transmission!!

Revision 1.7  2002/11/08 07:57:06  ghillie
added functions to initiate a call
corrected FACILITY calls to use PLCI instead of NCCI in DTMF processing as told by Mr. Ortmann on comp.dcom.isdn.capi

Revision 1.6  2002/10/31 15:39:04  ghillie
added missing FACILITY_RESP message (oops...)

Revision 1.5  2002/10/31 12:40:06  ghillie
added DTMF support
small fixes like making some unnecessary global variables local, removed some unnecessary else cases

Revision 1.4  2002/10/30 14:29:25  ghillie
added getCIPvalue

Revision 1.3  2002/10/30 10:47:13  ghillie
added debug output

Revision 1.2  2002/10/29 14:27:09  ghillie
added stop_file_*, added semaphore calls to guarantee right order of execution (I hope ;-) )

Revision 1.1  2002/10/25 13:29:38  ghillie
grouped files into subdirectories

Revision 1.15  2002/10/24 09:55:52  ghillie
many fixes. Works for one call now

Revision 1.14  2002/10/23 09:43:05  ghillie
small variable name change (stationID->faxStationID)

Revision 1.13  2002/10/10 12:45:40  gernot
added AudioReceive module, some small details changed

Revision 1.12  2002/10/09 14:36:22  gernot
added CallModule base class for all call handling modules

Revision 1.11  2002/10/09 11:18:59  gernot
cosmetic changes (again...) and changed info function of CAPI class

Revision 1.10  2002/10/05 13:53:00  gernot
changed to use thread class of CommonC++ instead of the threads-package
some cosmetic improvements (indentation...)

Revision 1.9  2002/10/04 15:48:03  gernot
structure changes completed & compiles now!

Revision 1.8  2002/10/04 13:27:15  gernot
some restructuring to get it to a working state ;-)
does not do anything useful yet nor does it even compile...

Revision 1.7  2002/10/01 09:02:04  gernot
changes for compilation with gcc3.2

Revision 1.6  2002/09/22 14:22:53  gernot
some cosmetic comment improvements ;-)

Revision 1.5  2002/09/19 12:08:19  gernot
added magic CVS strings

Revision 1.4  2002/09/18 16:59:48  gernot
added version info

* Sun Sep 15 2002 - gernot@hillier.de
- put under CVS, cvs log follows above

* Sun May 20 2002 - gernot@hillier.de
- first version

*/

Generated by  Doxygen 1.6.0   Back to index