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

connection.h

Go to the documentation of this file.
/** @file connection.h
    @brief Contains Connection - Encapsulates a CAPI connection with all its states and methods.

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

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

#ifndef CONNECTION_H
#define CONNECTION_H

#include <capi20.h>
#include <vector>
#include <string>
#include <fstream>
#include "capiexception.h"

class CallInterface;
class Capi;

using namespace std;

/** @brief Encapsulates a CAPI connection with all its states and methods.

    This class encapsulates one ISDN connection (physical and logical). It has two groups of methods:
    methods which are supposed to be called from the application (declared public) which serve to
    access the connection, send data, clear it etc. Also there are many message handlers implemented
    (declared as private) which are called by Capi::readMessage() and do the most message handling stuff.

    Only one logical connection per physical connection is supported.

    To communicate with the application by callback functions, the application must implement the CallInterface.
    The methods of this class are called if different events occur like call completion or a finished data transfer.

    There are two ways how Connection objects are created:
      - automatically for each incoming connection
      - manually to initiate a outgoing connection

   @author Gernot Hillier
*/
00049 class Connection
{
      friend class Capi;

      public:
            /** @brief Type for describing the service of incoming and outgoing calls.

                Several similar services are grouped together so the application doesn't have to distinct between speech calls
                originating from the analog or digital network, between devices providing a High Layer compatibility and devices
                which only provide bearer capabilities and so on.

                For outgoing calls, the most specific value will be used.

                For exact details concerning the different services see the parameter CIP in the CAPI spec.
            */
00064             enum service_t {
00065                   VOICE, ///< connections for speech services originated from the analog or digital network (CIP values 1,4,16)
00066                   FAXG3,  ///< connections for fax Group2/3 services originating from the digital network (as analog networks don't provide service indicator) (CIP value 17)
00067                   OTHER   ///< all other service types not included in the above values
            };

            /** @brief Constructor. Create an object to initiate an outgoing call

                This constructor is used when the application creates a Connection object manually to initiate an outgoing connection.

                It constructs the necessary information elements (B channel protocol settings, Number elements) and calls 
                Capi::connect_req to initiate a call.

                @param capi pointer to the Capi Object
                @param controller number of the controller which should initiate the call
                @param call_from our number
                @param clir set to TRUE to hide our number (so that the called party can't see it)
                @param call_to the number which we want to call
                @param service service to use (currently only VOICE and FAXG3 are supported), see service_t
                @param faxStationID fax station ID, only used with service faxG3
                @param faxHeadline fax headline (written on each fax page), only used with service faxG3, encoded in ISO8859-1
                @throw CapiExternalError thrown when parameters are missing or wrong
                @throw CapiMsgError thrown by Capi::connect_req, see there
            */
            Connection (Capi* capi, _cdword controller, string call_from, bool clir, string call_to, service_t service, string faxStationID, string faxHeadline) throw (CapiExternalError, CapiMsgError);

            /** @brief. Destructor. Deletes the connection object.

                Can block if file transmission is still in progress and/or if connection is not cleared already.
                
                Please call as soon as you don't need the object any more as this will also free some
                CAPI resources associated to the call.

                Please disconnect before deleting a Connection object! The auto-disconnect here is only supported
                to prevent fatal errors and won't work very nicely!!
            */
            ~Connection();

            /** @brief Register the instance implementing the CallInterface

                @param call_if - pointer to the instance to use
            */
            void registerCallInterface(CallInterface *call_if);

            /** @brief Change the used B protcols (e.g. switch from speech to faxG3)

                You have to disconnect the logical connection before calling this method. So to change from speech to fax do:
                  - disconnect(LOGICAL_ONLY);
                  - wait for CallInterface::CallDisconnectedLogical() to be called
                  - changeProtocol(FAXG3,"stationID","headline")
                  - wait for CallInterface::callConnected() to be called
                  
                Does nothing if the requested service is already active. Otherwise the necessary information elements are built
                and Capi::select_b_protocol_req is called.

                @param desired_service service to switch to
                @param faxStationID Only needed when switching to FaxG3. The fax station ID to use.
                @param faxHeadline Only needed when switching to FaxG3. The fax headline to use, encoded in ISO8859-1
                @throw CapiExternalError Thrown by Connection::buildBconfiguration. See there.
                @throw CapiMsgError Thrown by Connection::select_b_protocol_req. See there.
                @throw CapiWrongState Connection is in wrong state. Either it was finished by the partner or you didn't disconnect the logical connection before calling changeProtocol
            */
            void changeProtocol (service_t desired_service, string faxStationID, string faxHeadline) throw (CapiMsgError, CapiExternalError, CapiWrongState);

            /** @brief called to start sending of a file
                
                The transmission will be controlled automatically by Connection - no further user interaction is necessary
                if the whole file should be sent.

                The file has to be in the correct format expected by CAPI, i.e. bit-reversed A-Law, 8 khz, mono (".la" for sox) for speech, SFF for faxG3

                @param filename the name of the file which should be sent
                @throw CapiWrongState Thrown if Connection isn't up completely (physical & logical)
                @throw CapiExternalError Thrown if file transmission is already in progress or the file couldn't be opened
                @throw CapiMsgError Thrown by send_block(). See there.
                @throw CapiError Thrown by send_block(). See there.
            */
            void start_file_transmission(string filename) throw (CapiError,CapiWrongState,CapiExternalError,CapiMsgError);

            /** @brief called to stop sending of the current file, will block until file is really finished

                If you stop the file transmission manually, CallInterface::transferCompleted won't be called.
            */
            void stop_file_transmission();

            /** @brief called to activate receive mode

                This method doen't do anything active, it will only set the receive mode for this connection
                If you don't call this, all received data is discarded. If called, the data B3 stream received
                is written to this file w/o changes. So it's in the native format given by CAPI (i.e. inserved A-Law
                for speech, SFF for FaxG3).

                @param filename name of the file to which to save the incoming data
                @throw CapiWrongState Thrown if Connection isn't up completely (physical & logical)
                @throw CapiExternalError Thrown if file reception is already in progress or the file couldn't be opened
            */
            void start_file_reception(string filename) throw (CapiWrongState, CapiExternalError);

            /** @brief called to stop receive mode

                This closes the reception file and tells us to ignore further incoming B3 data.
            */
            void stop_file_reception();

            /** @brief Tells disconnectCall() method how to disconnect.
            */
00170             enum disconnect_mode_t {
00171                   ALL, ///< do the necessary steps to finish the call nicely (first logical, then physical)
00172                   PHYSICAL_ONLY, ///< quick'n'dirty disconnect (physical only, logical will auto-disconnect with protocol error)
00173                   LOGICAL_ONLY ///< only disconnect logical connection, physical will stay up
            };

            /** @brief Terminate this connection

                According to the current state and the given mode, the needed steps to disconnect will be executed.

                If you don't specify a mode, the connection will be completely cleared (first logical, then physical).

                It doesn't throw any error if you call it for an already cleared connection, so it's safe to call it more
                than one time.

                To reject a waiting call you haven't accepted earlier, use rejectWaiting(), not disconnectCall().

                Attention: Connection objects will not be deleted after the disconnection. You must delete the Connection
                object explicitly. The reason for this behavior is to allow you to get connection related information
                (like disconnect cause, ...) after the connection has cleared. See also CallInterface::callDisconnectedPhysical().

                @param disconnect_mode see description of disconnect_mode_t
                @throw CapiMsgError Thrown by Capi::disconnect_b3_req() or Capi::disconnect_req(). See there.
            */
            void disconnectCall(disconnect_mode_t disconnect_mode=ALL) throw (CapiMsgError);

            /** @brief Accept a waiting incoming call.

                Will update the saved service to the desired_service. Calls Capi::connect_resp().

                @param desired_service to determine with which service we should connect (e.g. VOICE or FAXG3)
                @param faxStationID my fax station ID - only needed in FAXG3 mode
                @param faxHeadline my fax headline - only needed in FAXG3 mode, encoded in ISO8859-1
                @throw CapiWrongState Thrown if call is not in necessary state (waiting for acception or rejection)
                @throw CapiExternalError Thrown by buildBconfiguration and if method is called with an outgoing call
                @throw CapiMsgError Thrown by Capi::connect_resp(). See there.
            */
            void connectWaiting(service_t desired_service, string faxStationID="", string faxHeadline="")  throw (CapiWrongState,CapiExternalError,CapiMsgError);

            /** @brief Reject a waiting incoming call

                Only use for waiting calls - to disconnect an already connected call use disconnectCall().

                @param reject reject cause, see CAPI spec ch 5.6 for details
                @throw CapiWrongState Thrown if call is not in necessary state (waiting for acception or rejection)
                @throw CapiExternalError Thrown if function called with wrong parameters
                @throw CapiMsgError Thrown by Capi::connect_resp(). See there.
            */
            void rejectWaiting(_cword reject) throw (CapiWrongState, CapiMsgError, CapiExternalError);

            /** @brief disable timeout for a pending call (i.e. send ALERT)

                Normally, a call is indicated from ISDN and timeouts after 4 (or 8) seconds if no answer is received.
                If you want to accept the call, not immediately, but some secods later, you must call acceptWaiting().
                This tells ISDN that we will accept it some times later (i.e. send ALERT_REQ)

                @throw CapiWrongState Thrown if call is not in necessary state (waiting for acception or rejection)
                @throw CapiMsgError Thrown by Capi::calert_req(). See there.
            */
            void acceptWaiting() throw (CapiMsgError, CapiWrongState);

            /** @brief Enable indication for DTMF signals

                Normally you get no indication when the CAPI recognizes a DTMF signal. With enableDTMF()
                you enable these indications. DTMF signals will be saved locally and signalled by CallInterface::gotDTMF().
                You can read the saved DTMF signales with getDTMF().

                @throw CapiWrongState Thrown if Connection isn't up completely (physical & logical)
                @throw CapiMsgError Thrown by Capi::facility_req(). See there.
            */
            void enableDTMF() throw (CapiWrongState, CapiMsgError);

            /** @brief Disable indication for DTMF signals

                @throw CapiWrongState Thrown if Connection isn't up completely (physical & logical)
                @throw CapiMsgError Thrown by Capi::facility_req(). See there.
            */
            void disableDTMF() throw (CapiWrongState, CapiMsgError);

            /** @brief read the saved DTMF characters

                DTMF characters will only be saved if you called enableDTMF() before.

                @return string containing received DTMF coded as characters ('0'..'9','A'..'D','*','#','X'=fax CNG,'Y'=fax CED)
            */
            string getDTMF();

            /** @brief Delete the saved DTMF characters
            */
            void clearDTMF();

            /** @brief Return number of the called party (the source of the call)

                @return CalledPartyNumber
            */
            string getCalledPartyNumber();

            /** @brief Return number of calling party (the destination of the call)

                @return callingPartyNumber
            */
            string getCallingPartyNumber();

            /** @brief Return currently used service mode

                @return service as described in Connection::service_t
            */
            service_t getService();

            /** @brief Return disconnection cause given by the CAPI

                0x33xx=see CAPI spec
                0x34xx=ISDN cause, for coding of xx see ETS 300102-1.

                @return Returns the disconnection cause, 0=no cause available
            */
            _cword getCause();

            /** @brief Return disconnection cause given by the CAPI

                0x33xx=see CAPI spec
                0x34xx=ISDN cause, for coding of xx see ETS 300102-1.

                @return Returns the disconnection cause of Layer3, 0=no cause available or normal clearing
            */
            _cword getCauseB3();


            /**  @brief Represents the current connection state in an easy way
            */
00300             enum connection_state_t {
00301                   DOWN, ///< this means the connection is completely down, i.e. physical and logical down
00302                   WAITING, ///< this means an incoming connection is waiting for our decision (accept or reject)
00303                   UP, ///< this means the connection is completely up, i.e. physical and logical up
00304                   OTHER_STATE ///< connection is in some other state (e.g. physical up, logical down, ...)
            };

            /** @brief Return the connection state

                @return current connection state as specified in Connection::connection_state_t
            */
            connection_state_t getState();

            /** @brief several parameters describing fax protocol details for incoming faxes

                Information is available when B3 connection is established (after CallInterface::callConnected()
                was called) unless noted otherwise.
            */
00318             struct fax_info_t {
00319                   int rate; ///< bit rate used at connect or at disconnect (depends when you ask for it)
00320                   bool hiRes; ///< fax is transferred in high resolution
00321                   unsigned short format; ///< 0=SFF,black&white, 1=colorJPEG
00322                   int pages; ///< number of transmitted pages (only available after disconnection!)
00323                   std::string stationID; ///< ID of the sending station
            };

            /** @brief Return fax information

                @return several informations about a fax transfer as specified in Connection::fax_info_t, NULL when not available
            */
            fax_info_t* getFaxInfo();

            /** @brief Output error message

                This is intended for external use if some other part of the application wants to make a error-log entry.
                For internal use in this class just output to the stream "error".

                @param message the message to print
            */
            void errorMessage(string message);


            /** @brief Output debug message

                This is intended for external use if some other part of the application wants to make a log entry.
                For internal use in this class just output to the stream "debug".

                @param message the message to print
                @param level the debug level of the given message (see capisuite.conf for explanation)
            */
            void debugMessage(string message, unsigned short level);

      protected:

            /** @brief Constructor. Create an object for an incoming call

                This one is used by Capi when an incoming connection triggers the automatic creation of a Connection object, i.e.
                when we receive a CONNECT_IND message.

                It only extracts some data (numbers, services, etc.) from the message and saves it in private attributes.
                The answer to CONNECT_IND (i.e. CONNECT_RESP) is given later by the Connection object.

                @param message the received CONNECT_IND message
                @param capi pointer to the Capi Object
                @param DDILength set the length of DDI extension numbers (0=default means disable DDI)
                @param DDIBaseLength the length of the base number of the PtP interface
                @param DDIStopNumbers a vector of strings listing complete DDI extension numbers which are shorter than DDILength 
            */
            Connection (_cmsg& message, Capi *capi, unsigned short DDILength=0, unsigned short DDIBaseLength=0, std::vector<std::string> DDIStopNumbers=std::vector<std::string>());

            /********************************************************************************/
            /*        methods handling CAPI messages - called by the Capi class           */
            /********************************************************************************/

            /*************************** INDICATIONS ****************************************/

            /** @brief Called when we get CONNECT_ACTIVE_IND from CAPI

                This method will also send a response to Capi and initiate
                a B3 connection if necessary.

                @param message the received CONNECT_ACTIVE_IND message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiMsgError Thrown by Capi::connect_b3_req
            */
            void connect_active_ind(_cmsg& message) throw (CapiWrongState, CapiMsgError);

            /** @brief called when we get CONNECT_B3_IND from CAPI

                This method will also send a response to Capi.

                @param message the received CONNECT_B3_IND message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
                @throw CapiMsgError Thrown by Capi::connect_b3_resp()
            */
            void connect_b3_ind(_cmsg& message) throw (CapiWrongState, CapiMsgError);

            /** @brief called when we get CONNECT_B3_ACTIVE_IND from CAPI

                This method will also send a response to Capi and call CallInterface::callConnected().

                @param message the received CONNECT_B3_ACTIVE_IND message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
                @throw CapiExternalError Thrown if no CallInterface is registered
                @throw CapiError Thrown if invalid message was received
            */
            void connect_b3_active_ind(_cmsg& message) throw (CapiError,CapiWrongState,CapiExternalError);

            /** @brief called when we get DATA_B3_IND from CAPI

                This method will also save the received data, send a response to Capi and call CallInterface::dataIn().

                @param message the received DATA_B3_IND message
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
                @throw CapiMsgError Thrown by Capi::data_b3_resp()
            */
            void data_b3_ind(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /** @brief called when we get FACILITY_IND from CAPI with facility selector saying it's DTMF

                This method will save the received DTMF to received_dtmf, send a response to Capi and call
                CallInterface::gotDTMF().

                @param message the received FACILITY_IND message
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
            */
            void facility_ind_DTMF(_cmsg& message) throw (CapiError,CapiWrongState);

            /** @brief called when we get INFO_IND from CAPI with Info number saying it's ALERTING

                This method will call CallInterface::alerting().

                @param message the received INFO_IND message
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
            */
            void info_ind_alerting(_cmsg& message) throw (CapiError,CapiWrongState);

            /** @brief called when we get INFO_IND from CAPI with Info number saying it's ALERTING

                This method will understand additional Called Party Number Info Elements to get the DDI
                (necessary for getting the whole number in PtP configuration as the DDI is signalled
                *after* CONNECT_IND.

                @param message the received INFO_IND message
                @return true if the CalledPartyNumber is complete (DDI length fulfilled or stop_number found)
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
            */
            bool info_ind_called_party_nr(_cmsg& message) throw (CapiError,CapiWrongState);

            /** @brief called when we get DISCONNECT_B3_IND from CAPI

                This method will also send a response to Capi and stop_file_transmission and stop_file_reception().
                It will call CallInterface::callDisconnectedLogical() and initiate termination of physical connection.

                @param message the received DISCONNECT_B3_IND message
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
            */
            void disconnect_b3_ind(_cmsg& message) throw (CapiError,CapiWrongState);

            /** @brief called when we get DISCONNECT_IND from CAPI

                This method will also send a response to Capi and call CallInterface::callDisconnectedPhysical().

                @param message the received DISCONNECT_IND message
                @throw CapiError Thrown when an invalid message is received
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state or plci_state)
                @throw CapiMsgError Thrown by Capi::disconnect_resp()
            */
            void disconnect_ind(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /*************************** CONFIRMATIONS **************************************/

            /** @brief called when we get CONNECT_CONF from CAPI

                @param message the received CONNECT_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
            */
            void connect_conf(_cmsg& message) throw (CapiWrongState, CapiMsgError);

            /** @brief called when we get CONNECT_B3_CONF from CAPI

                @param message the received CONNECT_B3_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong ncci_state)
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
            */
            void connect_b3_conf(_cmsg& message) throw (CapiWrongState, CapiMsgError);

            /** @brief called when we get SELECT_B_PROTOCOL_CONF from CAPI

                @param message the received SELECT_B_PROTOCOL_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiError Thrown when an invalid message is received
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
            */
            void select_b_protocol_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /** @brief called when we get ALERT_CONF from CAPI

                @param message the received ALERT_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiError Thrown when an invalid message is received
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
            */
            void alert_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /** @brief called when we get DATA_B3_CONF from CAPI

               This will trigger new send_block().

                @param message the received DATA_B3_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
                @throw CapiError Thrown when an invalid message is received and by Connection::send_block()
                @throw CapiExternalError Thrown by Connection::send_block()
            */
            void data_b3_conf(_cmsg& message) throw (CapiError,CapiWrongState, CapiMsgError, CapiExternalError);

            /** @brief called when we get FACILITY_CONF from CAPI with facility selector saying it's DTMF

                @param message the received FACILITY_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiError Thrown when an invalid message is received
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
            */
            void facility_conf_DTMF(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /** @brief called when we get DISCONNECT_B3_CONF from CAPI

                @param message the received DISCONNECT_B3_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
                @throw CapiError Thrown when an invalid message is received
            */
            void disconnect_b3_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /** @brief called when we get DISCONNECT_CONF from CAPI

                @param message the received DISCONNECT_CONF message
                @throw CapiWrongState Thrown when the message is received unexpected (i.e. in a wrong plci_state)
                @throw CapiMsgError Thrown if the info InfoElement indicates an error
                @throw CapiError Thrown when an invalid message is received
            */
            void disconnect_conf(_cmsg& message) throw (CapiError,CapiWrongState,CapiMsgError);

            /********************************************************************************/
            /*                           internal methods                           */
            /********************************************************************************/

            /** @brief return a prefix containing this pointer and date for log messages

                      @return constructed prefix as stringstream
            */
            string prefix();

            /** @brief format the CallingPartyNr or CalledPartyNr to readable string

                @param capi_input the CallingPartyNumber resp. CalledPartyNumber struct
                    @param isCallingNr true = CallingPartyNr / false = CalledPartyNr
                      @return the number formatted as string
            */
            string getNumber (_cstruct capi_input, bool isCallingNr);

            /** @brief called to send next block (2048 bytes) of file

                The transmission will be controlled automatically by Connection, so you don't
                need to call this method directly. send_block() will automatically send as much
                packets as the configured window size (conf_send_buffers) permits.

                Will call CallInterface::transmissionComplete() if the file was transferred completely.

                @throw CapiWrongState Thrown when the the connection is not up completely (physical & logical)
                @throw CapiExternalError Thrown when no CallInterface is registered
                @throw CapiError Thrown on some internal errors
                @throw CapiMsgError Thrown by Capi::data_b3_req().
            */
            void send_block() throw (CapiError,CapiWrongState,CapiExternalError,CapiMsgError);

            /** @brief called to build the B Configuration info elements out of given service

                This is a convenience function to do the quite annoying enconding stuff for the
                6 B configuration parameters.

                It also checks if the requested controller really has this abilities and throws
                an exception otherwise.

                @param controller number of controller to use - necessary to check available services
                @param service value indicating service to be used as described in service_t
                @param faxStationID my fax station ID
                @param faxHeadline the fax headline, encoded in ISO8859-1
                @param B1proto return value: B1protocol value for CAPI, see CAPI spec
                @param B2proto return value: B2protocol value for CAPI, see CAPI spec
                @param B3proto return value: B3protocol value for CAPI, see CAPI spec
                @param B1config return value: B1configuration element for CAPI, see CAPI spec
                @param B2config return value: B2configuration element for CAPI, see CAPI spec
                @param B3config return value: B3configuration element for CAPI, see CAPI spec
                @throw CapiExternalError thrown when the ISDN controller doesn't support the wanted service
            */
            void buildBconfiguration(_cdword controller, service_t service, string faxStationID, string faxHeadline, _cword& B1proto, _cword& B2proto, _cword& B3proto, _cstruct& B1config, _cstruct& B2config, _cstruct& B3config) throw (CapiExternalError);

            /** @brief convert a String from ISO8859-1 to CP437 (IBM PC-DOS charset)

                Unfortunately, some CAPI drivers expect the fax headline to be given in the IBM PC-DOS
                charset. This method can convert the string from the normal ISO8859-1 representation
                to this charset.

                @param text the string to convert
                @throw CapiExternalError thrown when the iconv* functions report an error (other than conversion not supported)
            */
            void convertToCP437(string &text);

            /********************************************************************************/
            /*                           attributes                           */
            /********************************************************************************/

            /** @brief State for the physical connection as defined in the CAPI spec.

                For complete diagrams and state definition see CAPI 2.0 spec, chapter 7.2

            */
00625             enum plci_state_t {
00626                   P0,   ///< default state. no connection.
00627                   P01,  ///< CONNECT_REQ sent, waiting for CONNECT_CONF
00628                   P1,   ///< CONNECT_CONF received, waiting for CONNECT_ACTIVE_IND
00629                   P2,   ///< CONNECT_IND received, no CONNECT_RESP given yet
00630                   P3,   ///< only needed for handsets
00631                   P4,   ///< CONNECT_RESP sent, waiting for CONNECT_ACTIVE_IND
00632                   P5,   ///< DISCONNECT_REQ sent, waiting for DISCONNECT_IND
00633                   P6,   ///< DISCONNECT_IND received, DISCONNECT_RESP not sent yet
00634                   PACT  ///< active physical connection
            } plci_state;

            /** @brief State for logical connection as defined in the CAPI spec

                For complete diagrams and state definition see CAPI 2.0 spec, chapter 7.2
            */
00641             enum ncci_state_t {
00642                   N0,   ///< default state, no connection.
00643                   N01,  ///< CONNECT_B3_REQ sent, waiting for CONNECT_B3_CONF
00644                   N1,   ///< CONNECT_B3_IND received, CONNECT_B3_RESP not sent yet
00645                   N2,   ///< CONNECT_B3_CONF received / CONNECT_B3_RESP sent, waiting for CONNECT_B3_ACTIVE_IND
00646                   N3,   ///< RESET_B3_REQ sent, waiting for RESET_B3_IND
00647                   N4,   ///< DISCONNECT_B3_REQ sent, waiting for DISCONNECT_B3_IND
00648                   N5,   ///< DISCONNECT_B3_IND received
00649                   NACT  ///< active logical connection
            } ncci_state;

00652             _cdword plci;    ///< CAPI id for call
00653             _cdword ncci;    ///< id for logical connection

00655             service_t service; ///< as described in Connection::service_t, set to the last known service (either got from ISDN or set explicitly)

00657             _cword connect_ind_msg_nr; ///< this is needed as connect_resp is given in another function as connect_ind

00659             _cword disconnect_cause, ///< the disconnect cause as given by the CAPI in DISCONNECT_IND
                  disconnect_cause_b3; ///< the disconnect cause as given by the CAPI in DISCONNECT_B3_IND

00662             string call_from; ///< CallingPartyNumber, formatted as string with leading '0' or '+' prefix
00663             string call_to;   ///< CalledPartyNumber, formatted as string

00665             string received_dtmf; ///< accumulates the received DTMF data, see readDTMF()

00667             bool keepPhysicalConnection, ///< set to true to disable auto-physical disconnect after logical disconnect for one time
                  our_call; ///< set to true if we initiated the call (needed to know as some messages must be sent if we initiated the call)

00670             CallInterface *call_if; ///< pointer to the object implementing CallInterface
00671             Capi *capi; ///< pointer to the Capi object

00673             pthread_mutex_t send_mutex,  ///< to realize critical sections in transmission code
                        receive_mutex; ///< to realize critical sections in reception code

00676             ofstream *file_for_reception; ///< NULL if no file is received, pointer to the file otherwise
00677             ifstream *file_to_send;  ///< NULL if no file is sent, pointer to the file otherwise
                                     
00679             ostream &debug, ///< debug stream
                    &error; ///< stream for error messages 
00681             unsigned short debug_level; ///< debug level

            /** @brief ring buffer for sending

                7 buffers a 2048 byte mark the maximal window size handled by CAPI

                is empty: buffer_used==0 / is full: buffers_used==7
                to forget item: buffers_used--; buffer_start++;
                to remember item: send_buffer[ (buffer_start+buffers_used)%8 ]=item; buffers_used++
            */
00691             char send_buffer[7][2048];

00693             unsigned short buffer_start, ///< holds the index for the first buffer currently used
                  buffers_used; ///< holds the number of currently used buffers

00696             fax_info_t* fax_info; ///< holds some data about fax connections

00698             unsigned short DDILength; ///< the length of DDI extension numbers. 0 means DDI disabled
00699             unsigned short DDIBaseLength; ///< the length of the base number for a PtP interface
00700             vector<string> DDIStopNumbers; ///< list of complete DDI extensions shorter than DDILength
};

#endif

/*  History

$Log: connection.h,v $
Revision 1.6.2.4  2003/11/11 21:05:41  gernot
- fix typo in comment

Revision 1.6.2.3  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.6.2.2  2003/11/01 22:59:33  gernot
- read CalledPartyNr InfoElements

Revision 1.6.2.1  2003/10/26 16:51:55  gernot
- begin implementation of DDI, get DDI Info Elements

Revision 1.6  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.5  2003/05/25 13:38:30  gernot
- support reception of color fax documents

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

Revision 1.3  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.2  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.1.1.1  2003/02/19 08:19:53  gernot
initial checkin of 0.4

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

Revision 1.29.2.1  2003/02/10 14:07:54  ghillie
- use pthread_mutex_* instead of CommonC++ Semaphore

Revision 1.29  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.28  2002/12/16 13:13:47  ghillie
- added getCauseB3 to return B3 cause

Revision 1.27  2002/12/13 11:46:59  ghillie
- added attribute our_call to differ outgoing and incoming calls

Revision 1.26  2002/12/11 13:39:05  ghillie
- added support for PHYSICAL_ONLY disconnect in disconnectCall()

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

Revision 1.24  2002/12/09 15:42:24  ghillie
- save debug and error stream in own attributes

Revision 1.23  2002/12/06 15:25:47  ghillie
- new return value for getState(): WAITING

Revision 1.22  2002/12/06 13:07:36  ghillie
- update docs because application is now responsible to delete
  Connection object
- new methods getCause() and getState()

Revision 1.21  2002/12/05 15:05:12  ghillie
- moved constructor for incoming calls to "private:"

Revision 1.20  2002/12/02 12:31:36  ghillie
renamed Connection::SPEECH to Connection::VOICE

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

Revision 1.18  2002/11/27 16:03:20  ghillie
updated comments for doxygen

Revision 1.17  2002/11/25 11:51:54  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.16  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.15  2002/11/21 15:30:28  ghillie
- added new method Connection::acceptWaiting() - sends ALERT_REQ
- updated description of Connection::connectWaiting()

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

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

Revision 1.12  2002/11/18 12:24:33  ghillie
- changed disconnectCall() so that it doesn't throw exceptions any more,
  so that we can call it in any state

Revision 1.11  2002/11/17 14:40:55  ghillie
added isUp()

Revision 1.10  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.9  2002/11/15 13:49:10  ghillie
fix: callmodule wasn't aborted when call was only connected/disconnected physically

Revision 1.8  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.7  2002/11/13 08:34:54  ghillie
moved history to the bottom

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

Revision 1.5  2002/11/08 07:57:07  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.4  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.3  2002/10/30 14:29:25  ghillie
added getCIPvalue

Revision 1.2  2002/10/29 14:27:42  ghillie
added stop_file_*, added semaphores

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

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

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

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

Revision 1.7  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.6  2002/10/01 09:02:04  gernot
changes for compilation with gcc3.2

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

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

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

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

*/

Generated by  Doxygen 1.6.0   Back to index