]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Added mod_khomp Endpoint.
authorGeovani Ricardo Wiedenhoft <grw@geovani.(none)>
Mon, 18 Oct 2010 18:17:43 +0000 (16:17 -0200)
committerGeovani Ricardo Wiedenhoft <grw@geovani.(none)>
Mon, 18 Oct 2010 18:17:43 +0000 (16:17 -0200)
This module has been developed to make a nice,
affordable brazilian board called Khomp
(http://www.khomp.com.br) compatible with FreeSWITCH.

Supported boards:
- FXS
- FXO
- E1
- GSM (boards and usb devices)
- Passive record
- kommuter

96 files changed:
src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml [new file with mode: 0644]
src/mod/endpoints/mod_khomp/Makefile [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/atomic.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/config_commons.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/config_options.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/config_options.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/option.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/option.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/section.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/configurator/section.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/flagger.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/format.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/format.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/function.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/initializer.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/k3lapi.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/k3lapi.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/k3lutil.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/k3lutil.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/logger.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/noncopyable.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/refcounter.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/regex.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/regex.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/saved_condition.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/saved_condition.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/scoped_lock.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/simple_lock.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/strings.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/strings.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/tagged_union.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/thread.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/timer.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/timer.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/types.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/variant.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/verbose.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/commons/verbose.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/Manual.html [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/Manual.pdf [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/README.html [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/README.pdf [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/README_en.html [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/README_en.pdf [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/User_Guide.html [new file with mode: 0644]
src/mod/endpoints/mod_khomp/docs/User_Guide.pdf [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/applications.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/cli.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/defs.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/frame.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/globals.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/k3l.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/khomp_pvt.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/khomp_pvt_fxo.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/khomp_pvt_gsm.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/khomp_pvt_kxe1.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/khomp_pvt_passive.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/lock.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/logger.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/opt.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/revision.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/spec.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/include/utils.h [new file with mode: 0644]
src/mod/endpoints/mod_khomp/install.sh [new file with mode: 0755]
src/mod/endpoints/mod_khomp/mod_khomp.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/applications.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/cli.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/frame.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/globals.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/khomp_pvt_fxo.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/khomp_pvt_gsm.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/khomp_pvt_kxe1.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/khomp_pvt_passive.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/lock.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/logger.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/opt.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/spec.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/src/utils.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/config_defaults.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/config_defaults.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/klog-config.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/klog-config.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/klog-options.cpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/support/klog-options.hpp [new file with mode: 0644]
src/mod/endpoints/mod_khomp/tools/getversion.sh [new file with mode: 0755]

diff --git a/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml b/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml
new file mode 100644 (file)
index 0000000..7255fb8
--- /dev/null
@@ -0,0 +1,549 @@
+<configuration name="khomp.conf" description="Khomp Configuration">
+<!-- Config for all boards -->
+<settings>
+
+<!--
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;; This is the configuration file for the Khomp ;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Endpoint 1.0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+-->
+<channels>
+<!-- Section for main configurations about channels. -->
+
+<!--
+Enable/disable generalized echo cancellation in the channel, for calls
+passing inside FreeSWITCH (disabled for bridged calls).
+(default = yes)
+
+<param name="echo-canceller" value="yes"/>
+-->
+
+<!--
+Enable/disable AGC (auto gain control). Should be used carefully, as it
+can make line noise really loud.
+(default = yes)
+
+<param name="auto-gain-control" value="yes"/>
+-->
+
+<!--
+Enable/disable sending DTMFs out-band as a way to pass detected DTMFs to
+FreeSWITCH. Needed if FreeSWITCH generates digits for us in bridge application 
+or is being used for IVR ("URA", in pt_BR).
+(default = yes)
+
+<param name="out-of-band-dtmfs" value="yes"/>
+-->
+
+<!--
+Enable/disable DTMF suppression delay. WARNING: if you disable this, DTMFs
+will not be suppressed anymore! You should only use this option if
+"out-of-band-dtmfs" is "no".
+(default = yes)
+
+<param name="suppression-delay" value="yes"/>
+-->
+
+<!--
+Adjust connection automagically if a FAX tone is detected.
+(default = yes)
+
+<param name="auto-fax-adjustment" value="yes"/>
+-->
+
+<!--
+Time (is seconds) since connection, when we may detect FAX tone and perform
+automagical adjustment. After this, FAX tone detection is ignored.
+Possible values: 0 - 9999
+(default = 30).
+
+<param name="fax-adjustment-timeout" value="30"/>
+-->
+
+<!--
+Enable/disable pulse detection (reported as DTMF digits).
+(default = yes)
+
+<param name="pulse-forwarding" value="yes"/>
+-->
+
+<!--
+Enable correct standard following for R2/MFC protocol. Disabled by default,
+as using FreeSWITCH behind a PBX may timeout all outgoing calls without this.
+However, you can set this to "yes" if FreeSWITCH is directly connected to a
+CO (central office) or to a fast signaling PBX, and have a correct
+behaviour for condition obtaining/reporting.
+(default = no)
+
+<param name="r2-strict-behaviour" value="no"/>
+-->
+
+<!--
+Set the delay (in ms) after sending ringback condition where audio stream
+should be opened for the channel. Limited to 25ms min, 500ms max.
+(default = 250)
+
+<param name="r2-preconnect-wait" value="250"/>
+-->
+
+<!--
+Enable/disable native bridge mode (known in pt_BR as "trombone") for calls
+in the Khomp channel, passing the audio inside the board when both channels
+(incoming and outgoing) are of type Khomp. This reduces the echo and the
+audio delay, and frees the host from most audio processing.
+(default = yes)
+
+<param name="native-bridge" value="yes"/>
+-->
+
+<!--
+Defines the incoming context for calls on E1 channels. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD-LL)
+
+<param name="context-digital" value="khomp-DD-LL"/>
+-->
+
+<!--
+Defines the incoming context for calls on FXS channels. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD-CC)
+
+<param name="context-fxs" value="khomp-DD-CC"/>
+-->
+
+<!--
+Defines the "alternative" context for calls on FXS channels, which will be
+checked if the main context does not match for a call. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD)
+
+<param name="context-fxs-alt" value="khomp-DD"/>
+-->
+
+<!--
+Defines the incoming context for calls on FXO channels. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD-CC)
+
+<param name="context-fxo" value="khomp-DD-CC"/>
+-->
+
+<!--
+Defines the "alternative" context for calls on FXO channels, which will be
+checked if the main context does not match for a call. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD)
+
+<param name="context-fxo-alt" value="khomp-DD"/>
+-->
+
+<!--
+Defines the incoming context for calls on GSM channels. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD-CC)
+
+<param name="context-gsm-call" value="khomp-DD-CC"/>
+-->
+
+<!--
+Defines the "alternative" context for calls on GSM channels, which will be
+checked if the main context does not match for a call. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-DD)
+
+<param name="context-gsm-call-alt" value="khomp-DD"/>
+-->
+
+<!--
+Defines the incoming context for messages on GSM channels. Some wildcards are
+accepted, and described in the bottom of this file.
+(default = khomp-sms-DD-CC)
+
+<param name="context-gsm-sms" value="khomp-sms-DD-CC"/>
+-->
+
+<!--
+Defines the incoming context for calls on Passive Record boards (KPR). Some 
+wildcards are accepted, and described in the bottom of this file.
+(default = khomp-DD-CC)
+
+<param name="context-pr" value="khomp-DD-CC"/>
+-->
+
+<!--
+Set the logging of messages to console. Possible values (to set more than one,
+separate the values with comma):
+
+ errors    - Error messages, when something goes really wrong.
+ warnings  - Warnings, used when something might not be going as expected.
+ messages  - Generic messages, used to indicate some information.
+ events    - Show received K3L events as console messages.
+ commands  - Show sent K3L commands as console messages.
+ audio     - Enable messages for K3L audio events (very verbose!).
+ modem     - Enable messages for data received from KGSM modems.
+ link      - Enable logging of link status changes.
+ standard  - Special, enable default messages (RECOMMENDED).
+ all       - Special, enable ALL messages (should not be used naively).
+
+(default = standard)
+
+<param name="log-to-console" value="standard"/>
+-->
+
+<!--
+Set the logging of messages to disk. Possible values (to set more than one,
+separate the values with comma):
+
+ errors    - Error messages, when something goes really wrong.
+ warnings  - Warnings, used when something might not be going as expected.
+ messages  - Generic messages, used to indicate some information.
+ events    - Record received K3L events as log messages.
+ commands  - Record sent K3L commands as log messages.
+ audio     - Enable messages for K3L audio events (very verbose!).
+ modem     - Enable messages for data received from KGSM modems.
+ link      - Enable logging of link status changes.
+ functions - Enable debugging for functions. Should not be used naively!).
+ threads   - Enable debugging for threads. Should not be used naively!).
+ locks     - Enable debugging for locks. Should not be used naively!).
+ streams   - Enable debugging for streams. Should not be used naively!).
+ standard  - Special, enable default messages (RECOMMENDED).
+ debugging - Special, enable debug messages (should not be used naively).
+ all       - Special, enable ALL messages (DO NOT USE THIS!).
+
+(default = standard)
+
+<param name="log-to-disk" value="standard"/>
+-->
+
+<!--
+Set the low level tracing. DO NOT USE THIS UNLESS YOU WERE ADVISED TO DO SO.
+Possible values (to set more than one, separate the values with comma):
+
+k3l  - Enable the low level tracing of board's API. 
+        If you are using 'kserver', this option will take no effect. For
+        the k3l tracing to proceed, you will need to (re)start kserver 
+        with 'debug' option. E.g. '#> kserver start -debug'.
+rdsi - Enable ISDN low level debugging.
+r2   - Enable r2 protocol low level debugging.
+
+(default = <empty>)
+
+<param name="trace" value=""/>
+-->
+
+<!--
+Set output volume level. Possible values:
+
+  * '+ N' = increase N times;
+  * '- N' = decrease N times.
+  *   '0' = leave default.
+
+(default = 0)
+
+<param name="output-volume" value="0"/>
+-->
+
+<!--
+Set input volume level. Can only be used if AGC (and not pulse detection)
+is enabled on the board configuration. Possible values:
+
+  * '+ N' = increase N times;
+  * '- N' = decrease N times.
+  *   '0' = leave default.
+
+(default = 0)
+
+<param name="input-volume" value="0"/>
+-->
+
+<!--
+Sets the default AMA flags, affecting the categorization of entries in 
+the call detail records.
+(default = default)
+
+<param name="amaflags" value="default"/>
+-->
+
+<!--
+Sets the account code for calls placed on the channel. The account code may
+be any alphanumeric string
+(default = KhompBoard)
+
+<param name="accountcode" value="KhompBoard"/>
+-->
+
+<!--
+Set the language of the channel (useful for selecting audio messages of a
+specific language on answer).
+(default = <empty>)
+
+<param name="language" value="pt_BR"/>
+-->
+
+<!--
+Set the music on hold class of the channel (useful for selecting a group of
+songs to play on hold).
+(default = default)
+
+<param name="mohclass" value="default"/>
+-->
+
+<!--
+Sets the global orig (CALLERID) base for FXS boards. This number is added
+to a sequencial number, which is incremented for each FXS board and FXS
+channel in the system.
+
+For more example of how to use this option, see channel README file,
+section 'Opcoes do application Bridge', item '<action application="bridge" data="Khomp/r304" />'.
+(default = 0)
+
+<param name="fxs-global-orig" value="0200"/>
+-->
+
+<!--
+Sets the numbers (separated by comma) in which the 'pbx-dialtone' from
+FXS boards will be changed to 'co-dialtone' (public tone), when they are
+pressed.
+(default = <empty>)
+
+<param name="fxs-co-dialtone" value="0,90"/>
+-->
+
+<!--
+Enable or disable sending number of A throught BINA DTMF signalization to
+a FXS branch.
+(default = yes)
+
+<param name="fxs-bina" value="yes"/>
+-->
+
+<!--
+Enable/disable using CTbus for Khomp CTI boards in native bridge.
+(WARNING: just used for internal testings!)
+(default = no)
+
+<param name="has-ctbus" value="no"/>
+-->
+
+<!--
+This is the delay time to really disconnect a channel after the disconnect
+event arrive. If a connect event comes up in this interval, then the 
+disconnection is ignored and the call keeps going on. Values in ms.
+(default = 0)
+
+<param name="disconnect-delay" value="0"/>
+-->
+
+<!--
+This timer controls the delay associated with ringback generation in the
+Khomp channel, when the other side *does not send audio* - in other words,
+this is used when calling peers located at VoIP channels.
+Values are in milliseconds.
+(default = 1500)
+
+<param name="delay-ringback-co" value="1500"/>
+-->
+
+<!--
+This timer controls the delay associated with ringback generation in the
+Khomp channel when the other side report a continuous stream of audio in
+silence - in other words, this is used when the audio is present but does
+not have any tone. Values are in milliseconds.
+(default = 2500)
+
+<param name="delay-ringback-pbx" value="2500"/>
+-->
+
+<!--
+Defines if the channel should optimize audio delay by droping longstanding
+packets from audio buffer. This guarantees the minimal audio delay for the
+user, and avoid delays associated with miscoded SIP clients. However,
+depending on the system's scheduling policy (some 2.6 kernel releases),
+this may result on excessive drop of packets, and audible audio skipping.
+This should not be changed naively.
+(default = no)
+
+<param name="optimize-audio-path" value="no"/>
+-->
+
+<!--
+Defines if the channel should ignore some uncommon DTMF digits detected by
+the board (A, B, C and D). This reduces the number of false positives which
+may happen sometimes, without affecting correctness on traditional
+scenarios. However, if you need to pass those digits througth the board,
+you may need to set this option to 'no'.
+(default = yes)
+
+<param name="ignore-letter-dtmfs" value="yes"/>
+-->
+
+<!--
+For KFXO series boards, defines if audio will be allowed being sent into
+outgoing calls before it has been connected.
+(default = yes)
+
+<param name="fxo-send-pre-audio" value="yes"/>
+-->
+
+<!--
+Defines the timeout, in seconds, between digits of a FXS board's extension.
+(default = 7)
+
+<param name="fxs-digit-timeout" value="7"/>
+-->
+
+<!--
+Enables/Disables the action of dropping collect calls. If enabled, all
+collect calls will be dropped no matter what KDropCollectCall is set to.
+(default = no)
+
+<param name="drop-collect-call" value="no"/>
+-->
+
+<!--
+Defines if the activation and deactivation of Kommuter is done automatically by the channel,
+or manually by the user. Possible values:
+
+auto     - Khomp channel driver starts all kommuter devices at initialization and stops them if the module is unloaded.
+manual   - The user must explicity call the CLI command < khomp kommuter on/off >, that starts or stops the kommuter devices connected to this machine.
+(default = auto)
+
+<param name="kommuter-activation" value="auto"/>
+-->
+
+<!--
+Defines the default value for the Kommuter watchdog in seconds.
+All kommuters conected to this machine will be initialized with this value,
+and will commute the links after reaching this time with no response of the channel.
+The minimum is 0 (will never commute the links), and maximum value is 255 seconds.
+(default = 10)
+
+<param name="kommuter-timeout" value="10"/>
+-->
+
+<!--
+When adjusted to some DTMF digit sequence, it will define those as the digits
+to be used to initialize a call transfer using PBX-to-PBX signaling.
+(default = empty)
+
+<param name="user-transfer-digits" value="#2"/>
+-->
+
+<!--
+;;;;;;;;;;;;;;;;;;;; CONTEXTS WILDCARDS ;;;;;;;;;;;;;;;;;;;;;;
+
+For incoming contexts, you can use the following wildcards:
+
+'DD' (device number): the sequence number of the board on the
+system (can be checked using "khomp summary", valid for all
+board models);
+
+'LL' (link number): the sequence number of link where the call
+has arrived on the board. valid only for E1 boards.
+
+'SSSS' (serial number): the serial number of the board (can
+be checked using "khomp summary", and it's valid for all
+board models);
+
+'CC' (channel number): the channel number on which the call
+or message has arrived (valid for FXO, FXS and GSM boards);
+
+'CCC' (channel number): same as above, but valid only for E1
+channels;
+-->
+
+</channels>
+
+<!--  Section for configuring allocation groups. -->
+<groups>
+<!--
+In this section, you should define options using the following syntax:
+
+<groupname> = <allocation-string>[:<context>]
+
+<param name="pstn" value="b0l0 + b1c38"/>
+<param name="pstn" value="b0l0 + b1c38:from-pstn"/>
+
+You may define your own groups. In the example above, the group 
+called pstn can be used in the bridge string as <action application="brigde" data="Khomp/Gpstn/..." />
+or <action application="brigde" data="Khomp/Gpstn/..." />. As a result, the allocation string will be
+replaced with the one associated with the group "pstn". This is the same
+of doing <action application="brigde" data="Khomp/b0l0 + b1c38/... />.
+In the second example, a context is also defined which can be used in
+extensions.conf for inbound calls on that allocation string's range.
+-->
+</groups>
+
+<!--
+Section for configuring cadences used on FXS boards and the whole
+channel (fast busy, ringback tones, etc).
+-->
+<cadences>
+<!--
+Default value for cadences. You may define your own cadences, and
+also use them in the bridge arguments as "cadence=your_cadence_name".
+
+ "0,0" means a continuous dialtone.
+
+ (default as defined below)
+ <param name="fast-busy" value="100,100" />
+ <param name="ringback" value="1000,4000" />
+ <param name="pbx-dialtone" value="1000,100" />
+ <param name="vm-dialtone " value="1000,100,100,100" />
+ <param name="co-dialtone " value="0,0" />
+-->
+</cadences>
+
+
+<!-- Section for configuring CALLERID's associated with FXS boards. -->
+<fxs-branches>
+<!--
+In this section, you should define options using the following syntax:
+
+'orig_prefix = serial number 0, serial number 1, ...'
+
+ex: <param name="880" value="111,222"/>
+
+In the example above (assuming KFXS-SPX boards 1234 and 4535), the
+branches will be numbered from 800 to 829 in board 1234, and from
+830 to 859 in board 4535.
+-->
+</fxs-branches>
+
+<!-- Section for configuring FXS hotlines. -->
+<fxs-hotlines>
+<!--
+In this section, you should define options using the following syntax:
+
+'orig_prefix = destination_number'
+
+ex: <param name="804" value="32332933" />
+
+In the example above, the branch numbered 804 will call the number
+3233-2933 (Khomp support number) every time the FXS branch goes off hook.
+-->
+</fxs-hotlines>
+
+<!-- Section for configuring specific options for FXS branches. -->
+<fxs-options>
+<!--
+In this section, you should define options using the following syntax:
+
+'orig_prefix = option1:value | option2:value | option3:value' ...
+
+ex: <param name="804" value="output-volume:+2' />
+
+In the example above, the branch numbered 804 will have specific
+configuration for default output volume set to +2.
+
+Possible values to options is:
+context, input-volume, output-volume language,
+mohclass, amaflags, accountcode, calleridnum, calleridname, mailbox.
+-->
+</fxs-options>
+
+</settings>
+</configuration>
diff --git a/src/mod/endpoints/mod_khomp/Makefile b/src/mod/endpoints/mod_khomp/Makefile
new file mode 100644 (file)
index 0000000..94923c7
--- /dev/null
@@ -0,0 +1,41 @@
+MODNAME := mod_khomp
+VERBOSE := 1
+
+ifeq ($(strip $(FREESWITCH_PATH)),)
+       BASE := ../../../../
+else
+       BASE := $(FREESWITCH_PATH)
+endif
+
+curr_dir := $(shell pwd)
+
+versions := -DFS_VERSION_MAJOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MAJOR" $(BASE)) -DFS_VERSION_MINOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MINOR" $(BASE)) -DFS_VERSION_MICRO=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MICRO" $(BASE))
+
+LOCAL_CFLAGS = -I./ -I./include -I./commons -I./support -D_REENTRANT -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DK3L_HOSTSYSTEM -DCOMMONS_LIBRARY_USING_FREESWITCH -g -ggdb #-DDEBUG_FLAGS
+LOCAL_CFLAGS += $(versions)
+
+LOCAL_LDFLAGS = -lk3l
+
+LOCAL_OBJS = ./commons/k3lapi.o ./commons/k3lutil.o ./commons/config_options.o ./commons/format.o ./commons/strings.o ./commons/ringbuffer.o ./commons/verbose.o ./commons/saved_condition.o ./commons/regex.o ./commons/timer.o ./commons/configurator/configfile.o ./commons/configurator/option.o ./commons/configurator/section.o ./commons/configurator/restriction.o
+LOCAL_OBJS += ./support/klog-config.o ./support/klog-options.o ./support/config_defaults.o
+LOCAL_OBJS += ./src/globals.o ./src/opt.o ./src/frame.o ./src/utils.o ./src/lock.o ./src/spec.o ./src/applications.o ./src/khomp_pvt_fxo.o ./src/khomp_pvt_gsm.o ./src/khomp_pvt_kxe1.o ./src/khomp_pvt_passive.o ./src/khomp_pvt.o ./src/logger.o ./src/cli.o
+
+conf_file_name := khomp.conf.xml
+conf_file_dir := $(curr_dir)/Install/files
+conf_file_dir_alt := $(curr_dir)/conf
+conf_file_install = $(sysconfdir)/autoload_configs
+
+include $(BASE)/build/modmake.rules
+
+depend_install:
+       @echo "Copy $(conf_file_name)"
+       @if test -d  $(conf_file_install) ; then \
+               if test -f $(conf_file_dir)/$(conf_file_name) ; then \
+                       cp $(conf_file_dir)/$(conf_file_name) $(conf_file_install)/$(conf_file_name).new ;\
+               else \
+                       cp $(conf_file_dir_alt)/$(conf_file_name) $(conf_file_install)/$(conf_file_name).new ;\
+               fi; \
+               if test ! -f "$(conf_file_install)/$(conf_file_name)" ; then \
+                       mv $(conf_file_install)/$(conf_file_name).new $(conf_file_install)/$(conf_file_name) ;\
+               fi; \
+       fi;
diff --git a/src/mod/endpoints/mod_khomp/commons/atomic.hpp b/src/mod/endpoints/mod_khomp/commons/atomic.hpp
new file mode 100644 (file)
index 0000000..daa598c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+    KHOMP generic endpoint/channel library.
+
+    This code was based on FreeBSD 7.X SVN (sys/i386/include/atomic.h),
+    with changes regarding optimizations and generalizations, and a
+    remake of the interface to fit use C++ features.
+
+    Code is distributed under original license.
+    Original copyright follows:
+
+ * Copyright (c) 1998 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+
+*/
+
+#ifndef _ATOMIC_HPP_
+#define _ATOMIC_HPP_
+
+namespace Atomic
+{
+    // Macros used to insert compare and exchange instructions easily into functions.
+
+    #define MAKE_CMPXCHG_FUNCTION(INS, PTR, EXP, VAL, TYPE)  \
+        PunnedType pexp; pexp.valtype = EXP;                 \
+        PunnedType pval; pval.valtype = VAL;                 \
+        TYPE vexp = *(pexp.podtype);                         \
+        TYPE vval = *(pval.podtype);                         \
+        TYPE res;                                            \
+        unsigned char chg = 0;                               \
+        asm volatile("lock;" INS "sete %1;"                  \
+        : "=a" (res),                           /* 0 */      \
+        "=q" (chg),                             /* 1 */      \
+        "=m" (*(unsigned char **)(PTR))         /* 2 */      \
+        : "r" (vval),                           /* 3 */      \
+        "a" (vexp),                             /* 4 */      \
+        "m" (*(unsigned char **)(PTR))          /* 5 */      \
+        : "memory");                                         \
+        *(pexp.podtype) = res;                               \
+        return (chg != 0 ? true : false);
+
+    #define MAKE_CMPXCHG8B_FUNCTION(PTR,EXP,VAL)           \
+        PunnedType pexp; pexp.valtype = EXP;               \
+        PunnedType pval; pval.valtype = VAL;               \
+        unsigned long long vexp = *(pexp.podtype);         \
+        unsigned long long vval = *(pval.podtype);         \
+        unsigned long long res = (unsigned long long)exp;  \
+        unsigned char chg = 0;                             \
+        asm volatile("lock; cmpxchg8b %2; sete %1;"        \
+        : "+A" (vexp),                    /* 0 (result) */ \
+        "=q" (chg)                        /* 1 */          \
+        : "m" (*(unsigned char**)(PTR)),  /* 2 */          \
+        "b" ((unsigned long)(vval)),                       \
+        "c" ((unsigned long)(vval >> 32)));                \
+        *(pexp.podtype) = vexp;                            \
+        return (chg != 0 ? true : false);
+
+    // Types used for making CMPXCHG instructions independent from base type.
+
+    template < typename ValType, typename PodType >
+    union PunnedTypeTemplate
+    {
+        ValType * valtype;
+        PodType * podtype;
+    };
+
+    template < int SizeOfType, typename ReturnType >
+    struct HelperCreateCAS;
+
+    template < typename ValType >
+    struct HelperCreateCAS<4, ValType>
+    {
+        #if !defined(__LP64__) && !defined(__LP64)
+            typedef unsigned long BaseType;
+        #else
+            typedef unsigned int  BaseType;
+        #endif
+
+        typedef PunnedTypeTemplate< ValType, BaseType > PunnedType;
+
+        inline static bool apply(volatile void *p, ValType * exp, ValType now)
+        {
+            #if !defined(__LP64__) && !defined(__LP64)
+                MAKE_CMPXCHG_FUNCTION("cmpxchgl %3,%5;", p, exp, &now, BaseType);
+            #else
+                MAKE_CMPXCHG_FUNCTION("cmpxchgl %k3,%5;", p, exp, &now, BaseType);
+            #endif
+        }
+    };
+
+    template < typename ValType >
+    struct HelperCreateCAS<8, ValType>
+    {
+        #if !defined(__LP64__) && !defined(__LP64)
+            typedef unsigned long long BaseType;
+        #else
+            typedef unsigned long BaseType;
+        #endif
+
+        typedef PunnedTypeTemplate< ValType, BaseType > PunnedType;
+
+        inline static volatile ValType apply(volatile void *p, ValType * exp, ValType now)
+        {
+            #if !defined(__LP64__) && !defined(__LP64)
+                MAKE_CMPXCHG8B_FUNCTION(p, exp, &now);
+            #else
+                MAKE_CMPXCHG_FUNCTION("cmpxchgq %3,%5;", p, exp, &now, BaseType);
+            #endif
+        }
+
+    };
+
+    // The CAS function itself.
+
+    template < typename ValType >
+    inline bool doCAS(volatile ValType * p, ValType * o, ValType n)
+    {
+        return HelperCreateCAS<sizeof(ValType), ValType>::apply(static_cast<volatile void *>(p), o, n);
+    };
+
+    template < typename ValType >
+    inline bool doCAS(volatile ValType * p, ValType o, ValType n)
+    {
+        return HelperCreateCAS<sizeof(ValType), ValType>::apply(static_cast<volatile void *>(p), &o, n);
+    };
+
+    #undef MAKE_CMPXCHG_32_FUNCTION
+    #undef MAKE_CMPXCHG_64_FUNCTION
+
+    #define MAKE_LOCKED_TEMPLATE(NAME)                                                     \
+    template < typename ValType > inline void do##NAME(volatile ValType * p, ValType v);   \
+    template < typename ValType > inline void do##NAME(volatile ValType * p);
+
+    #define MAKE_LOCKED_FUNCTION(NAME, TYPE, INS, CONS, VAL)                                                                                    \
+    template < > inline void do##NAME < TYPE > (volatile TYPE * p, TYPE v){   asm volatile("lock;" INS : "=m" (*p) : CONS (VAL), "m" (*p)); }   \
+    template < > inline void do##NAME < TYPE > (volatile TYPE * p)        {   asm volatile("lock;" INS : "=m" (*p) : CONS (1),   "m" (*p)); }
+
+    #define MAKE_LOCKED_FUNCTIONS(NAME, TYPE, INS, CONS, VAL)       \
+        MAKE_LOCKED_FUNCTION(NAME, TYPE, INS, CONS, VAL)            \
+        MAKE_LOCKED_FUNCTION(NAME, unsigned TYPE, INS, CONS, VAL)
+
+    MAKE_LOCKED_TEMPLATE(Add);
+    MAKE_LOCKED_TEMPLATE(Sub);
+    MAKE_LOCKED_TEMPLATE(SetBits);
+    MAKE_LOCKED_TEMPLATE(ClearBits);
+
+    MAKE_LOCKED_FUNCTIONS(Add,   int,   "addl %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(Sub,   int,   "subl %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(SetBits,   int,   "orl %1,%0",   "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(ClearBits, int,   "andl %1,%0",  "ir", ~v);
+
+    #if !defined(__LP64__) && !defined(__LP64)
+
+    MAKE_LOCKED_FUNCTIONS(Add,   long,  "addl %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(Sub,   long,  "subl %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(SetBits,   long,  "orl %1,%0",   "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(ClearBits, long,  "andl %1,%0",  "ir", ~v);
+
+    #else
+
+    MAKE_LOCKED_FUNCTIONS(Add,   long,  "addq %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(Sub,   long,  "subq %1,%0",  "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(SetBits,   long,  "orq %1,%0",   "ir",  v);
+    MAKE_LOCKED_FUNCTIONS(ClearBits, long,  "andq %1,%0",  "ir", ~v);
+
+    #endif
+};
+
+#endif /* _ATOMIC_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/config_commons.hpp b/src/mod/endpoints/mod_khomp/commons/config_commons.hpp
new file mode 100644 (file)
index 0000000..de8f327
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _CONFIG_COMMONS_HPP_
+#define _CONFIG_COMMONS_HPP_
+
+/****************************************************************************/
+/* ASTERISK */
+#if   defined(COMMONS_LIBRARY_USING_ASTERISK)
+ #define COMMONS_IMPLEMENTATION asterisk
+/****************************************************************************/
+/* CALLWEAVER */
+#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER)
+ #define COMMONS_IMPLEMENTATION callweaver
+/****************************************************************************/
+/* FREESWITCH */
+#elif defined(COMMONS_LIBRARY_USING_FREESWITCH)
+ #define COMMONS_IMPLEMENTATION freeswitch
+/****************************************************************************/
+/* GNU/LINUX (generic) */
+#elif defined(COMMONS_LIBRARY_USING_GNU_LINUX)
+ #define COMMONS_IMPLEMENTATION gnulinux
+/****************************************************************************/
+#else
+ #error Unknown implementation selected. Please define COMMONS_LIBRARY_USING_* correctly.
+#endif
+
+#define COMMONS_INCLUDE(file) <COMMONS_IMPLEMENTATION/file>
+
+#endif  /* _CONFIG_COMMONS_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/config_options.cpp b/src/mod/endpoints/mod_khomp/commons/config_options.cpp
new file mode 100644 (file)
index 0000000..5383855
--- /dev/null
@@ -0,0 +1,710 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <config_options.hpp>
+
+ConfigOption::ConfigOption(std::string name, const ConfigOption::StringType & value, const ConfigOption::StringType defvalue, string_allowed_type allowed, bool list_me)
+: _my_name(name), _value_data(new StringData(const_cast<StringType &>(value), defvalue, allowed), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, const ConfigOption::StringType & value, const ConfigOption::StringType defvalue, bool list_me)
+: _my_name(name), _value_data(new StringData(const_cast<StringType &>(value), defvalue, string_allowed_type()), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, const ConfigOption::SignedIntType & value, const ConfigOption::SignedIntType defvalue,
+                             ConfigOption::SignedIntType min, ConfigOption::SignedIntType max, ConfigOption::SignedIntType step, bool list_me)
+: _my_name(name), _value_data(new SignedIntData(const_cast<SignedIntType &>(value), defvalue, Range<SignedIntType>(min, max, step)), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, const ConfigOption::UnsignedIntType & value, const ConfigOption::UnsignedIntType defvalue,
+                             ConfigOption::UnsignedIntType min, ConfigOption::UnsignedIntType max, ConfigOption::UnsignedIntType step, bool list_me)
+: _my_name(name), _value_data(new UnsignedIntData(const_cast<UnsignedIntType &>(value), defvalue, Range<UnsignedIntType>(min, max, step)), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, const ConfigOption::BooleanType & value, const ConfigOption::BooleanType defvalue, bool list_me)
+: _my_name(name), _value_data(new BooleanData(const_cast<BooleanType &>(value), defvalue), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, ConfigOption::FunctionType fun, std::string defvalue, string_allowed_type allowed, bool list_me)
+: _my_name(name), _value_data(new FunctionData(fun, defvalue, allowed), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(std::string name, ConfigOption::FunctionType fun, std::string defvalue, bool list_me)
+: _my_name(name), _value_data(new FunctionData(fun, defvalue, string_allowed_type()), true),
+  _list_me(list_me), _values(NULL), _loaded(false)
+{};
+
+ConfigOption::ConfigOption(const ConfigOption & o)
+: _my_name(o._my_name), _value_data(o._value_data),
+  _list_me(o._list_me), _values(o._values), _loaded(o._loaded)
+{};
+
+ConfigOption::~ConfigOption(void)
+{
+    if (_values)
+    {
+        for (unsigned int i = 0; _values[i] != NULL; i++)
+            delete _values[i];
+
+        delete[] _values;
+        _values = NULL;
+    }
+};
+
+void ConfigOption::set(ConfigOption::StringType value)
+{
+    switch (_value_data.which())
+    {
+        case ID_STRING:
+        {
+            try
+            {
+                StringData & tmp = _value_data.get<StringData>();
+
+                if (tmp.string_allowed.empty())
+                {
+                    tmp.string_val = value;
+                    _loaded = true;
+                }
+                else
+                {
+                    if (tmp.string_allowed.find(value) != tmp.string_allowed.end())
+                    {
+                        tmp.string_val = value;
+                        _loaded = true;
+                        return;
+                    }
+
+                    std::string allowed_string;
+
+                    for (string_allowed_type::iterator i = tmp.string_allowed.begin(); i != tmp.string_allowed.end(); i++)
+                    {
+                        allowed_string += " '";
+                        allowed_string += (*i);
+                        allowed_string += "'";
+                    }
+
+                    throw ConfigProcessFailure(STG(FMT("value '%s' not allowed for option '%s' (allowed values:%s)")
+                        % value % _my_name % allowed_string));
+                }
+                break;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+        }
+
+        case ID_FUN:
+        {
+            try
+            {
+                FunctionData & tmp = _value_data.get<FunctionData>();
+                tmp.fun_val(value);
+                _loaded = true;
+                break;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+        }
+
+        default:
+        {
+            throw ConfigProcessFailure(STG(FMT("option '%s' is not of type string, nor function defined") % _my_name));
+        }
+    }
+}
+
+void ConfigOption::set(ConfigOption::SignedIntType value)
+{
+    try
+    {
+        SignedIntData & tmp = _value_data.get<SignedIntData>();
+
+        if (value < tmp.sint_Range.minimum)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too low)") % value % _my_name));
+
+        if (value > tmp.sint_Range.maximum)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too high)") % value % _my_name));
+
+        if (((value - tmp.sint_Range.minimum) % tmp.sint_Range.step) != 0)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (outside allowed step)") % value % _my_name));
+
+        tmp.sint_val = value;
+        _loaded = true;
+    }
+    catch(ValueType::InvalidType & e)
+    {
+        throw;
+    }
+}
+
+void ConfigOption::set(ConfigOption::UnsignedIntType value)
+{
+    try
+    {
+        UnsignedIntData & tmp = _value_data.get<UnsignedIntData>();
+
+        if (value < tmp.uint_Range.minimum)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too low)") % value % _my_name));
+
+        if (value > tmp.uint_Range.maximum)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (too high)") % value % _my_name));
+
+        if (((value - tmp.uint_Range.minimum) % tmp.uint_Range.step) != 0)
+            throw ConfigProcessFailure(STG(FMT("value '%d' out-of-Range for option '%s' (outside allowed step)") % value % _my_name));
+
+        tmp.uint_val = value;
+        _loaded = true;
+    }
+    catch(ValueType::InvalidType & e)
+    {
+        throw;
+    }
+}
+
+void ConfigOption::set(ConfigOption::BooleanType value)
+{
+    try
+    {
+        BooleanData & tmp = _value_data.get<BooleanData>();
+        tmp.bool_val = value;
+        _loaded = true;
+    }
+    catch(ValueType::InvalidType & e)
+    {
+        throw;
+    }
+}
+
+std::string & ConfigOption::name(void) { return _my_name; };
+
+ConfigOption::value_id_type ConfigOption::type(void)
+{
+    return (value_id_type) _value_data.which();
+};
+
+const char ** ConfigOption::values(void)
+{
+    if (_values != NULL)
+        return _values;
+
+    switch ((value_id_type) _value_data.which())
+    {
+        case ConfigOption::ID_BOOL:
+        {
+            _values = new const char*[3];
+
+            _values[0] = strdup("yes");
+            _values[1] = strdup("no");
+            _values[2] = NULL;
+
+            return _values;
+        }
+
+        case ConfigOption::ID_SINT:
+        {
+            try
+            {
+                SignedIntData & tmp = _value_data.get<SignedIntData>();
+
+
+                unsigned int count = ((tmp.sint_Range.maximum - tmp.sint_Range.minimum) / tmp.sint_Range.step) + 1;
+                unsigned int index = 0;
+
+                _values = new const char*[count + 1];
+
+                for (SignedIntType i = tmp.sint_Range.minimum; i <= tmp.sint_Range.maximum; i += tmp.sint_Range.step, index++)
+                    _values[index] = strdup(STG(FMT("%d") % i).c_str());
+
+                _values[index] = NULL;
+
+                return _values;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+        }
+
+        case ConfigOption::ID_UINT:
+        {
+            try
+            {
+                UnsignedIntData & tmp = _value_data.get<UnsignedIntData>();
+
+                unsigned int count = ((tmp.uint_Range.maximum - tmp.uint_Range.minimum) / tmp.uint_Range.step) + 1;
+                unsigned int index = 0;
+
+                _values = new const char*[count + 1];
+
+                for (UnsignedIntType i = tmp.uint_Range.minimum; i <= tmp.uint_Range.maximum; i += tmp.uint_Range.step, index++)
+                    _values[index] = strdup(STG(FMT("%d") % i).c_str());
+
+                _values[index] = NULL;
+
+                return _values;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+        }
+
+        case ConfigOption::ID_STRING:
+        {
+            try
+            {
+                StringData & tmp = _value_data.get<StringData>();
+
+                _values = new const char*[ tmp.string_allowed.size() + 1 ];
+
+                unsigned int index = 0;
+
+                for (string_allowed_type::iterator i = tmp.string_allowed.begin(); i != tmp.string_allowed.end(); i++, index++)
+                    _values[index] = strdup((*i).c_str());
+
+                _values[index] = NULL;
+
+                return _values;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+        }
+
+        case ConfigOption::ID_FUN:
+        {
+            try
+            {
+                FunctionData & tmp = _value_data.get<FunctionData>();
+
+                _values = new const char*[ tmp.fun_allowed.size() + 1 ];
+
+                unsigned int index = 0;
+
+                for (string_allowed_type::iterator i = tmp.fun_allowed.begin(); i != tmp.fun_allowed.end(); i++, index++)
+                    _values[index] = strdup((*i).c_str());
+
+                _values[index] = NULL;
+                return _values;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+        }
+
+        default:
+            throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which()));
+    }
+};
+
+void ConfigOption::reset(void)
+{
+    _loaded = false;
+};
+
+void ConfigOption::commit(void)
+{
+    if (_loaded)
+        return;
+
+    switch ((value_id_type) _value_data.which())
+    {
+        case ConfigOption::ID_BOOL:
+        {
+            try
+            {
+                BooleanData & tmp = _value_data.get<BooleanData>();
+                tmp.bool_val = tmp.bool_default;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+            break;
+        }
+
+        case ConfigOption::ID_SINT:
+        {
+            try
+            {
+                SignedIntData & tmp = _value_data.get<SignedIntData>();
+                tmp.sint_val = tmp.sint_default;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+            break;
+        }
+
+        case ConfigOption::ID_UINT:
+        {
+            try
+            {
+                UnsignedIntData & tmp = _value_data.get<UnsignedIntData>();
+                tmp.uint_val = tmp.uint_default;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+            break;
+        }
+
+        case ConfigOption::ID_STRING:
+        {
+            try
+            {
+                StringData & tmp = _value_data.get<StringData>();
+                tmp.string_val = tmp.string_default;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+            break;
+        }
+
+        case ConfigOption::ID_FUN:
+        {
+            try
+            {
+                FunctionData & tmp = _value_data.get<FunctionData>();
+                tmp.fun_val(tmp.fun_default);
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+            break;
+        }
+
+        default:
+            throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which()));
+    }
+
+    _loaded = true;
+};
+
+void ConfigOption::copy_from(ConfigOption & src)
+{
+    if (src._value_data.which() != _value_data.which())
+        throw ConfigProcessFailure(STG(FMT("unable to copy options, source type differs from destination.")));
+
+    if (!src._loaded)
+        return;
+
+    switch ((value_id_type) _value_data.which())
+    {
+        case ConfigOption::ID_BOOL:
+        {
+            try
+            {
+                BooleanData & stmp = src._value_data.get<BooleanData>();
+                BooleanData & dtmp = _value_data.get<BooleanData>();
+                /* do not copy references, but values.. */
+                bool tmpval = stmp.bool_val;
+                dtmp.bool_val = tmpval;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+            break;
+        }
+
+        case ConfigOption::ID_SINT:
+        {
+            try
+            {
+                SignedIntData & stmp = src._value_data.get<SignedIntData>();
+                SignedIntData & dtmp = _value_data.get<SignedIntData>();
+                /* do not copy references, but values.. */
+                int tmpval = stmp.sint_val;
+                dtmp.sint_val = tmpval;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+            break;
+        }
+
+        case ConfigOption::ID_UINT:
+        {
+            try
+            {
+                UnsignedIntData & stmp = src._value_data.get<UnsignedIntData>();
+                UnsignedIntData & dtmp = _value_data.get<UnsignedIntData>();
+                /* do not copy references, but values.. */
+                unsigned int tmpval = stmp.uint_val;
+                dtmp.uint_val = tmpval;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+
+            break;
+        }
+
+        case ConfigOption::ID_STRING:
+        {
+            try
+            {
+                StringData & stmp = src._value_data.get<StringData>();
+                StringData & dtmp = _value_data.get<StringData>();
+                /* do not copy references, but values.. */
+                std::string tmpval = stmp.string_val;
+                dtmp.string_val = tmpval;
+            }
+            catch(ValueType::InvalidType & e)
+            {
+                throw;
+            }
+
+            break;
+        }
+
+        case ConfigOption::ID_FUN:
+        {
+            /* TO IMPLEMENT (NEEDS ANOTHER METHOD ON FUNCTION FOR GETTING VALUE) */
+
+//            FunctionData & tmp = boost::get<FunctionData>(_value_data);
+//
+//            if (!tmp.loaded)
+//            {
+//                tmp.fun_val(tmp.fun_default);
+//                tmp.loaded = true;
+//            }
+            break;
+        }
+
+        default:
+            throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % _value_data.which()));
+    }
+
+    _loaded = true;
+};
+
+/*********************************/
+
+bool ConfigOptions::add(ConfigOption option)
+{
+    //option_map_type::iterator iter2 = _map.begin();
+
+    //boost::tie(iter2, ok2)
+    std::pair<option_map_type::iterator, bool> ret = _map.insert(option_pair_type(option.name(), option));
+
+    return ret.second;
+}
+
+bool ConfigOptions::synonym(std::string equiv_opt, std::string main_opt)
+{
+    //syn_option_map_type::iterator iter = _syn_map.begin();
+
+    //boost::tie(iter, ok)
+    std::pair<syn_option_map_type::iterator, bool> ret = _syn_map.insert(syn_option_pair_type(equiv_opt, main_opt));
+
+    return ret.second;
+}
+
+ConfigOptions::string_set ConfigOptions::options(void)
+{
+    string_set res;
+
+    for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++)
+        res.insert((*i).first);
+
+    return res;
+}
+
+void ConfigOptions::process(const char * name, const char * value)
+{
+    option_map_type::iterator iter = find_option(name);
+
+    if (iter == _map.end())
+        throw ConfigProcessFailure(STG(FMT("unknown option '%s'") % name));
+
+    try
+    {
+        switch ((*iter).second.type())
+        {
+            case ConfigOption::ID_SINT:
+                set<ConfigOption::SignedIntType>((*iter).first, Strings::toulong(value));
+                return;
+            case ConfigOption::ID_UINT:
+                set<ConfigOption::UnsignedIntType>((*iter).first, Strings::tolong(value));
+                return;
+            case ConfigOption::ID_BOOL:
+                set<ConfigOption::BooleanType>((*iter).first, Strings::toboolean(value));
+                return;
+            case ConfigOption::ID_STRING:
+            case ConfigOption::ID_FUN:
+                set<ConfigOption::StringType>((*iter).first, std::string(value));
+                return;
+            default:
+                throw ConfigProcessFailure(STG(FMT("unknown type identifier '%d'") % (*iter).second.type()));
+        }
+    }
+    catch (Strings::invalid_value & e)
+    {
+        throw ConfigProcessFailure(STG(FMT("invalid value '%s' for option '%s'") % value % name));
+    }
+}
+
+const char ** ConfigOptions::values(const char * name)
+{
+    option_map_type::iterator iter = find_option(name);
+
+    if (iter == _map.end())
+        throw ConfigProcessFailure(STG(FMT("unknown option '%s'") % name));
+
+    return (*iter).second.values();
+}
+
+const char ** ConfigOptions::values(void)
+{
+    if (_values != NULL)
+        return _values;
+
+    unsigned int count = 0;
+
+    for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++)
+        if ((*i).second.list_me())
+            ++count;
+
+    _values = new const char*[ count + 1 ];
+
+    unsigned int index = 0;
+
+    for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++)
+    {
+        if ((*i).second.list_me())
+        {
+            _values[index] = strdup((*i).first.c_str());
+            ++index;
+        }
+    }
+
+    _values[index] = NULL;
+
+    return _values;
+}
+
+void ConfigOptions::reset(void)
+{
+    for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++)
+        (*i).second.reset();
+}
+
+ConfigOptions::messages_type ConfigOptions::commit(void)
+{
+    messages_type msgs;
+
+    for (option_map_type::iterator i = _map.begin(); i != _map.end(); i++)
+    {
+        try
+        {
+            (*i).second.commit();
+        }
+        catch (ConfigProcessFailure & e)
+        {
+            msgs.push_back(e.msg);
+        }
+    }
+
+    return msgs;
+}
+
+bool ConfigOptions::loaded(std::string name)
+{
+    option_map_type::iterator iter = find_option(name);
+
+    if (iter == _map.end())
+        return false;
+
+    return iter->second.loaded();
+}
+
+void ConfigOptions::copy_from(ConfigOptions & source, std::string name)
+{
+    option_map_type::iterator iter_src = source.find_option(name);
+    option_map_type::iterator iter_dst = find_option(name);
+
+    if (iter_src == source._map.end())
+        throw ConfigProcessFailure(STG(FMT("unknown option '%s' on source") % name));
+
+    if (iter_dst == _map.end())
+        throw ConfigProcessFailure(STG(FMT("unknown option '%s' on destination") % name));
+
+    iter_dst->second.copy_from(iter_src->second);
+}
+
+ConfigOptions::option_map_type::iterator ConfigOptions::find_option(std::string name)
+{
+    syn_option_map_type::iterator syn_iter = _syn_map.find(name);
+
+    if (syn_iter != _syn_map.end())
+        name = syn_iter->second;
+
+    option_map_type::iterator iter = _map.find(name);
+
+    return iter;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/config_options.hpp b/src/mod/endpoints/mod_khomp/commons/config_options.hpp
new file mode 100644 (file)
index 0000000..3cfe2e1
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <set>
+#include <map>
+#include <vector>
+
+#include <strings.hpp>
+
+#include <function.hpp>
+#include <variant.hpp>
+#include <format.hpp>
+
+#ifndef _CONFIG_OPTIONS_HPP_
+#define _CONFIG_OPTIONS_HPP_
+
+struct ConfigProcessFailure
+{
+    ConfigProcessFailure(std::string _msg): msg(_msg) {};
+    std::string msg;
+};
+
+struct ConfigOption
+{
+    typedef int          SignedIntType;
+    typedef unsigned int UnsignedIntType;
+    typedef bool         BooleanType;
+    typedef std::string  StringType;
+
+    typedef Function::Function1 < void, std::string > FunctionType;
+
+    typedef std::set < StringType >     string_allowed_type;
+
+    /* this should reflect 'variant.which()'! */
+    typedef enum
+    {
+        ID_SINT   = 0,
+        ID_UINT   = 1,
+        ID_BOOL   = 2,
+        ID_STRING = 3,
+        ID_FUN    = 4,
+    }
+    value_id_type;
+
+    template < typename number_type >
+    struct Range
+    {
+        Range(number_type _minimum, number_type _maximum, number_type _step)
+        : minimum(_minimum), maximum(_maximum), step(_step) {};
+
+        number_type minimum, maximum, step;
+    };
+
+    struct SignedIntData : public VariantBaseType < void >
+    {
+        SignedIntData(SignedIntType & _sint_val, SignedIntType _sint_default, Range< SignedIntType > _sint_Range)
+        : sint_val(_sint_val), sint_default(_sint_default), sint_Range(_sint_Range) {};
+
+        int which()
+        {
+            return ID_SINT;
+        }
+
+        SignedIntType        & sint_val;
+        SignedIntType          sint_default;
+        Range<SignedIntType>   sint_Range;
+    };
+
+    struct UnsignedIntData : public VariantBaseType < void >
+    {
+        UnsignedIntData(UnsignedIntType & _uint_val, UnsignedIntType _uint_default, Range< UnsignedIntType > _uint_Range)
+        : uint_val(_uint_val), uint_default(_uint_default), uint_Range(_uint_Range) {};
+
+        int which()
+        {
+            return ID_UINT;
+        }
+
+        UnsignedIntType        & uint_val;
+        UnsignedIntType          uint_default;
+        Range<UnsignedIntType>   uint_Range;
+    };
+
+    struct BooleanData : public VariantBaseType < void >
+    {
+        BooleanData(BooleanType & _bool_val, BooleanType _bool_default)
+        : bool_val(_bool_val), bool_default(_bool_default) {};
+
+        int which()
+        {
+            return ID_BOOL;
+        }
+
+        BooleanType      & bool_val;
+        BooleanType        bool_default;
+    };
+
+    struct StringData : public VariantBaseType < void >
+    {
+        StringData(std::string & _string_val, std::string _string_default, string_allowed_type _string_allowed)
+        : string_val(_string_val), string_default(_string_default), string_allowed(_string_allowed) {};
+
+        int which()
+        {
+            return ID_STRING;
+        }
+
+        std::string         & string_val;
+        std::string           string_default;
+        string_allowed_type   string_allowed;
+    };
+
+    struct FunctionData : public VariantBaseType < void >
+    {
+        FunctionData(FunctionType _fun_val, std::string _fun_default, string_allowed_type _fun_allowed)
+        : fun_val(_fun_val), fun_default(_fun_default), fun_allowed(_fun_allowed) {};
+
+        int which()
+        {
+            return ID_FUN;
+        }
+
+        FunctionType             fun_val;
+        std::string          fun_default;
+        string_allowed_type  fun_allowed;
+    };
+
+
+    typedef Variant < VariantBaseType < void > >  ValueType;
+
+    ConfigOption(std::string, const StringType &, const StringType, string_allowed_type allowed, bool list_me = true);
+    ConfigOption(std::string, const StringType &, const StringType = "", bool list_me = true);
+    ConfigOption(std::string, const SignedIntType &, const SignedIntType = 0, SignedIntType min = -INT_MAX, SignedIntType max = INT_MAX, SignedIntType step = 1, bool list_me = true);
+    ConfigOption(std::string, const UnsignedIntType &, const UnsignedIntType = 0, UnsignedIntType min = 0, UnsignedIntType max = UINT_MAX, UnsignedIntType step = 1, bool list_me = true);
+    ConfigOption(std::string, const BooleanType &, const BooleanType = false, bool list_me = true);
+    ConfigOption(std::string, FunctionType, std::string defvalue, string_allowed_type allowed, bool list_me = true);
+    ConfigOption(std::string, FunctionType, std::string defvalue = "", bool list_me = true);
+
+    ConfigOption(const ConfigOption & o);
+
+    ~ConfigOption(void);
+
+    void set(StringType value);
+
+    void set(SignedIntType value);
+    void set(UnsignedIntType value);
+    void set(BooleanType value);
+
+    BooleanType get_bool(){ return _value_data.get<BooleanData>().bool_val; }
+    std::string get_str(){ return _value_data.get<StringData>().string_val; }
+    SignedIntType get_sint(){ return _value_data.get<SignedIntData>().sint_val; }
+    UnsignedIntType get_uint(){ return _value_data.get<UnsignedIntData>().uint_val; }
+
+    std::string    & name(void);
+    value_id_type    type(void);
+
+    const char **  values(void);
+
+    void            reset(void);
+    void           commit(void);
+
+    bool          list_me(void) { return _list_me; };
+    bool           loaded(void) { return _loaded;  };
+
+    void        copy_from(ConfigOption &);
+
+ protected:
+    std::string       _my_name;
+    ValueType     _value_data;
+
+    bool              _list_me;
+    const char **      _values;
+    bool               _loaded;
+};
+
+struct ConfigOptions
+{
+    typedef std::vector < std::string >    messages_type;
+
+    ConfigOptions(void): _values(NULL) {};
+
+    typedef std::set < std::string >  string_set;
+
+    typedef std::map  < std::string, ConfigOption >   option_map_type;
+    typedef std::pair < std::string, ConfigOption >  option_pair_type;
+
+    typedef std::map  < std::string, std::string >   syn_option_map_type;
+    typedef std::pair < std::string, std::string >  syn_option_pair_type;
+
+    bool add(ConfigOption option);
+
+    /* only valid in "process" (for backwards compatibility config files) */
+    bool synonym(std::string, std::string);
+
+    template <typename ValueType>
+    void set(std::string name, ValueType value)
+    {
+        option_map_type::iterator iter = _map.find(name);
+
+        if (iter == _map.end())
+            throw ConfigProcessFailure(STG(FMT("unknown option: %s") % name));
+
+        (*iter).second.set(value);
+    }
+
+    std::string get(std::string name)
+    {
+        option_map_type::iterator iter = _map.find(name);
+
+        if (iter == _map.end())
+            throw ConfigProcessFailure(STG(FMT("unknown option: %s") % name));
+
+        switch((*iter).second.type())
+        {
+            case ConfigOption::ID_BOOL: return (*iter).second.get_bool() ? "yes" : "no";
+            case ConfigOption::ID_STRING: return (*iter).second.get_str();
+            case ConfigOption::ID_UINT: return STG(FMT("%d") % (*iter).second.get_uint());
+            case ConfigOption::ID_SINT: return STG(FMT("%d") % (*iter).second.get_sint());
+            case ConfigOption::ID_FUN: return "";
+        }
+    }
+
+    string_set options(void);
+
+    void process(const char *, const char *); /* process option from file */
+
+    void           reset(void);         /* reset loaded opts */
+    messages_type commit(void);         /* set defaults */
+
+    const char ** values(const char *); /* option value */
+    const char ** values(void);         /* values from options */
+
+    bool          loaded(std::string);  /* return if config was loaded */
+
+    void          copy_from(ConfigOptions &, std::string);
+
+ protected:
+    option_map_type::iterator find_option(std::string);
+
+ protected:
+    option_map_type      _map;
+    syn_option_map_type  _syn_map;
+
+    const char ** _values;
+};
+
+#endif /* _CONFIG_OPTIONS_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/configfile.cpp
new file mode 100644 (file)
index 0000000..6aa2e59
--- /dev/null
@@ -0,0 +1,241 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+#include <errno.h>
+
+#include <configurator/configfile.hpp>
+
+#if _MSC_VER >= 1400
+#undef close
+#endif
+
+void Configfile::ignore(std::string str)
+{
+       _ignores.insert(str);
+};
+
+bool Configfile::select(Section **ptr, std::string str)
+{
+       /* default section == this! */
+       *ptr = this;
+       
+       /* always success by default */
+       return true;
+};
+
+bool Configfile::adjust(Section * section, std::string & opt, std::string & val)
+{
+       return section->load(opt, val);
+};
+
+bool Configfile::deserialize(std::ifstream& fd)
+{
+       Section * section = NULL;
+       
+       /* default selection! */
+       if (!select(&section))
+       {
+               _errors.push_back("default selection has failed!");
+               return false;
+       }
+
+       size_t count = 0;
+
+       while (fd.good())
+       {
+               std::string str;
+
+               /* read one line! */
+               std::getline(fd, str);
+
+               size_t lst = str.size() - 1;
+
+               if (str.size() >= 1 && str[lst] == '\r') //cuida das quebras de linha do tipo \r\n
+               {
+                       str.erase(lst,1);
+                       --lst;
+               }
+
+               /* empty line! */
+               if (str.size() == 0)
+                       continue;
+
+               /* comment! */
+               if (str[0] == '#')
+                       continue;
+
+               ++count;
+
+               if (str[0] == '[' && str[lst] == ']')
+               {
+                       str.erase(0,1);   --lst;
+                       str.erase(lst,1); --lst;
+
+                       if (!select(&section, str))
+                       {
+                               _errors.push_back(STG(FMT("erroneous section '%s'") % str));
+
+                               /* ignore this section */
+                               section = NULL;
+                               continue;
+                       }
+               }
+               else
+               {
+                       std::string::size_type pos = str.find('=');
+
+                       if (pos == std::string::npos)
+                       {
+                               _errors.push_back(STG(FMT("erroneous separator '%s'") % str));
+                               continue;
+                       };
+
+                       if (section == NULL)
+                       {
+                               _errors.push_back(STG(FMT("no section for option '%s'") % str));
+                               continue;
+                       }
+
+                       std::string  opt(str.substr(0,pos));
+                       std::string  val(str.substr(pos+1));
+
+                       if (_ignores.find(opt) != _ignores.end())
+                               continue;
+
+                       if (val == "@") val = "";
+
+                       if (adjust(section, opt, val))
+                               continue;
+
+                       _errors.push_back(STG(FMT("option '%s' does "
+                               "not exist or '%s' is not a valid value (at section '%s')")
+                               % opt % val % section->name()));
+               }
+       }
+
+       // retorna 'true' se arquivo tinha alguma coisa valida.
+       return (count != 0);
+}
+
+bool Configfile::obtain()
+{
+       std::ifstream fd(_filename.c_str());
+
+       if (!fd.is_open())
+       {
+               _errors.push_back(STG(FMT("unable to open file '%s': %s")
+                       % _filename % strerror(errno)));
+               return false;
+       };
+
+       if (!deserialize(fd))
+       {
+               fd.close();
+               return false;
+       }
+
+       fd.close();
+       return true;
+};
+
+void Configfile::recurse(std::ofstream& fd, Section * section)
+{
+       typedef Section::SectionMap::iterator section_iter;
+       typedef Section::OptionMap::iterator  option_iter;
+
+       for (option_iter i = section->option_begin(); i != section->option_end(); i++)
+       {
+               std::string res;
+
+               if ((*i).second.store(res))
+               {
+                       if (res == "") res = "@";
+                       fd << (*i).first << "=" << res << std::endl;
+               }
+       }
+       
+       if (!section->recursive())
+               return;
+       
+       for (section_iter j = section->section_begin(); j != section->section_end(); j++)
+               recurse(fd, (*j).second);
+}
+
+bool Configfile::serialize(std::ofstream& fd)
+{
+       recurse(fd, this);
+       return true;
+}
+
+bool Configfile::provide()
+{
+       std::string tmp(_filename);
+       tmp += ".new";
+
+       std::ofstream fd(tmp.c_str());
+
+       if (!fd.good())
+       {
+               _errors.push_back(STG(FMT("unable to open file '%s': %s")
+                       % tmp % strerror(errno)));
+               return false;
+       }
+
+       if (!serialize(fd))
+       {
+               fd.close();
+               return false;
+       }
+
+       fd.close();
+
+       if (rename(tmp.c_str(), _filename.c_str()) != 0)
+       {
+               _errors.push_back(STG(FMT("unable to replace config file '%s': %s")
+                       % _filename % strerror(errno)));
+               return false;
+       }
+
+       return true;
+}
+
+#if _MSC_VER >= 1400
+#define close _close
+#endif
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/configfile.hpp
new file mode 100644 (file)
index 0000000..61f4246
--- /dev/null
@@ -0,0 +1,90 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <vector>
+#include <fstream>
+#include <sstream>
+#include <set>
+
+#include <format.hpp>
+
+#include <configurator/section.hpp>
+
+#ifndef _CONFIG_CONFIGFILE_HPP_
+#define _CONFIG_CONFIGFILE_HPP_
+
+struct Configfile: public Section
+{
+       typedef std::list < std::string > ErrorVector;
+       typedef std::set < std::string >  NameSet;
+
+       Configfile(std::string name, std::string desc)
+       : Section(name, desc), _good(false) {};
+
+       virtual ~Configfile() {};
+
+       bool                good() { return _good;     };
+       std::string &   filename() { return _filename; };
+
+       ErrorVector &     errors() { return _errors;   };
+
+       void ignore(std::string);
+
+       virtual bool obtain();
+       virtual bool provide();
+
+ protected:
+       virtual bool select(Section **, std::string str = "");
+       virtual bool adjust(Section *, std::string & opt, std::string & val);
+
+       virtual bool deserialize(std::ifstream &);
+       virtual bool serialize(std::ofstream &);
+
+       void recurse(std::ofstream &, Section *);
+
+ protected:
+       bool             _good;
+       ErrorVector      _errors;
+       NameSet          _ignores;
+       std::string      _filename;
+};
+
+#endif /* _CONFIG_CONFIGFILE_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/option.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/option.cpp
new file mode 100644 (file)
index 0000000..083883e
--- /dev/null
@@ -0,0 +1,185 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <configurator/option.hpp>
+
+bool Option::equals(std::string & value)
+{
+       switch (_restriction.numeral())
+       {
+               case Restriction::N_UNIQUE:
+               {
+                       Restriction::Value my_value;
+
+                       if (!_restriction.get(Restriction::F_USER, my_value))
+                               return false;
+
+                       return (my_value == value);
+               }
+               case Restriction::N_MULTIPLE:
+               {
+                       Restriction::Vector my_values;
+
+                       if (!_restriction.get(Restriction::F_USER, my_values))
+                               return false;
+
+                       for (Restriction::Vector::iterator i = my_values.begin(); i != my_values.end(); i++)
+                       {
+                               if ((*i) == value)
+                                       return true;
+                       }
+                       
+                       return false;
+               }
+       }
+
+       return false;
+}
+
+bool Option::load(std::string & value)
+{
+       bool ret = _restriction.set(Restriction::F_FILE, value);
+
+       if (ret) _modified = false;
+
+       return ret;
+}
+
+bool Option::change(std::string & value)
+{
+       bool ret = _restriction.set(Restriction::F_FILE, value);
+
+       if (ret) _modified = true;
+
+       return ret;
+}
+
+bool Option::store(std::string & value)
+{
+       switch  (_restriction.numeral())
+       {
+               case Restriction::N_UNIQUE:
+                       return _restriction.get(Restriction::F_FILE, value);
+               
+               case Restriction::N_MULTIPLE:
+               {
+                       Restriction::Vector values;
+                       
+                       if (!_restriction.get(Restriction::F_FILE, values))
+                               return false;
+
+                       Strings::Merger strs;
+                       for (Restriction::Vector::iterator i = values.begin(); i != values.end(); i++)
+                               strs.add(*i);
+                       value = strs.merge(","); 
+
+                       return true;
+               }
+               
+               default:
+                       return false;
+       }
+}
+
+Option::Flags Option::set(const char * value)
+{
+       std::string str_value(value);
+       return set(str_value);
+}
+
+
+Option::Flags Option::set(Restriction::Value & value)
+{
+       Restriction::Value  last_value, curr_value;
+       Flags               flags;
+       
+       bool ret1 = _restriction.get(Restriction::F_USER, last_value);
+       
+       if (!_restriction.set(Restriction::F_USER, value))
+               return flags;
+       
+       flags[F_ADJUSTED] = true;
+
+       bool ret2 = _restriction.get(Restriction::F_USER, curr_value);
+       
+       if (!ret1 || (ret2 && (last_value != curr_value)))
+       {
+               flags[F_MODIFIED] = true;
+               _modified = true;
+       }
+
+       return flags;
+}
+
+Option::Flags Option::set(Restriction::Vector & values)
+{
+       Restriction::Vector  last_values, curr_values;
+       Flags                flags;
+       
+       bool ret1 = _restriction.get(Restriction::F_USER, last_values);
+
+       if (!_restriction.set(Restriction::F_USER, values))
+               return flags;
+               
+       flags[F_ADJUSTED] = true;
+
+       bool ret2 = _restriction.get(Restriction::F_USER, curr_values);
+
+       if (!ret1 || (ret2 && (last_values != curr_values)))
+       {
+               flags[F_MODIFIED] = true;
+               _modified = true;
+       }
+
+       return flags;
+}
+
+bool Option::get(Restriction::Value & value)
+{
+       return _restriction.get(Restriction::F_USER, value);
+}
+
+bool Option::get(Restriction::Vector & values)
+{
+       return _restriction.get(Restriction::F_USER, values);
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/option.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/option.hpp
new file mode 100644 (file)
index 0000000..8aa103a
--- /dev/null
@@ -0,0 +1,122 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <iostream>
+
+#include <string>
+#include <list>
+#include <vector>
+
+#include <strings.hpp>
+
+#include <configurator/restriction.hpp>
+
+#ifndef _CONFIG_OPTION_HPP_
+#define _CONFIG_OPTION_HPP_
+
+struct Option
+{
+    enum FlagTypes
+    {
+               F_MODIFIED = 0x0, /* if option was modified */
+               F_ADJUSTED = 0x1, /* if option was correctly formated */
+    };
+
+       struct Flags: public std::vector<bool>
+       {
+               Flags(): std::vector<bool>(2) {};
+       };
+
+       typedef Restriction::Value   Value;
+       typedef Restriction::Vector Vector;
+
+    /* exception */
+    struct InvalidDefaultValue
+    {
+        InvalidDefaultValue(std::string name, std::string value)
+        : _name(name), _value(value) {};
+
+        std::string &  name() { return _name;  };
+        std::string & value() { return _value; };
+
+      protected:
+        std::string _name;
+        std::string _value;
+    };
+
+       Option(std::string name, std::string desc, std::string defvalue, Restriction restriction)
+       : _name(name), _desc(desc), _restriction(restriction), _modified(true)
+       {
+               std::string value(defvalue);
+
+               if (!(set(value)[F_ADJUSTED]))
+            throw InvalidDefaultValue(name, defvalue);
+       }
+
+       const std::string & name()        { return _name; };
+       const std::string & description() { return _desc; };
+
+       Restriction       & restriction() { return _restriction; };
+       bool                modified()    { return _modified;    };
+
+ public:
+       bool    load(std::string &);
+       bool    change(std::string &);
+       bool    store(std::string &);
+
+       Flags   set(const char  *);
+       Flags   set(Value  &);
+       Flags   set(Vector &);
+
+       bool    get(Value  &);
+       bool    get(Vector &);
+
+       bool    equals(std::string &);
+
+ protected:
+       std::string   _name;
+       std::string   _desc;
+
+       Restriction   _restriction;
+       bool          _modified;
+};
+
+#endif /* _CONFIG_OPTION_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/restriction.cpp
new file mode 100644 (file)
index 0000000..9653a7c
--- /dev/null
@@ -0,0 +1,353 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <math.h>
+#include <string.h>
+
+#include <iostream>
+#include <strings.hpp>
+
+#include <configurator/restriction.hpp>
+
+/* internal helper! */
+bool Restriction::equalNumber(const double a, const double b)
+{
+    char tmp1[64];
+    char tmp2[64];
+
+    snprintf(tmp1, sizeof(tmp1), "%.3f", a);
+    snprintf(tmp2, sizeof(tmp2), "%.3f", b);
+
+    if (strncmp(tmp1, tmp2, sizeof(tmp1)))
+        return false;
+
+    return true;
+}
+
+/* process value to our internal representation */
+
+bool Restriction::process(Restriction::Format fmt,
+               const Restriction::Value & value, Restriction::Value & final)
+{
+       switch (_bounds)
+       {
+               case B_RANGE:
+               {
+                       if (_kind != K_NUMBER)
+                               return false;
+
+            std::string tmpvalue;
+            
+            Restriction::Value::const_iterator itr = value.begin();
+            Restriction::Value::const_iterator end = value.end();
+            
+            tmpvalue.reserve(value.size());
+
+            // f*cking dot/comma notation!
+            for (; itr != end; ++itr)
+                tmpvalue += ((*itr) != ',' ? (*itr) : '.');
+
+            try
+            {
+                       double newvalue = Strings::todouble(tmpvalue);
+
+                if (newvalue < _init && newvalue > _fini)
+                    return false;
+
+                double res = (newvalue - _init) / _step;
+
+                if (!equalNumber(res, rint(res)))
+                    return false;
+    
+                       final = value;
+                           return true;
+            }
+            catch (...)
+            {
+                return false;
+            }
+               }
+               
+               case B_LIST:
+                       for (List::iterator i = _list.begin(); i != _list.end(); i++)
+                       {
+                               Value & tmp = (*i);
+                                               
+                               if (tmp == value)
+                               {
+                                       final = value;
+                                       return true;
+                               }
+                       }
+                       return false;
+
+               case B_MAPS:
+                       switch (fmt)
+                       {
+                               case F_USER:
+                               {
+                                       Map::iterator i = _map_from_usr.find(std::string(value));
+
+                                       if (i == _map_from_usr.end())
+                                               return false;
+
+                                       Value & tmp = (*i).second;
+
+                                       final = tmp;
+                                       return true;
+                               }
+
+                               case F_FILE:
+                               {
+                                       Map::iterator i = _map_from_cfg.find(std::string(value));
+
+                                       if (i == _map_from_cfg.end())
+                                               return false;
+
+                                       final = value;
+                                       return true;
+                               }
+
+                               default:
+                                       break;
+                       }
+                       return false;
+                                       
+               case B_FREE:
+                       final = value;
+                       return true;
+
+               default:
+                       break;
+       }
+
+       return false;
+}
+
+/* unprocess the value (outputs the external representation) */
+
+bool Restriction::unprocess(Restriction::Format fmt,
+               const Restriction::Value & value, Restriction::Value & final)
+{
+       switch (_bounds)
+       {
+               case B_MAPS:
+
+                       switch (fmt)
+                       {
+                               case F_USER:
+                               {
+                                       Map::iterator i = _map_from_cfg.find(std::string(value));
+
+                                       if (i == _map_from_cfg.end())
+                                               return false;
+
+                                       final = (*i).second;
+                                       return true;
+                               }
+                               default:
+                                       break;
+                       }
+
+               default:
+                       final = value;
+                       return true;
+       }
+}
+
+/***************************** *****************************/
+
+bool Restriction::get(Restriction::Format fmt, Restriction::Value & value)
+{
+       if (_numeral != N_UNIQUE)
+               return false;
+
+       if (!unprocess(fmt, _value._unique, value))
+               return false;
+
+       return true;
+}
+
+bool Restriction::get(Restriction::Format fmt, Restriction::Vector & values)
+{
+       if (_numeral != N_MULTIPLE)
+               return false;
+
+    List & my_values = _value._multiple;
+
+       for (List::iterator i = my_values.begin(); i != my_values.end(); i++)
+       {
+               Value & value = (*i);
+               Value   final;
+                               
+               if (!unprocess(fmt, value, final))
+                       return false;
+
+               values.push_back(final);
+       };
+
+       return true;
+}
+
+/***************************** *****************************/
+
+bool Restriction::set(Restriction::Format fmt, Restriction::Value &value)
+{
+       switch (_numeral)
+       {
+               case N_UNIQUE:
+               {
+                       Value final;
+
+                       if (!process(fmt, value, final))
+                               return false;
+
+                       _value._unique = final;
+                       return true;
+               }
+               
+               case N_MULTIPLE:
+               {
+                       if (value == "@" || value == "#" || value == "")
+                       {
+                               _value._multiple.clear();
+                               return true;
+                       }
+                       
+                       Strings::vector_type values;
+                       Strings::tokenize(value, values, ",");
+                       
+                       return set(fmt, values);
+               }
+               
+               default:
+                       return false;
+       }
+}
+
+bool Restriction::set(Restriction::Format fmt, Restriction::Vector & values)
+{
+       if (_numeral != N_MULTIPLE)
+               return false;
+
+       if (values.empty())
+       {
+               _value._multiple.clear();
+       }
+       else
+       {
+               /* list needed to store temporary values */
+           List finals;
+
+               for (Vector::iterator i = values.begin(); i != values.end(); i++)
+               {
+                       Value & value = (*i);
+                       Value   final;
+                       
+                       if (!process(fmt, value, final))
+                               return false;
+
+                       finals.push_back(final);
+               }
+               
+               List & lst = _value._multiple;
+
+               /* need to clear values set before */
+               lst.clear();
+               
+               for (List::iterator i = finals.begin(); i != finals.end(); i++)
+               {
+                       Value value = (*i);
+                       lst.push_back(value);
+               }
+       };
+
+       return true;
+}
+
+/***************************** *****************************/
+
+void Restriction::allowed(Restriction::Vector &vals)
+{
+       switch (_bounds)
+       {
+               case B_FREE:
+                       return;
+
+               case B_LIST:
+                       for (List::iterator i = _list.begin(); i != _list.end(); i++)
+                               vals.push_back((*i));
+                       break;
+
+               case B_MAPS:
+                       for (Map::iterator i = _map_from_usr.begin(); i != _map_from_usr.end(); i++)
+                               vals.push_back((*i).first);
+                       break;
+
+               case B_RANGE:
+        {
+                       if (_kind != K_NUMBER)
+                               return;
+
+            // is there any fraction?
+            bool has_fraction = (!equalNumber(_init, rint(_init))) || (!equalNumber(_fini, rint(_fini))) || (!equalNumber(_step, rint(_step)));
+
+            const char * format = (has_fraction ? "%.2f" : "%02.0f");
+
+                       for (double i = _init; i <= _fini; i += _step)
+                       {
+                               char tmp[32];
+                               snprintf(tmp, sizeof(tmp), format, i);
+                               vals.push_back(std::string(tmp));
+                       }
+                       break;
+        }
+
+               default:
+                       break;
+       }
+}
+
+void Restriction::init_class()
+{
+       _value._unique.clear();
+       _value._multiple.clear();
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/restriction.hpp
new file mode 100644 (file)
index 0000000..0815ede
--- /dev/null
@@ -0,0 +1,321 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <stdarg.h>
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+
+#ifndef _CONFIG_RESTRICTION_HPP_
+#define _CONFIG_RESTRICTION_HPP_
+
+struct Restriction
+{
+       /* generic types */
+       enum Format
+    {
+        F_USER,
+        F_FILE
+    };
+
+    enum Kind
+    {
+//        K_INTEGER,
+//        K_FLOAT,
+        K_STRING,
+        K_NUMBER // = K_INTEGER // compatibility
+    };
+
+    enum Bounds
+    {
+        B_FREE,
+        B_RANGE,
+        B_LIST,
+        B_MAPS
+    };
+
+    enum Numeral
+    {
+        N_UNIQUE,
+        N_MULTIPLE
+    };
+
+       typedef std::string   Value;
+
+       /* types used for data input */
+       struct Pair
+    {
+        const char *pretty;
+        const char *value;
+    };
+
+       typedef std::pair < Value, Value >   PairMap;
+       typedef std::list < PairMap >        ListMap;
+
+       /* types used internally */
+       typedef std::map < Value, Value >           Map;
+       typedef std::vector < Value >            Vector;
+
+       typedef std::list < Value >                List;
+       typedef std::pair < Value, Value >       MapPair;
+
+    struct Generic
+    {
+        Value _unique;
+        List  _multiple;
+    };
+
+       Restriction(Kind kind, Numeral num)
+       : _kind(kind), _bounds(B_FREE), _numeral(num), _unit(""),
+         _init(-1), _fini(-1), _step(-1)
+       {
+               init_class();
+       }
+
+/*
+       Restriction(Kind kind, Numeral num,
+                   int init, int fini, int step = 1)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(init), _ifini(fini), _istep(step),
+         _finit(-1), _ffini(-1), _fstep(-1)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   const char *unit, int init, int fini, int step = 1)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(init), _ifini(fini), _istep(step),
+         _finit(-1), _ffini(-1), _fstep(-1)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   std::string unit, int init, int fini, int step = 1)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(init), _ifini(fini), _istep(step),
+         _finit(-1), _ffini(-1), _fstep(-1)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   float init, float fini, float step = 1)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(-1), _ifini(-1), _istep(-1)
+         _finit(init), _ffini(fini), _fstep(step),
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   const char *unit, float init, float fini, float step = 1.0)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(-1), _ifini(-1), _istep(-1)
+         _finit(init), _ffini(fini), _fstep(step),
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   std::string unit, float init, float fini, float step = 1.0)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _iinit(-1), _ifini(-1), _istep(-1)
+         _finit(init), _ffini(fini), _fstep(step),
+       {
+               init_class();
+       }
+*/
+
+       Restriction(Kind kind, Numeral num,
+                   double init, double fini, double step = 1)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(""),
+         _init(init), _fini(fini), _step(step)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   const char *unit, double init, double fini, double step = 1.0)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _init(init), _fini(fini), _step(step)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   std::string unit, double init, double fini, double step = 1.0)
+       : _kind(kind), _bounds(B_RANGE), _numeral(num), _unit(unit),
+         _init(init), _fini(fini), _step(step)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   const char *first, ...)
+       : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""),
+         _init(-1), _fini(-1), _step(-1)
+       {
+               _list.push_back(std::string(first));
+
+               va_list ap;
+               va_start(ap, first);
+
+               while (true)
+               {
+                       const char *arg = va_arg(ap, const char *);
+
+                       if (arg == NULL) break;
+
+                       _list.push_back(std::string(arg));
+               }
+               
+               init_class();
+       }
+       
+       Restriction(Kind kind, const char *unit, Numeral num,
+                   const char *first, ...)
+       : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(unit),
+         _init(-1), _fini(-1), _step(-1)
+       {
+               _list.push_back(std::string(first));
+
+               va_list ap;
+               va_start(ap, first);
+
+               while (true)
+               {
+                       const char *arg = va_arg(ap, const char *);
+
+                       if (arg == NULL) break;
+
+                       _list.push_back(std::string(arg));
+               }
+               
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num,
+                   const struct Pair first, ...)
+       : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""),
+         _init(-1), _fini(-1), _step(-1)
+       {
+               _map_from_usr.insert(MapPair(Value(first.pretty), Value(first.value)));
+               _map_from_cfg.insert(MapPair(Value(first.value), Value(first.pretty)));
+
+               va_list ap;
+               va_start(ap, first);
+
+               while (true)
+               {
+                       Pair arg = va_arg(ap, Pair);
+
+                       if (arg.pretty == NULL) break;
+
+                       _map_from_usr.insert(MapPair(Value(arg.pretty), Value(arg.value)));
+                       _map_from_cfg.insert(MapPair(Value(arg.value), Value(arg.pretty)));
+               }
+               
+               init_class();
+       }
+       
+       Restriction(Kind kind, Numeral num, List list)
+       : _kind(kind), _bounds(B_LIST), _numeral(num), _unit(""),
+         _init(-1), _fini(-1), _step(-1), _list(list)
+       {
+               init_class();
+       }
+
+       Restriction(Kind kind, Numeral num, ListMap map)
+       : _kind(kind), _bounds(B_MAPS), _numeral(num), _unit(""),
+         _init(-1), _fini(-1), _step(-1)
+       {
+               for (ListMap::iterator i = map.begin(); i != map.end(); i++)
+               {
+                       _map_from_usr.insert(MapPair(Value((*i).first), Value((*i).second)));
+                       _map_from_cfg.insert(MapPair(Value((*i).second), Value((*i).first)));
+               }
+
+               init_class();
+       }
+
+       Kind      kind()    { return _kind;    };
+       Bounds    bounds()  { return _bounds;  };
+       Numeral   numeral() { return _numeral; };
+
+       Value   unit() { return _unit;    };
+
+       bool  set(Format, Vector &);
+       bool  set(Format, Value &);
+
+       bool  get(Format, Vector &);
+       bool  get(Format, Value &);
+
+       void  allowed(Vector &);
+
+ private:
+       bool  process(Format, const Value &, Value &);
+       bool  unprocess(Format, const Value &, Value &);
+       void  init_class();
+
+       bool  equalNumber(const double, const double);
+
+ protected:
+       Kind      _kind;
+       Bounds    _bounds;
+       Numeral   _numeral;
+
+       Value     _unit;
+
+       double    _init, _fini, _step;
+
+    Map       _map_from_usr,
+                 _map_from_cfg;
+
+       List      _list;
+       
+       Generic   _value;
+};
+
+#endif /* _CONFIG_RESTRICTION_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/section.cpp b/src/mod/endpoints/mod_khomp/commons/configurator/section.cpp
new file mode 100644 (file)
index 0000000..5d26858
--- /dev/null
@@ -0,0 +1,130 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <configurator/section.hpp>
+
+void Section::options(Section::OptionVector & vec)
+{
+       for (OptionMap::iterator it = _options.begin(); it != _options.end();)
+       {
+               vec.push_back(&((*it).second));
+               ++it;
+       }
+}
+
+void Section::sections(Section::SectionVector & vec)
+{
+       for (SectionMap::iterator it = _sections.begin(); it != _sections.end();)
+       {
+               vec.push_back((*it).second);
+               ++it;
+       }
+}
+
+/*********/
+
+Option * Section::option_find(std::string & str, bool recurse)
+{
+       OptionMap::iterator i = _options.find(str);
+
+       if (i == _options.end())
+    {
+        if (!recurse)
+            throw not_found();
+
+        for (SectionMap::iterator i = _sections.begin(); i != _sections.end(); i++)
+        {
+            try
+            {
+                return i->second->option_find(str, recurse);
+            }
+            catch (not_found & e)
+            {
+                /* keep looping! */
+            };
+        }
+
+        throw not_found();
+    }
+
+       return &((*i).second);
+}
+
+Option * Section::option_find(const char * str, bool recurse)
+{
+       std::string sstr(str);
+       return option_find(sstr, recurse);
+}
+
+/*********/
+
+Section * Section::section_find(std::string & str, bool recurse)
+{
+       SectionMap::iterator i = _sections.find(str);
+
+       if (i == _sections.end())
+    {
+        if (!recurse)
+            throw not_found();
+
+        for (SectionMap::iterator i = _sections.begin(); i != _sections.end(); i++)
+        {
+            try
+            {
+                return i->second->section_find(str, recurse);
+            }
+            catch (not_found & e)
+            {
+                /* keep looping! */
+            };
+        }
+
+        throw not_found();
+    }
+
+       return ((*i).second);
+}
+
+Section * Section::section_find(const char * str, bool recurse)
+{
+       std::string sstr(str);
+       return section_find(sstr, recurse);
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/configurator/section.hpp b/src/mod/endpoints/mod_khomp/commons/configurator/section.hpp
new file mode 100644 (file)
index 0000000..fdb7823
--- /dev/null
@@ -0,0 +1,226 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include <string>
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <iostream>
+
+#include <configurator/option.hpp>
+
+#ifndef _CONFIG_SECTION_HPP_
+#define _CONFIG_SECTION_HPP_
+
+struct Section
+{
+       typedef std::map < std::string, Option >   OptionMap;
+       typedef std::vector< Option * >            OptionVector;
+
+       typedef std::map < std::string, Section * > SectionMap;
+       typedef std::vector < Section * >           SectionVector;
+
+       struct not_found {}; /* exception */
+       
+// protected:
+       Section(std::string name, std::string desc, bool recursive = true)
+       : _name(name), _description(desc), _recursive(recursive) {};
+
+       void add(Option o)
+       {
+               _options.insert(std::pair<std::string,Option>(o.name(), o));
+       };
+
+       void del(std::string name)
+       {
+               _options.erase(name);
+       };
+
+       void add(Section *s)
+       {
+               _sections.insert(std::pair<std::string,Section*>(s->name(), s));
+       };
+
+ public:
+       const std::string & name()           { return _name;        };
+       const std::string & description()    { return _description; };
+       const bool                & recursive()      { return _recursive;   };
+
+       OptionMap::iterator option_begin()   { return _options.begin(); };
+       OptionMap::iterator option_end()     { return _options.end();   };
+
+       SectionMap::iterator section_begin() { return _sections.begin(); };
+       SectionMap::iterator section_end()   { return _sections.end();   };
+
+       /**/
+
+       Option  *  option_find(const char *, bool recurse = false);
+       Section * section_find(const char *, bool recurse = false);
+
+       Option  *  option_find(std::string &, bool recurse = false);
+       Section * section_find(std::string &, bool recurse = false);
+
+       /**/
+
+       void options(OptionVector &);
+       void sections(SectionVector &);
+
+       /**/
+
+       template <typename F>
+       bool search_and_apply(std::string &key, std::string &value, F f)
+       {
+               OptionMap::iterator i = _options.find(key);
+
+               if (i != _options.end())
+                       return f((*i).second);
+
+               if (!_recursive)
+                       return false;
+
+               return (find_if(_sections.begin(), _sections.end(), f) != _sections.end());
+       }
+
+ private:
+       struct key_value
+       {
+               key_value(std::string &k, std::string &v): _k(k), _v(v) {};
+               std::string & _k, & _v;
+       };
+
+       struct load_section: protected key_value
+       {
+               load_section(std::string &k, std::string &v): key_value(k,v) {};
+
+               bool operator()(Option &o)                 { return o.load(_v);            };
+               bool operator()(SectionMap::value_type &v) { return v.second->load(_k,_v); };
+       };
+
+       struct change_section: protected key_value
+       {
+               change_section(std::string &k, std::string &v): key_value(k,v) {};
+
+               bool operator()(Option &o)                 { return o.change(_v);            };
+               bool operator()(SectionMap::value_type &v) { return v.second->change(_k,_v); };
+       };
+
+       struct store_section: protected key_value
+       {
+               store_section(std::string &k, std::string &v): key_value(k,v) {};
+
+               bool operator()(Option &o)                 { return o.store(_v);            };
+               bool operator()(SectionMap::value_type &v) { return v.second->store(_k,_v); };
+       };
+
+       struct set_section: protected key_value
+       {
+               set_section(std::string &k, std::string &v): key_value(k,v) {};
+
+               bool operator()(Option &o)                 { return (o.set(_v))[Option::F_ADJUSTED]; };
+               bool operator()(SectionMap::value_type &v) { return  v.second->set(_k,_v);           };
+       };
+
+       struct get_section: protected key_value
+       {
+               get_section(std::string &k, std::string &v): key_value(k,v) {};
+
+               bool operator()(Option &o)                 { return o.get(_v);            };
+               bool operator()(SectionMap::value_type &v) { return v.second->get(_k,_v); };
+       };
+
+       struct modified_section
+       {
+               bool operator()(OptionMap::value_type  &v) { return v.second.modified();  };
+               bool operator()(SectionMap::value_type &v) { return v.second->modified(); };
+       };
+
+ public:
+       bool load(const char * key, std::string value)
+       {
+               std::string skey(key);
+               return search_and_apply(skey, value, load_section(skey, value));
+       }
+
+       bool load(std::string &key, std::string &value)
+       {
+               return search_and_apply(key, value, load_section(key, value));
+       }
+
+       bool change(std::string &key, std::string &value)
+       {
+               return search_and_apply(key, value, change_section(key, value));
+       }
+
+       bool store(std::string &key, std::string &value)
+       {
+               return search_and_apply(key, value, store_section(key, value));
+       }
+
+       bool set(std::string &key, std::string &value)
+       {
+               return search_and_apply(key, value, set_section(key, value));
+       }
+
+       bool get(std::string &key, std::string &value)
+       {
+               return search_and_apply(key, value, get_section(key, value));
+       }
+
+       bool modified()
+       {
+               return ((find_if(_options.begin(), _options.end(), modified_section()) != _options.end()) ||
+                       (find_if(_sections.begin(), _sections.end(), modified_section()) != _sections.end()));
+       }
+
+ private:
+       Section() {};
+
+ protected:
+    std::string       _name;
+       std::string       _description;
+
+    OptionMap         _options;
+    SectionMap        _sections;
+
+    bool              _recursive;
+};
+
+#endif /* _CONFIG_SECTION_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/flagger.hpp b/src/mod/endpoints/mod_khomp/commons/flagger.hpp
new file mode 100644 (file)
index 0000000..49a4add
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <map>
+
+#include <initializer.hpp>
+
+#ifndef _FLAGGER_HPP_
+#define _FLAGGER_HPP_
+
+template < typename Flag >
+struct Flagger
+{
+ protected:
+    struct Bool
+    {
+        Bool():        value(false) {};
+        Bool(bool &v): value(v)     {};
+
+        bool value;
+    };
+
+    typedef std::map< Flag, Bool >  Map;
+
+ public:
+    typedef  Initializer< Flag >  InitFlags;
+
+    Flagger() {};
+
+    Flagger(InitFlags flags)
+    {
+        for (typename InitFlags::iterator i = flags.begin(); i != flags.end(); i++)
+        {
+            Flag & flag = (*i);
+            _map[flag].value = true;
+        };
+    };
+
+    void set(Flag elt, bool value = true)
+    {
+        _map[elt].value = value;
+    }
+
+    bool is_set(Flag elt)
+    {
+        return _map[elt].value;
+    }
+
+    Flagger & operator&(Flag elt)
+    {
+        set(elt);
+        return *this;
+    };
+
+    bool operator[](Flag elt)
+    {
+        return is_set(elt);
+    };
+
+ protected:
+     Map _map;
+};
+
+#endif /* _FLAGGER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/format.cpp b/src/mod/endpoints/mod_khomp/commons/format.cpp
new file mode 100644 (file)
index 0000000..20f7920
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include "format.hpp"
+//#include <iostream>
+
+Format::Format(const char  * format_string, bool raise_exception)
+: _format(format_string), _valid(true), _raise(raise_exception)
+{
+    initialize(format_string);
+}
+
+/*
+Format::Format(std::string & format_string, bool raise_exception)
+: _format(NULL), _valid(true), _raise(raise_exception)
+{
+    initialize(format_string.c_str());
+}
+*/
+
+Format::Format(std::string   format_string, bool raise_exception)
+: _format(format_string), _valid(true), _raise(raise_exception)
+{
+    initialize(format_string.c_str());
+}
+
+void Format::initialize(const char * format_string)
+{
+    std::string txt;
+
+    const char * ptr = format_string;
+
+    while (*ptr != '\0')
+    {
+        if (*ptr != '%')
+        {
+            txt += *ptr;
+            ++ptr;
+            continue;
+        }
+
+        const char * ptr2 = ptr+1;
+
+        if (*ptr2 == '%')
+        {
+            txt += *ptr;
+
+            ptr += 2;
+            continue;
+        }
+
+        if (!txt.empty())
+            push_argument(txt, T_LITERAL);
+
+        std::string arg(1, *ptr);
+
+        ++ptr;
+
+        bool finished = false;
+
+        short long_count = 0;
+        short short_count = 0;
+
+        while(*ptr != '\0' && !finished)
+        {
+            switch (*ptr)
+            {
+                case ' ':
+                    // uncomplete format with ' ', make it a literal.
+                    arg += *ptr;
+                    push_argument(arg, T_LITERAL);
+                    finished = true;
+                    break;
+
+                case '%':
+                    // uncomplete format with '%', make it a literal and start a new format.
+                    push_argument(arg, T_LITERAL);
+                    arg += *ptr;
+                    break;
+
+                case 'h':
+                    short_count = std::min<short>(short_count+1, 2);
+                    long_count = 0;
+                    arg += *ptr;
+                    break;
+
+                case 'l':
+                    long_count = std::min<short>(long_count+1, 2);
+                    short_count = 0;
+                    arg += *ptr;
+                    break;
+
+                case 'd':
+                case 'i':
+                    arg += *ptr;
+                    switch (long_count - short_count)
+                    {
+                        case  2:
+                            push_argument(arg, T_SIGNED_LONG_LONG);
+                            break;
+                        case  1:
+                            push_argument(arg, T_SIGNED_LONG);
+                            break;
+                        case  0:
+                            push_argument(arg, T_SIGNED_INT);
+                            break;
+                        case -1:
+                            push_argument(arg, T_SIGNED_SHORT);
+                            break;
+                        case -2:
+                            push_argument(arg, T_SIGNED_SHORT_SHORT);
+                            break;
+                        default:
+                            break;
+                    }
+                    finished = true;
+                    break;
+
+                case 'o':
+                case 'u':
+                case 'x':
+                case 'X':
+                    arg += *ptr;
+                    switch (long_count - short_count)
+                    {
+                        case  2:
+                            push_argument(arg, T_UNSIGNED_LONG_LONG);
+                            break;
+                        case  1:
+                            push_argument(arg, T_UNSIGNED_LONG);
+                            break;
+                        case  0:
+                            push_argument(arg, T_UNSIGNED_INT);
+                            break;
+                        case -1:
+                            push_argument(arg, T_UNSIGNED_SHORT);
+                            break;
+                        case -2:
+                            push_argument(arg, T_UNSIGNED_SHORT_SHORT);
+                            break;
+                        default:
+                            break;
+                    }
+                    finished = true;
+                    break;
+
+                case 'e':
+                case 'E':
+                case 'f':
+                case 'F':
+                case 'g':
+                case 'G':
+                case 'a':
+                case 'A':
+                    arg += *ptr;
+                    push_argument(arg, T_FLOAT);
+                    finished = true;
+                    break;
+
+                case 'c':
+                    arg += *ptr;
+                    push_argument(arg, T_CHAR);
+                    finished = true;
+                    break;
+
+                case 's':
+                    arg += *ptr;
+                    push_argument(arg, T_STRING);
+                    finished = true;
+                    break;
+
+                case 'p':
+                    arg += *ptr;
+                    push_argument(arg, T_POINTER);
+                    finished = true;
+                    break;
+
+                case 'C':
+                case 'S':
+                case 'm':
+                case 'n': // unsupported for now.
+                    arg += *ptr;
+                    push_argument(arg, T_ANYTHING);
+                    finished = true;
+                    break;
+
+                default:
+                    arg += *ptr;
+                    break;
+            }
+
+            ++ptr;
+        }
+
+        if (!arg.empty())
+            push_argument(arg, T_LITERAL);
+    }
+
+    if (!txt.empty())
+        push_argument(txt, T_LITERAL);
+}
+
+void Format::mark_invalid(std::string & msg)
+{
+    if (_valid)
+    {
+        _valid = false;
+
+        std::string finalmsg;
+
+        finalmsg += "** INVALID FORMAT: ";
+        finalmsg += msg;
+        finalmsg += " **";
+
+        _result = finalmsg;
+    }
+}
+
+void Format::raise_check(void)
+{
+    if (!_valid && _raise)
+        throw InvalidFormat(_result);
+}
+
+bool Format::validity_check(void)
+{
+    raise_check();
+
+    return _valid;
+}
+
+const Format::Argument * Format::next_argument(void)
+{
+//    std::cerr << "size: " << _args.size() << std::endl;
+
+    while (true)
+    {
+//        std::cerr << "loop size: " << _args.size() << std::endl;
+
+        if (_args.empty())
+            return NULL; // throw NoArgumentLeft();
+
+        const Argument & top = _args.front();
+
+        if (top.type() == T_LITERAL)
+        {
+//            std::cerr << "top type == LITERAL, looping..." << std::endl;
+            _result += top.fmts();
+            pop_argument();
+        }
+        else
+        {
+//            std::cerr << "top type: " << top.type() << std::endl;
+            return &top;
+        }
+    }
+}
+
+void Format::pop_argument(void)
+{
+    _args.pop();
+}
+
+void Format::push_argument(std::string & data, Format::Type type)
+{
+//    std::cerr << "pushing type (" << type << ") with format (" << data << ")" << std::endl;
+
+    _args.push(Argument(data, type));
+    data.clear();
+}
+
+std::string Format::str()
+{
+    if (!validity_check())
+        return _result;
+
+    if (next_argument() == NULL)
+        return _result;
+
+    std::string msg;
+
+    msg += "too few arguments passed for format '";
+    msg += _format;
+    msg += "' (";
+    msg += _format;
+    msg += ")";
+
+    mark_invalid(msg);
+
+    return _result;
+}
+
+
diff --git a/src/mod/endpoints/mod_khomp/commons/format.hpp b/src/mod/endpoints/mod_khomp/commons/format.hpp
new file mode 100644 (file)
index 0000000..b1ebe74
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _FORMAT_H_
+#define _FORMAT_H_
+
+#include <cstring>
+#include <cstdlib>
+#include <typeinfo>
+#include <stdexcept>
+#include <string>
+#include <queue>
+#include <iostream>
+#include <stdio.h>
+
+#ifdef WIN32 // WINDOWS
+#include <KHostSystem.h>
+#endif
+
+
+/* macros used for shortening lines and making the code clearer */
+#define STG(x) (x).str()
+#define FMT(x) Format(x)
+
+struct Format
+{
+    static const unsigned int strings_base_length = 64;
+    static const unsigned int generic_base_length = 64;
+
+    struct InvalidFormat
+    {
+        InvalidFormat(std::string msg) : _msg(msg) {}
+
+        std::string _msg;
+    };
+
+    explicit Format(const char  * format_string, bool raise_exception = false);
+    explicit Format(std::string   format_string, bool raise_exception = false);
+
+    void initialize(const char *);
+
+    std::string str(void);
+
+    ////////////////////////////////////////////////////////////
+
+ protected:
+
+    enum Type
+    {
+        T_ANYTHING = 1,
+
+        T_SIGNED_SHORT,
+        T_SIGNED_SHORT_SHORT,
+        T_SIGNED_INT,
+        T_SIGNED_LONG,
+        T_SIGNED_LONG_LONG,
+
+        T_UNSIGNED_SHORT,
+        T_UNSIGNED_SHORT_SHORT,
+        T_UNSIGNED_INT,
+        T_UNSIGNED_LONG,
+        T_UNSIGNED_LONG_LONG,
+
+        T_FLOAT,
+        T_CHAR,
+
+        T_POINTER,
+        T_STRING,
+
+        T_LITERAL
+    };
+
+    struct Argument
+    {
+        Argument(std::string fmts, Type type)
+        : _fmts(fmts), _type(type) {};
+
+        Type                type(void) const { return _type; }
+        const std::string & fmts(void) const { return _fmts; }
+
+     protected:
+        std::string _fmts;
+        Type        _type;
+    };
+
+    typedef std::queue < Argument > ArgumentQueue;
+
+    ////////////////////////////////////////////////////////////
+
+ public:
+
+    template < typename V >
+    Format & operator%( V value )
+    {
+        if (!validity_check())
+            return *this;
+
+        const Argument * top = next_argument();
+
+        if (top == NULL)
+        {
+            std::string msg;
+
+            msg += "too many arguments passed for format '";
+            msg += _format;
+            msg += "'";
+
+            mark_invalid(msg);
+        }
+        else
+        {
+            char temp[generic_base_length];
+
+            if (!generic_verify(value, top->type()))
+            {
+                std::string msg;
+
+                msg += "type mismatch: got type '";
+                msg += typeid(value).name();
+                msg += "' in format '";
+                msg += top->fmts();
+                msg += "' (";
+                msg += _format;
+                msg += ")";
+
+                mark_invalid(msg);
+                return *this;
+            }
+
+            snprintf(temp, sizeof(temp), top->fmts().c_str(), value);
+            _result += temp;
+
+            pop_argument();
+        }
+
+        raise_check();
+        return *this;
+    }
+
+    template < typename V >
+    Format & operator%( V * value )
+    {
+        if (!validity_check())
+            return *this;
+
+        const Argument * top = next_argument();
+
+        if (top == NULL)
+        {
+            std::string msg;
+
+            msg += "too many arguments passed for format '";
+            msg += _format;
+            msg += "'";
+
+            mark_invalid(msg);
+        }
+        else
+        {
+            switch (top->type())
+            {
+                case T_POINTER:
+                {
+                    char temp[generic_base_length];
+                    snprintf(temp, sizeof(temp), top->fmts().c_str(), value);
+                    _result += temp;
+                    break;
+                }
+
+                case T_STRING:
+                {
+                    if ((typeid(const char)          == typeid(V)) ||
+                        (typeid(char)                == typeid(V)) ||
+                        (typeid(const unsigned char) == typeid(V)) ||
+                        (typeid(unsigned char)       == typeid(V)) ||
+                        (typeid(const void)          == typeid(V)) ||
+                        (typeid(void)                == typeid(V)))
+                    {
+                        int len = strlen((const char*)value)+strings_base_length+1;
+
+                        char * temp = new char[len];
+
+                        snprintf(temp, len, top->fmts().c_str(), value);
+                        _result += temp;
+
+                        delete[] temp;
+                    }
+                    else
+                    {
+                        std::string msg;
+
+                        msg += "type mismatch: got type '";
+                        msg += typeid(value).name();
+                        msg += "' in string format (";
+                        msg += _format;
+                        msg += ")";
+
+                        mark_invalid(msg);
+                    }
+                    break;
+                }
+
+                default:
+                {
+                    std::string msg;
+
+                    msg += "type mismatch: got pointer/string type in format '";
+                    msg += top->fmts();
+                    msg += "' (";
+                    msg += _format;
+                    msg += ")";
+
+                    mark_invalid(msg);
+                    break;
+                }
+            }
+
+            pop_argument();
+        }
+
+        raise_check();
+        return *this;
+    }
+
+/*
+    Format & operator%( std::string   value )
+    {
+        return operator%(value);
+    }
+*/
+
+    Format & operator%( const std::string value )
+    {
+        if (!validity_check())
+            return *this;
+
+        const Argument * top = next_argument();
+
+        if (top == NULL)
+        {
+            std::string msg;
+
+            msg += "too many arguments passed for format '";
+            msg += _format;
+            msg += "'";
+
+            mark_invalid(msg);
+        }
+        else
+        {
+            if (top->type() == T_STRING)
+            {
+                int len = value.length()+strings_base_length+1;
+
+                char * temp = new char[len];
+
+                snprintf(temp, len, top->fmts().c_str(), value.c_str());
+                _result += temp;
+
+                delete[] temp;
+            }
+            else
+            {
+                std::string msg;
+
+                msg += "type mismatch: got string type in format '";
+                msg += top->fmts();
+                msg += "' (";
+                msg += _format;
+                msg += ")";
+
+                mark_invalid(msg);
+            }
+
+            pop_argument();
+        }
+
+        raise_check();
+        return *this;
+    }
+
+ protected:
+
+    template < typename V >
+    bool number_verify_signed_short( V value )
+    {
+        return
+           ((typeid(V) == typeid(short int) ||
+             typeid(V) == typeid(short) ||
+             typeid(V) == typeid(const short int) ||
+             typeid(V) == typeid(const short) ||
+             typeid(V) == typeid(volatile short int) ||
+             typeid(V) == typeid(volatile short)) &&
+             sizeof(V) == sizeof(short));
+    }
+
+    template < typename V >
+    bool number_verify_unsigned_short( V value )
+    {
+        return
+           ((typeid(V) == typeid(unsigned short int) ||
+             typeid(V) == typeid(unsigned short) ||
+             typeid(V) == typeid(const unsigned short int) ||
+             typeid(V) == typeid(const unsigned short) ||
+             typeid(V) == typeid(volatile unsigned short int) ||
+             typeid(V) == typeid(volatile unsigned short)) &&
+             sizeof(V) == sizeof(unsigned short));
+    }
+
+    template < typename V >
+    bool number_verify_signed_long( V value )
+    {
+        return
+           ((typeid(V) == typeid(long int) ||
+             typeid(V) == typeid(long) ||
+             typeid(V) == typeid(const long int) ||
+             typeid(V) == typeid(const long) ||
+             typeid(V) == typeid(volatile long int) ||
+             typeid(V) == typeid(volatile long)) &&
+             sizeof(V) == sizeof(long));
+    }
+
+    template < typename V >
+    bool number_verify_unsigned_long( V value )
+    {
+        return
+           ((typeid(V) == typeid(unsigned long int) ||
+             typeid(V) == typeid(unsigned long) ||
+             typeid(V) == typeid(const unsigned long int) ||
+             typeid(V) == typeid(const unsigned long) ||
+             typeid(V) == typeid(volatile unsigned long int) ||
+             typeid(V) == typeid(volatile unsigned long)) &&
+             sizeof(V) == sizeof(long long));
+    }
+
+    template < typename V >
+    bool number_verify_signed_long_long( V value )
+    {
+        return
+           ((typeid(V) == typeid(long long int) ||
+             typeid(V) == typeid(long long) ||
+             typeid(V) == typeid(const long long int) ||
+             typeid(V) == typeid(const long long) ||
+             typeid(V) == typeid(volatile long long) ||
+             typeid(V) == typeid(volatile long long int)) &&
+             sizeof(V) == sizeof(long long));
+    }
+
+    template < typename V >
+    bool number_verify_unsigned_long_long( V value )
+    {
+        return
+           ((typeid(V) == typeid(unsigned long long int) ||
+             typeid(V) == typeid(unsigned long long) ||
+             typeid(V) == typeid(const unsigned long long int) ||
+             typeid(V) == typeid(const unsigned long long) ||
+             typeid(V) == typeid(volatile unsigned long long) ||
+             typeid(V) == typeid(volatile unsigned long long int)) &&
+             sizeof(V) == sizeof(unsigned long long));
+    }
+
+    template < typename V >
+    bool number_verify_signed_int( V value )
+    {
+        return
+            (sizeof(V) <= sizeof(int) ||
+             typeid(V) == typeid(int) ||
+             typeid(V) == typeid(const int) ||
+             typeid(V) == typeid(volatile int));
+    }
+
+    template < typename V >
+    bool number_verify_unsigned_int( V value )
+    {
+        return
+            (sizeof(V) <= sizeof(unsigned int) ||
+             typeid(V) == typeid(unsigned int) ||
+             typeid(V) == typeid(const unsigned int) ||
+             typeid(V) == typeid(volatile unsigned int));
+    }
+
+    template < typename V >
+    bool generic_verify( V value, Type type )
+    {
+        switch (type)
+        {
+            /* EXCEPTION: consider any number an valid input. */
+            case T_SIGNED_INT:
+            case T_UNSIGNED_INT:
+                return
+                    (number_verify_signed_int(value)     ||
+                     number_verify_unsigned_int(value)   ||
+                     number_verify_signed_long(value)    ||
+                     number_verify_unsigned_long(value)  ||
+                     number_verify_signed_short(value)   ||
+                     number_verify_unsigned_short(value));
+
+            case T_SIGNED_SHORT_SHORT:
+                return (typeid(V) == typeid(char) || typeid(V) == typeid(const char));
+
+            case T_SIGNED_SHORT:
+                return number_verify_signed_short(value);
+
+            case T_SIGNED_LONG:
+                return number_verify_signed_long(value);
+
+            case T_SIGNED_LONG_LONG:
+                return number_verify_signed_long_long(value);
+
+            case T_UNSIGNED_SHORT_SHORT:
+                return (typeid(V) == typeid(unsigned char) || typeid(V) == typeid(unsigned char));
+
+            case T_UNSIGNED_SHORT:
+                return number_verify_unsigned_short(value);
+
+            case T_UNSIGNED_LONG:
+                return number_verify_unsigned_long(value);
+
+            case T_UNSIGNED_LONG_LONG:
+                return number_verify_unsigned_long_long(value);
+
+            case T_FLOAT:
+                return (typeid(V) == typeid(float)) || (typeid(V) == typeid(double) ||
+                    typeid(V) == typeid(const float)) || (typeid(V) == typeid(const double));
+
+            case T_CHAR:
+                return (typeid(V) == typeid(char)) || (typeid(V) == typeid(unsigned char) ||
+                    typeid(V) == typeid(const char)) || (typeid(V) == typeid(const unsigned char));
+
+            case T_POINTER:
+            case T_STRING:
+                return false;
+
+            case T_ANYTHING:
+                return true;
+
+            case T_LITERAL:
+                return false;
+        }
+
+        return false;
+    };
+
+    void mark_invalid(std::string &);
+
+    bool validity_check(void);
+    void raise_check(void);
+
+/*
+    struct NoArgumentLeft
+    {
+        NoArgumentLeft(): empty(0) {};
+
+        unsigned int empty;
+    };
+*/
+
+    const Argument * next_argument(void);
+
+    void pop_argument(void);
+    void push_argument(std::string & data, Type type);
+
+ private:
+    std::string   _format;
+
+    bool          _valid;
+    bool          _raise;
+
+    std::string   _result;
+    ArgumentQueue _args;
+};
+
+#endif /* _FORMAT_H_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp b/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.cpp
new file mode 100644 (file)
index 0000000..29169f3
--- /dev/null
@@ -0,0 +1,62 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#include "saved_condition.hpp"
+
+bool SavedCondition::wait(unsigned int msec)
+{
+       bool ret = true;
+
+    switch_mutex_lock(_mutex);
+
+    if (!_signaled)
+       {
+        /* msec * 1000 = The amount of time in microseconds to wait. */
+               if (switch_thread_cond_timedwait(_condition, _mutex, (switch_interval_time_t)msec * 1000) != 0)
+                       ret = false;
+       }
+        
+    _signaled = false;
+
+       switch_mutex_unlock(_mutex);
+
+       return ret;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp b/src/mod/endpoints/mod_khomp/commons/freeswitch/saved_condition.hpp
new file mode 100644 (file)
index 0000000..8acf0f3
--- /dev/null
@@ -0,0 +1,136 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#ifndef _SAVED_CONDITION_
+#define _SAVED_CONDITION_
+
+#include <saved_condition.hpp>
+
+extern "C"
+{
+    #include <switch.h>
+}
+
+struct SavedCondition : public SavedConditionCommon// : public RefCounter < SavedCondition >
+{
+    typedef switch_thread_cond_t  BaseConditionType;
+    typedef switch_mutex_t        BaseMutexType;
+
+     SavedCondition(switch_memory_pool_t *pool=NULL):
+        _pool(pool),
+        _can_delete_pool(false)
+     {
+        if(!_pool)
+        {
+            switch_core_new_memory_pool(&_pool);
+            _can_delete_pool = true;
+        }
+
+        switch_thread_cond_create(&_condition, _pool);
+        switch_mutex_init(&_mutex, SWITCH_MUTEX_DEFAULT, _pool);
+     }
+
+     //SavedCondition(const SavedCondition &);
+    ~SavedCondition()
+    {
+        switch_thread_cond_destroy(_condition);
+        switch_mutex_destroy(_mutex);
+
+        if(_can_delete_pool)
+            switch_core_destroy_memory_pool(&_pool);
+    }
+
+    void signal(void)
+    {
+        switch_mutex_lock(_mutex);
+
+        _signaled = true;
+        switch_thread_cond_signal(_condition);
+
+        switch_mutex_unlock(_mutex);
+    }
+
+    void broadcast(void)
+    {
+        switch_mutex_lock(_mutex);
+
+        _signaled = true;
+        switch_thread_cond_broadcast(_condition);
+
+        switch_mutex_unlock(_mutex);
+    }
+
+    void wait(void)
+    {
+        switch_mutex_lock(_mutex);
+
+        if (!_signaled)
+            switch_thread_cond_wait(_condition, _mutex);
+        
+        _signaled = false;
+
+        switch_mutex_unlock(_mutex);
+    }
+
+    bool wait(unsigned int);
+
+    void reset(void)
+    {
+        switch_mutex_lock(_mutex);
+
+        _signaled = false;
+
+        switch_mutex_unlock(_mutex);
+    }
+
+    BaseMutexType     * mutex()     { return _mutex;     };
+    BaseConditionType * condition() { return _condition; };
+
+ protected:
+
+    BaseConditionType    *_condition;
+    BaseMutexType        *_mutex;
+    switch_memory_pool_t *_pool;
+    bool                 _can_delete_pool;
+};
+
+#endif /* _SAVED_CONDITION_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp b/src/mod/endpoints/mod_khomp/commons/freeswitch/simple_lock.hpp
new file mode 100644 (file)
index 0000000..530d912
--- /dev/null
@@ -0,0 +1,177 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#ifndef _SIMPLE_LOCK_HPP_
+#define _SIMPLE_LOCK_HPP_
+
+#include <simple_lock.hpp>
+
+extern "C"
+{
+    #include <switch.h>
+}
+
+template < typename Implementor >
+struct SimpleLockBasic: public SimpleLockCommon < Implementor >
+{
+    typedef SimpleLockCommon < Implementor >   Super;
+    typedef typename Super::Result            Result;
+
+    typedef switch_mutex_t BaseMutexType;
+
+    SimpleLockBasic(switch_memory_pool_t *pool = NULL)
+    : _pool(pool), _can_delete_pool( (_pool == NULL) )
+
+    {
+        if(!_pool)
+            switch_core_new_memory_pool(&_pool);
+
+        //switch_mutex_init(&_mutex, SWITCH_MUTEX_DEFAULT, _pool);
+        switch_mutex_init(&_mutex, SWITCH_MUTEX_NESTED, _pool);
+    }
+
+    virtual ~SimpleLockBasic()
+    {
+        /* do nothing */
+    };
+    
+    void unreference()
+    {
+        switch_mutex_destroy(_mutex);
+
+        if (_can_delete_pool)
+            switch_core_destroy_memory_pool(&_pool);
+    }
+
+    Result trylock()
+    {
+        switch (switch_mutex_trylock(_mutex))
+        {
+            case SWITCH_STATUS_SUCCESS:
+                return Super::SUCCESS;
+            case SWITCH_STATUS_FALSE:
+            case SWITCH_STATUS_TERM:
+            case SWITCH_STATUS_NOTIMPL:
+            case SWITCH_STATUS_MEMERR:
+            case SWITCH_STATUS_GENERR:
+            case SWITCH_STATUS_SOCKERR:
+            case SWITCH_STATUS_NOTFOUND:
+            case SWITCH_STATUS_UNLOAD:
+            case SWITCH_STATUS_NOUNLOAD:
+            case SWITCH_STATUS_NOT_INITALIZED:
+                return Super::FAILURE;
+            //case SWITCH_STATUS_INUSE:
+            default:
+                return Super::ISINUSE;
+        }
+    }
+
+    void  unlock()
+    {
+        switch_mutex_unlock(_mutex);
+    }
+
+    BaseMutexType * mutex() { return _mutex; };
+
+ protected:
+    BaseMutexType *_mutex;
+    switch_memory_pool_t *_pool;
+    bool _can_delete_pool;
+};
+
+struct SimpleLock: public SimpleLockBasic < SimpleLock >
+{
+    typedef SimpleLockBasic < SimpleLock >   Super;
+    typedef Super::Result                   Result;
+
+    SimpleLock(switch_memory_pool_t *pool = NULL)
+    : Super(pool) {};
+
+    Result lock()
+    {
+        switch (switch_mutex_lock(_mutex))
+        {
+            case SWITCH_STATUS_SUCCESS:
+                return Super::SUCCESS;
+            case SWITCH_STATUS_FALSE:
+            case SWITCH_STATUS_TERM:
+            case SWITCH_STATUS_NOTIMPL:
+            case SWITCH_STATUS_MEMERR:
+            case SWITCH_STATUS_GENERR:
+            case SWITCH_STATUS_SOCKERR:
+            case SWITCH_STATUS_NOTFOUND:
+            case SWITCH_STATUS_UNLOAD:
+            case SWITCH_STATUS_NOUNLOAD:
+            case SWITCH_STATUS_NOT_INITALIZED:
+                return Super::FAILURE;
+            //case SWITCH_STATUS_INUSE:
+            default:
+                return Super::ISINUSE;
+        }
+    }
+};
+
+template < unsigned int Retries = 10, unsigned int Interval = 50 >
+struct SimpleNonBlockLock: public SimpleLockBasic < SimpleNonBlockLock < Retries, Interval > >
+{
+    typedef SimpleLockBasic < SimpleNonBlockLock < Retries, Interval > >   Super;
+    typedef typename Super::Result                                        Result;
+
+    SimpleNonBlockLock(switch_memory_pool_t *pool = NULL)
+    : Super(pool) {};
+
+    inline Result lock()
+    {
+        for (unsigned int i = 0; i < Retries; i++)
+        {
+            Result ret = Super::trylock();
+
+            if (ret != Super::ISINUSE)
+                return ret;
+
+            usleep(Interval * 1000);
+        }
+
+        return Super::ISINUSE;
+    }
+};
+
+#endif /* _SIMPLE_LOCK_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp b/src/mod/endpoints/mod_khomp/commons/freeswitch/thread.hpp
new file mode 100644 (file)
index 0000000..af50240
--- /dev/null
@@ -0,0 +1,327 @@
+/*  
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.  
+  
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or  
+    modify it under the terms of the GNU Lesser General Public  
+    License as published by the Free Software Foundation; either  
+    version 2.1 of the License, or (at your option) any later version.  
+  
+    This library is distributed in the hope that it will be useful,  
+    but WITHOUT ANY WARRANTY; without even the implied warranty of  
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
+    Lesser General Public License for more details.  
+  
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
+  
+*/
+
+#ifndef _THREAD_HPP_
+#define _THREAD_HPP_
+
+#include <thread.hpp>
+
+extern "C"
+{
+    #include <switch.h>
+}
+
+struct Thread : ThreadCommon
+{
+    typedef switch_thread_t BaseThreadType;
+
+    template<typename T, typename R, typename A>
+    struct ThreadData : ThreadDataCommon
+    {
+        ThreadData(T data, A arg) : _data(data), _arg(arg) {}
+
+        int run()
+        {
+            return _data(_arg);
+        }
+
+        T _data;
+        A _arg;
+    };
+    
+    template<typename T, typename R>
+    struct ThreadData < T, R, void > : ThreadDataCommon
+    {
+        ThreadData(T data) : _data(data) {}
+
+        int run()
+        {
+            return _data();
+        }
+
+        T _data;
+    };
+    
+    template<typename T, typename A>
+    struct ThreadData < T, void, A > : ThreadDataCommon
+    {
+        ThreadData(T data, A arg) : _data(data), _arg(arg) {}
+
+        int run()
+        {
+            _data(_arg);
+            return 0;
+        }
+
+        T _data;
+        A _arg;
+    };
+
+
+    template<typename T>
+    struct ThreadData < T, void, void > : ThreadDataCommon
+    {
+        ThreadData(T data) : _data(data) {}
+
+        int run()
+        {
+            _data();
+            return 0;
+        }
+
+        T _data;
+    };
+
+    template<typename T>
+    Thread(T obj, switch_memory_pool_t *pool=NULL) : 
+            _thread_info(new ThreadData<T, typename DecomposeFunction<T>::Return, void>(obj)),
+            _pool(pool),
+            _can_delete_pool(false)
+    {
+        if(!_pool)
+        {
+            switch_core_new_memory_pool(&_pool);
+            _can_delete_pool = true;
+        }
+
+        _thread_info->_thread = this;
+        _thread_info->_self = NULL;
+        _thread_info->_attribute = NULL;
+
+        if(switch_threadattr_create(
+                (switch_threadattr_t **)&_thread_info->_attribute, _pool) != 0)
+        {
+            _thread_info->_attribute = NULL;
+            return;
+        }
+
+        switch_threadattr_stacksize_set(
+                (switch_threadattr_t *)_thread_info->_attribute, 
+                SWITCH_THREAD_STACKSIZE);
+
+        if(!priority())
+        {
+            _thread_info->_attribute = NULL;
+        }
+
+    }
+    
+    template<typename T, typename A>
+    Thread(T obj, A arg, switch_memory_pool_t *pool=NULL) : 
+            _thread_info(new ThreadData<T, typename DecomposeFunction<T>::Return, A>(obj, arg)),
+            _pool(pool),
+            _can_delete_pool(false)
+    {
+        if(!_pool)
+        {
+            switch_core_new_memory_pool(&_pool);
+            _can_delete_pool = true;
+        }
+
+        _thread_info->_thread = this;
+        _thread_info->_self = NULL;
+        _thread_info->_attribute = NULL;
+
+        if(switch_threadattr_create(
+                (switch_threadattr_t **)&_thread_info->_attribute, _pool) != 0)
+        {
+            _thread_info->_attribute = NULL;
+            return;
+        }
+
+        switch_threadattr_stacksize_set(
+                (switch_threadattr_t *)_thread_info->_attribute, 
+                SWITCH_THREAD_STACKSIZE);
+
+        if(!priority())
+        {
+            _thread_info->_attribute = NULL;
+        }
+
+    }
+
+    ~Thread() 
+    {
+        if(_thread_info)
+            delete _thread_info;
+        
+        if (_can_delete_pool)
+            switch_core_destroy_memory_pool(&_pool);
+    }
+
+    void detach(bool d = true)
+    {
+        if(!_thread_info->_attribute)
+            return;
+
+        /* Non-zero if detached threads should be created. */
+        switch_threadattr_detach_set(
+                (switch_threadattr_t *)_thread_info->_attribute, d ? 1 : 0);
+    }
+
+    bool start()
+    {
+        if(!_pool || !_thread_info->_attribute)
+            return false;
+
+        switch_thread_create((switch_thread_t**)&_thread_info->_self, 
+                (switch_threadattr_t *)_thread_info->_attribute, 
+                run, 
+                _thread_info, 
+                _pool);
+
+        if(!_thread_info->_self)
+            return false;
+
+        return true;
+    }
+
+    int join()
+    {
+        /*
+         * block until the desired thread stops executing.
+         * @param retval The return value from the dead thread.
+         * @param thd The thread to join
+         *
+         * SWITCH_DECLARE(switch_status_t) switch_thread_join(switch_status_t *retval, switch_thread_t *thd);
+        */
+       
+        if(!_thread_info->_self)
+            return -2;
+
+        int retval = 0;
+
+        if(switch_thread_join((switch_status_t*)&retval, 
+                (switch_thread_t *)_thread_info->_self) != 0)
+            return -1;
+
+        return retval;
+    }
+
+    BaseThreadType * self()
+    {
+        //switch_thread_self();
+        //apr_os_thread_current();
+        return (BaseThreadType *)_thread_info->_self;
+    }
+
+private:
+    void exit(int status)
+    {
+        /**
+         * stop the current thread
+         * @param thd The thread to stop
+         * @param retval The return value to pass back to any thread that cares
+         */
+        //SWITCH_DECLARE(switch_status_t) switch_thread_exit(switch_thread_t *thd, switch_status_t retval);
+        switch_thread_exit((switch_thread_t *)_thread_info->_self, (switch_status_t)status);
+
+    }
+
+#ifndef WIN32
+    struct apr_threadattr_t {
+        apr_pool_t *pool;
+        pthread_attr_t attr;
+    };
+#endif
+
+    bool priority()
+    {
+#ifndef WIN32
+        struct sched_param param;
+        
+        struct apr_threadattr_t *myattr = (struct apr_threadattr_t *)_thread_info->_attribute;
+
+        if (pthread_attr_setschedpolicy(
+                (pthread_attr_t *)&myattr->attr, SCHED_RR) < 0)
+            return false;
+
+        if (pthread_attr_getschedparam(
+                (pthread_attr_t *)&myattr->attr, &param) < 0)
+            return false;
+
+        param.sched_priority = sched_get_priority_max(SCHED_RR);
+
+        if (pthread_attr_setschedparam(
+                (pthread_attr_t *)&myattr->attr, &param) < 0)
+            return false;
+
+#endif
+        return true;
+
+/*
+        //BUG in Freeswitch
+        if(switch_threadattr_priority_increase(
+                (switch_threadattr_t *)_thread_info->_attribute) != 0)
+            return false;
+
+        return true;
+*/
+    }
+
+
+protected:
+    ThreadDataCommon * _thread_info;
+    switch_memory_pool_t *_pool;
+    bool _can_delete_pool;
+
+protected:
+
+    static void *SWITCH_THREAD_FUNC run(BaseThreadType *thread, void * obj)
+    {
+        //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+        //        "Starting new Thread\n");
+
+        ThreadDataCommon * data = (ThreadDataCommon *)obj;
+        int retval = data->run();
+
+        //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+        //        "Stopping new Thread = %d\n", retval);
+
+        ((Thread *)(data->_thread))->exit(retval);
+
+        return NULL;
+    }
+
+};
+
+
+#endif /* _THREAD_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/function.hpp b/src/mod/endpoints/mod_khomp/commons/function.hpp
new file mode 100644 (file)
index 0000000..c448299
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the "LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <refcounter.hpp>
+
+#ifndef _FUNCTION_HPP_
+#define _FUNCTION_HPP_
+
+namespace Function
+{
+    struct EmptyFunction {};
+
+    /**/
+
+    template < typename FunctionTraits >
+    struct StorageBase: NEW_REFCOUNTER(StorageBase < FunctionTraits >)
+    {
+        typedef typename FunctionTraits::BaseType BaseType;
+
+        typedef typename FunctionTraits::FunType  FunType;
+        typedef typename FunctionTraits::ObjType  ObjType;
+
+        template < typename Functor >
+        StorageBase(Functor f)
+        : _object(reinterpret_cast<ObjType>(new Functor(f))),
+          _function(reinterpret_cast<FunType>(&(Functor::operator()))),
+          _malloced(true)
+        {};
+
+        template < typename Functor >
+        StorageBase(Functor & f, bool malloced)
+        : _object(reinterpret_cast<ObjType>((malloced ? new Functor(f) : &f))),
+          _function(reinterpret_cast<FunType>(&(Functor::operator()))),
+          _malloced(malloced)
+        {};
+
+        StorageBase()
+        : _object(reinterpret_cast<ObjType>(0)),
+          _function(reinterpret_cast<FunType>(0)),
+          _malloced(false)
+        {};
+
+        StorageBase(const StorageBase & o)
+        : INC_REFCOUNTER(o, StorageBase < FunctionTraits >),
+           _object(o._object), _function(o._function), _malloced(o._malloced)
+        {};
+
+        virtual ~StorageBase() {};
+
+        void unreference()
+        {
+            // TODO: will this work if we delete a different type? //
+            if (_malloced)
+                delete _object;
+        };
+
+        template < typename Functor >
+        void operator=(Functor f)
+        {
+            _object   = reinterpret_cast<ObjType>(new Functor(f)),
+            _function = reinterpret_cast<FunType>(&(Functor::operator()));
+            _malloced = false;
+        }
+
+     protected:
+        ObjType _object;
+        FunType _function;
+        bool    _malloced;
+    };
+
+    /**/
+
+    template < typename R >
+    struct VTable0
+    {
+        R operator()(void) { return R(); };
+    };
+
+    template < >
+    struct VTable0< void >
+    {
+        void operator()(void) { return; };
+    };
+
+    template < typename R >
+    struct Function0Traits
+    {
+        typedef VTable0<R> BaseType;
+
+        typedef R (BaseType::* FunType)(void);
+        typedef BaseType *     ObjType;
+    };
+
+    /**/
+
+    template < typename R, typename A0 >
+    struct VTable1
+    {
+        R operator()(A0 a0) { return R(); };
+    };
+
+    template < typename A0 >
+    struct VTable1< void, A0 >
+    {
+        void operator()(A0 a0) { return; };
+    };
+
+    template < typename R, typename A0 >
+    struct Function1Traits
+    {
+        typedef VTable1<R, A0> BaseType;
+
+        typedef R (BaseType::* FunType)(A0);
+        typedef BaseType *     ObjType;
+    };
+
+    /**/
+
+    template < typename R, typename A0, typename A1 >
+    struct VTable2
+    {
+        R operator()(A0 a0, A1) { return R(); };
+    };
+
+    template < typename A0, typename A1 >
+    struct VTable2< void, A0, A1 >
+    {
+        void operator()(A0 a0, A1 a1) { return; };
+    };
+
+    template < typename R, typename A0, typename A1 >
+    struct Function2Traits
+    {
+        typedef VTable2<R, A0, A1> BaseType;
+
+        typedef R (BaseType::* FunType)(A0, A1);
+        typedef BaseType *     ObjType;
+    };
+
+    /**/
+
+    template < typename R, typename A0, typename A1, typename A2 >
+    struct VTable3
+    {
+        R operator()(A0 a0, A1 a1, A2 a2) { return R(); };
+    };
+
+    template < typename A0, typename A1, typename A2 >
+    struct VTable3< void, A0, A1, A2 >
+    {
+        void operator()(A0 a0, A1 a1, A2 a2) { return; };
+    };
+
+    template < typename R, typename A0, typename A1, typename A2 >
+    struct Function3Traits
+    {
+        typedef VTable3<R, A0, A1, A2> BaseType;
+
+        typedef R (BaseType::* FunType)(A0, A1, A2);
+        typedef BaseType *     ObjType;
+    };
+
+    /**/
+
+    template < typename R, typename A0, typename A1, typename A2, typename A3 >
+    struct VTable4
+    {
+        R operator()(A0 a0, A1 a1, A2 a2, A3 a3) { return R(); };
+    };
+
+    template < typename A0, typename A1, typename A2, typename A3 >
+    struct VTable4< void, A0, A1, A2, A3 >
+    {
+        void operator()(A0 a0, A1 a1, A2 a2, A3 a3) { return; };
+    };
+
+    template < typename R, typename A0, typename A1, typename A2, typename A3 >
+    struct Function4Traits
+    {
+        typedef VTable4<R, A0, A1, A2, A3> BaseType;
+
+        typedef R (BaseType::* FunType)(A0, A1, A2, A3);
+        typedef BaseType *     ObjType;
+    };
+
+    /**/
+
+    template < typename R, typename A0 >
+    struct Function0 : public StorageBase < Function0Traits < R > >
+    {
+        typedef StorageBase < Function0Traits < R > >  Storage;
+
+        template < typename Functor >
+        Function0(Functor f): Storage(f) {};
+
+        template < typename Functor >
+        Function0(Functor & f, bool m): Storage(f, m) {};
+
+        Function0() {};
+
+        R operator()(void)
+        {
+            if (reinterpret_cast<void *>(Storage::_object) == 0)
+                throw EmptyFunction();
+
+            return ((Storage::_object)->*(Storage::_function))();
+        }
+    };
+
+    template < typename R, typename A0 >
+    struct Function1 : public StorageBase < Function1Traits < R, A0 > >
+    {
+        typedef StorageBase < Function1Traits < R, A0 > >  Storage;
+
+        template < typename Functor >
+        Function1(Functor f): Storage(f) {};
+
+        template < typename Functor >
+        Function1(Functor & f, bool m): Storage(f, m) {};
+
+        Function1() {};
+
+        R operator()(A0 a0)
+        {
+            if (reinterpret_cast<void *>(Storage::_object) == 0)
+                throw EmptyFunction();
+
+            return ((Storage::_object)->*(Storage::_function))(a0);
+        }
+    };
+
+    template < typename R, typename A0, typename A1 >
+    struct Function2 : public StorageBase < Function2Traits < R, A0, A1 > >
+    {
+        typedef StorageBase < Function2Traits < R, A0, A1 > >  Storage;
+
+        template < typename Functor >
+        Function2(Functor f): Storage(f) {};
+
+        template < typename Functor >
+        Function2(Functor & f, bool m): Storage(f, m) {};
+
+        Function2() {};
+
+        R operator()(A0 a0, A1 a1)
+        {
+            if (reinterpret_cast<void *>(Storage::_object) == 0)
+                throw EmptyFunction();
+
+            return ((Storage::_object)->*(Storage::_function))(a0, a1);
+        }
+    };
+
+    template < typename R, typename A0, typename A1, typename A2 >
+    struct Function3 : public StorageBase < Function3Traits < R, A0, A1, A2 > >
+    {
+        typedef StorageBase < Function3Traits < R, A0, A1, A2 > >  Storage;
+
+        template < typename Functor >
+        Function3(Functor f): Storage(f) {};
+
+        template < typename Functor >
+        Function3(Functor & f, bool m): Storage(f, m) {};
+
+        Function3() {};
+
+        R operator()(A0 a0, A1 a1, A2 a2)
+        {
+            if (reinterpret_cast<void *>(Storage::_object) == 0)
+                throw EmptyFunction();
+
+            return ((Storage::_object)->*(Storage::_function))(a0, a1, a2);
+        }
+    };
+
+    template < typename R, typename A0, typename A1, typename A2, typename A3 >
+    struct Function4 : public StorageBase < Function4Traits < R, A0, A1, A2, A3 > >
+    {
+        typedef StorageBase < Function4Traits < R, A0, A1, A2, A3 > >  Storage;
+
+        template < typename Functor >
+        Function4(Functor f): Storage(f) {};
+
+        template < typename Functor >
+        Function4(Functor & f, bool m): Storage(f, m) {};
+
+        Function4() {};
+
+        R operator()(A0 a0, A1 a1, A2 a2, A3 a3)
+        {
+            if (reinterpret_cast<void *>(Storage::_object) == 0)
+                throw EmptyFunction();
+
+            return ((Storage::_object)->*(Storage::_function))(a0, a1, a2, a3);
+        }
+    };
+};
+
+#endif /* _FUNCTION_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/initializer.hpp b/src/mod/endpoints/mod_khomp/commons/initializer.hpp
new file mode 100644 (file)
index 0000000..e0e110d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <vector>
+
+#ifndef _INITIALIZER_HPP_
+#define _INITIALIZER_HPP_
+
+template < typename Type >
+struct Initializer: public std::vector< Type >
+{
+    typedef std::vector< Type > super;
+
+    Initializer(Type   e) { push_back(e); };
+    Initializer(Type & e) { push_back(e); };
+
+    Initializer & operator&(Initializer v)
+    {
+        insert(super::end(), v.begin(), v.end());
+        return *this;
+    };
+
+    Initializer & operator&(Initializer & v)
+    {
+        insert(super::end(), v.begin(), v.end());
+        return *this;
+    };
+
+    Initializer & operator&(Type v)
+    {
+        insert(super::end(), v);
+        return *this;
+    };
+
+    Initializer & operator&(Type  & v)
+    {
+        insert(super::end(), v);
+        return *this;
+    };
+};
+
+#endif /* _INITIALIZER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/k3lapi.cpp b/src/mod/endpoints/mod_khomp/commons/k3lapi.cpp
new file mode 100644 (file)
index 0000000..f5afa13
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <k3lapi.hpp>
+
+#include <format.hpp>
+#include <verbose.hpp>
+
+K3LAPI::K3LAPI(bool has_exceptions)
+: _has_exceptions(has_exceptions),
+  _device_count(0),  _channel_count(0),  _link_count(0),
+  _device_config(0), _channel_config(0), _link_config(0)
+{};
+
+/* initialize the whole thing! */
+
+void K3LAPI::start(void)
+{
+    /* tie the used k3l to the compiled k3l version */
+    char *ret = k3lStart(k3lApiMajorVersion, k3lApiMinorVersion, 0); //k3lApiBuildVersion);
+
+    if (ret && *ret)
+        throw start_failed(ret);
+
+    /* call init automagically */
+    init();
+}
+
+void K3LAPI::stop(void)
+{
+    k3lStop();
+    fini();
+}
+
+/* envio de comandos para placa */
+
+void K3LAPI::mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index)
+{
+    KMixerCommand mix;
+
+    mix.Track = track;
+    mix.Source = src;
+    mix.SourceIndex = index;
+
+    command(dev, obj, CM_MIXER, (const char *) &mix);
+}
+
+void K3LAPI::mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index)
+{
+    /* estes buffers *NAO PODEM SER ESTATICOS*! */
+    char cmd[] = { 0x3f, 0x03, (char)obj, (char)track, 0xff, 0xff };
+
+    switch (src)
+    {
+        case kmsChannel:
+            cmd[4] = 0x05;
+            cmd[5] = (char)index;
+            break;
+
+        case kmsNoDelayChannel:
+            cmd[4] = 0x0a;
+            cmd[5] = (char)index;
+            break;
+
+        case kmsGenerator:
+            cmd[4] = 0x09;
+
+            switch ((KMixerTone)index)
+            {
+                case kmtSilence:
+                    cmd[5] = 0x0F;
+                    break;
+                case kmtDial:
+                    cmd[5] = 0x08;
+                    break;
+                case kmtBusy:
+                    cmd[5] = 0x0D;
+                    break;
+
+                case kmtFax:
+                case kmtVoice:
+                case kmtEndOf425:
+                case kmtCollect:
+                case kmtEndOfDtmf:
+                    /* TODO: exception, unable to generate */
+                    break;
+            }
+            break;
+
+        case kmsCTbus:
+        case kmsPlay:
+            /* TODO: exception, not implemented! */
+            break;
+    }
+
+    int32 dsp = get_dsp(dev, DSP_AUDIO);
+
+    raw_command(dev, dsp, cmd, sizeof(cmd));
+}
+
+void K3LAPI::mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index)
+{
+    KMixerCommand mix;
+
+    mix.Track = track;
+    mix.Source = src;
+    mix.SourceIndex = index;
+
+    command(dev, obj, CM_MIXER_CTBUS, (const char *) &mix);
+}
+
+void K3LAPI::command(int32 dev, int32 obj, int32 code, std::string & str)
+{
+    command(dev, obj, code, str.c_str());
+}
+
+void K3LAPI::command (int32 dev, int32 obj, int32 code, const char * parms)
+{
+    K3L_COMMAND cmd;
+
+    cmd.Cmd = code;
+    cmd.Object = obj;
+    cmd.Params = (byte *)parms;
+
+    int32 rc = k3lSendCommand(dev, &cmd);
+
+    if (rc != ksSuccess)
+        throw failed_command(code, dev, obj, rc);
+}
+
+void K3LAPI::raw_command(int32 dev, int32 dsp, std::string & str)
+{
+    raw_command(dev, dsp, str.data(), str.size());
+}
+
+void K3LAPI::raw_command(int32 dev, int32 dsp, const char * cmds, int32 size)
+{
+    std::string str(cmds, size);
+
+    int32 rc = k3lSendRawCommand(dev, dsp, (void *)cmds, size);
+
+    if (rc != ksSuccess)
+        throw failed_raw_command(dev, dsp, rc);
+}
+
+KLibraryStatus K3LAPI::get_param(K3L_EVENT *ev, const char *name, std::string &res)
+{
+    char tmp_param[256];
+    memset((void*)tmp_param, 0, sizeof(tmp_param));
+
+    int32 rc = k3lGetEventParam (ev, (sbyte *)name, (sbyte *)tmp_param, sizeof(tmp_param)-1);
+
+    if (rc != ksSuccess)
+        return (KLibraryStatus)rc;
+
+    res.append(tmp_param, strlen(tmp_param));
+    return ksSuccess;
+}
+
+std::string K3LAPI::get_param(K3L_EVENT *ev, const char *name)
+{
+    std::string res;
+
+    KLibraryStatus rc = get_param(ev, name, res);
+
+    if (rc != ksSuccess)
+        throw get_param_failed(name, rc);
+
+    return res;
+}
+
+void K3LAPI::init(void)
+{
+    if (_device_count != 0) return;
+
+    _device_count = k3lGetDeviceCount();
+
+    _device_type    = new KDeviceType[_device_count];
+    _device_config  = new device_conf_type[_device_count];
+    _channel_config = new channel_ptr_conf_type[_device_count];
+    _link_config    = new link_ptr_conf_type[_device_count];
+    _channel_count  = new unsigned int[_device_count];
+    _link_count     = new unsigned int[_device_count];
+
+    for (unsigned int dev = 0; dev < _device_count; dev++)
+    {
+        KLibraryStatus ret = ksSuccess;
+
+        _device_type[dev] = (KDeviceType) k3lGetDeviceType(dev);
+
+        /* caches each device config */
+        ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoDevice + dev, &(_device_config[dev]), sizeof(_device_config[dev]));
+
+        if (ret != ksSuccess)
+            throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d): %s") % dev % Verbose::status(ret)));
+
+        /* adjust channel/link count for device */
+        _channel_count[dev] = _device_config[dev].ChannelCount;
+        _link_count[dev] = _device_config[dev].LinkCount;
+
+        /* caches each channel config */
+        _channel_config[dev] = new channel_conf_type[_channel_count[dev]];
+
+        for (unsigned int obj = 0; obj < _channel_count[dev]; obj++)
+        {
+            ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoChannel + obj, &(_channel_config[dev][obj]), sizeof(_channel_config[dev][obj]));
+
+            if (ret != ksSuccess)
+                throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d,chan=%d): %s") % dev % obj % Verbose::status(ret)));
+        }
+
+        /* adjust link count for device */
+        _link_count[dev] = _device_config[dev].LinkCount;
+
+        /* caches each link config */
+        _link_config[dev] = new link_conf_type[_link_count[dev]];
+
+        for (unsigned int obj = 0; obj < _link_count[dev]; obj++)
+        {
+            ret = (KLibraryStatus)k3lGetDeviceConfig(dev, ksoLink + obj, &(_link_config[dev][obj]), sizeof(_link_config[dev][obj]));
+
+            if (ret != ksSuccess)
+                throw start_failed(STG(FMT("k3lGetDeviceConfig(dev=%d,link=%d): %s") % dev % obj % Verbose::status(ret)));
+        }
+    }
+}
+
+void K3LAPI::fini(void)
+{
+    for (unsigned int dev = 0; dev < _device_count; dev++)
+    {
+        if (_channel_config[dev])
+        {
+            delete[] _channel_config[dev];
+            _channel_config[dev] = NULL;
+        }
+
+        if (_link_config[dev])
+        {
+            delete[] _link_config[dev];
+            _link_config[dev] = NULL;
+        }
+    }
+
+    _device_count = 0;
+
+    if (_device_type)    { delete[] _device_type;       _device_type = NULL; }
+    if (_device_config)  { delete[] _device_config;   _device_config = NULL; }
+    if (_channel_config) { delete[] _channel_config; _channel_config = NULL; }
+    if (_link_config)    { delete[] _link_config;       _link_config = NULL; }
+    if (_channel_count)  { delete[] _channel_count;   _channel_count = NULL; }
+    if (_link_count)     { delete[] _link_count;         _link_count = NULL; }
+}
+
+int32 K3LAPI::get_dsp(int32 dev, K3LAPI::DspType type)
+{
+    switch (device_type(dev))
+    {
+        case kdtFXO:
+        case kdtFXOVoIP:
+#if K3L_AT_LEAST(1,6,0)
+        case kdtGSM:
+        case kdtGSMSpx:
+#endif
+#if K3L_AT_LEAST(2,1,0)
+        case kdtGSMUSB:
+        case kdtGSMUSBSpx:
+#endif
+            return 0;
+
+        default:
+            return (type == DSP_AUDIO ? 1 : 0);
+    }
+}
+
diff --git a/src/mod/endpoints/mod_khomp/commons/k3lapi.hpp b/src/mod/endpoints/mod_khomp/commons/k3lapi.hpp
new file mode 100644 (file)
index 0000000..5965484
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <string>
+
+#include <k3l.h>
+
+/* if using full k3l.h (for softpbx), version already defined. */
+#ifndef k3lApiMajorVersion
+# include <k3lVersion.h>
+#endif
+
+#ifdef __GNUC_PREREQ
+#if __GNUC_PREREQ(4,3)
+#include <cstring>
+#endif
+#endif
+
+#include <types.hpp>
+
+#ifndef _K3LAPI_HPP_
+#define _K3LAPI_HPP_
+
+struct K3LAPI
+{
+    /* exceptions */
+
+    struct start_failed
+    {
+        start_failed(const char * _msg) : msg(_msg) {};
+        start_failed(std::string  _msg) : msg(_msg) {};
+        std::string msg;
+    };
+
+    struct failed_command
+    {
+        failed_command(int32 _code, unsigned short _dev, unsigned short _obj, int32 _rc)
+        : code(_code), dev(_dev), obj(_obj), rc(_rc) {};
+
+        int32           code;
+        unsigned short  dev;
+        unsigned short  obj;
+        int32           rc;
+    };
+
+    struct failed_raw_command
+    {
+        failed_raw_command(unsigned short _dev, unsigned short _dsp, int32 _rc)
+        : dev(_dev), dsp(_dsp), rc(_rc) {};
+
+        unsigned short  dev;
+        unsigned short  dsp;
+        int32           rc;
+    };
+
+    struct invalid_device
+    {
+        invalid_device(int32 _device)
+        : device(_device) {};
+
+        int32 device;
+    };
+
+    struct invalid_channel
+    {
+        invalid_channel(int32 _device, int32 _channel)
+        : device(_device), channel(_channel) {};
+
+        int32 device, channel;
+    };
+
+    struct invalid_link
+    {
+        invalid_link(unsigned int _device, unsigned int _link)
+        : device(_device), link(_link) {};
+
+        int32 device, link;
+    };
+
+    struct get_param_failed
+    {
+        get_param_failed(std::string _name, int32 _rc)
+        : name(_name), rc((KLibraryStatus)_rc) {};
+
+        std::string name;
+        KLibraryStatus rc;
+    };
+
+    typedef K3L_DEVICE_CONFIG          device_conf_type;
+    typedef K3L_CHANNEL_CONFIG        channel_conf_type;
+    typedef K3L_CHANNEL_CONFIG *  channel_ptr_conf_type;
+    typedef K3L_LINK_CONFIG              link_conf_type;
+    typedef K3L_LINK_CONFIG *        link_ptr_conf_type;
+
+    /* constructors/destructors */
+
+             K3LAPI(bool has_exceptions = false);
+    virtual ~K3LAPI() {};
+
+    /* (init|final)ialize the whole thing! */
+
+    void start(void);
+    void stop(void);
+
+    /* verificacao de intervalos */
+
+    inline bool valid_device(int32 dev)
+    {
+        return (dev >= 0 && dev < ((int32)_device_count));
+    }
+
+    inline bool valid_channel(int32 dev, int32 obj)
+    {
+        return (valid_device(dev) && obj >= 0 && obj < ((int32)_channel_count[dev]));
+    }
+
+    inline bool valid_link(int32 dev, int32 obj)
+    {
+        return (valid_device(dev) && obj >= 0 && obj < ((int32)_link_count[dev]));
+    }
+
+    /*!
+      \brief High level object identifier
+      Since Khomp works with an object concept, this is used to map the
+      object id with its proper type.
+     */
+    struct target
+    {
+        /*! The types a target can have */
+        typedef enum { DEVICE, CHANNEL, MIXER, LINK } target_type;
+
+        target(K3LAPI & k3lapi, target_type type_init, int32 device_value, int32 object_value)
+        : type(type_init),
+          device((unsigned short)device_value),
+          object((unsigned short)object_value)
+        {
+            switch (type_init)
+            {
+                case DEVICE:
+                    if (!k3lapi.valid_device(device_value))
+                        throw invalid_device(device_value);
+                    break;
+
+                case CHANNEL:
+                case MIXER:
+                    if (!k3lapi.valid_channel(device_value, object_value))
+                        throw invalid_channel(device_value, object_value);
+                    break;
+
+                case LINK:
+                    if (!k3lapi.valid_link(device_value, object_value))
+                        throw invalid_link(device_value, object_value);
+                    break;
+            }
+
+        };
+
+        const target_type type;
+
+        const unsigned short device;
+        const unsigned short object;
+    };
+
+    /* envio de comandos para placa (geral) */
+
+    void raw_command(int32 dev, int32 dsp, std::string & str);
+    void raw_command(int32 dev, int32 dsp, const char * cmds, int32 size);
+
+    /* obter dados 'cacheados' (geral) */
+
+    inline unsigned int device_count(void)
+    {
+        return _device_count;
+    }
+
+    /* envio de comandos para placa (sem identificadores) */
+
+    void mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index);
+    void mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index);
+    void mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index);
+
+    void command (int32 dev, int32 obj, int32 code, std::string & str);
+    void command (int32 dev, int32 obj, int32 code, const char * parms = NULL);
+
+    /* obter dados 'cacheados' (sem identificadores) */
+
+    inline unsigned int channel_count(int32 dev)
+    {
+        if (!valid_device(dev))
+        {
+            if (_has_exceptions)
+                throw invalid_device(dev);
+            else
+                return 0;
+        }
+
+        return _channel_count[dev];
+    }
+
+    inline unsigned int link_count(int32 dev)
+    {
+        if (!valid_device(dev))
+        {
+            if (_has_exceptions)
+                throw invalid_device(dev);
+            else
+                return 0;
+        }
+
+        return _link_count[dev];
+    }
+
+    inline uint32 channel_stats(int32 dev, int32 obj, uint32 index)
+    {
+        if (!valid_channel(dev, obj))
+        {
+            if (_has_exceptions)
+                throw invalid_channel(dev, obj);
+            else
+                return 0;
+        }
+
+        uint32 res_value = (uint32)-1;
+        stt_code stt_res = ksFail;
+
+#if K3L_AT_LEAST(2,1,0)
+        stt_res = k3lGetChannelStats(dev, obj, index, &res_value);
+#endif
+
+        if(stt_res != ksSuccess)
+        {
+            return (uint32)-1;
+        }
+
+        return res_value;
+    }
+
+    KDeviceType device_type(int32 dev)
+    {
+        if (!valid_device(dev))
+        {
+            if (_has_exceptions)
+                throw invalid_device(dev);
+            else
+                return kdtDevTypeCount;
+        }
+
+        return _device_type[dev];
+    }
+
+
+    K3L_DEVICE_CONFIG & device_config(int32 dev)
+    {
+        if (!valid_device(dev))
+            throw invalid_device(dev);
+
+        return _device_config[dev];
+    }
+
+    K3L_CHANNEL_CONFIG & channel_config(int32 dev, int32 obj)
+    {
+        if (!valid_channel(dev, obj))
+            throw invalid_channel(dev, obj);
+
+        return _channel_config[dev][obj];
+    }
+
+    K3L_LINK_CONFIG & link_config(int32 dev, int32 obj)
+    {
+        if (!valid_link(dev, obj))
+            throw invalid_channel(dev, obj);
+
+        return _link_config[dev][obj];
+    }
+
+    /* envio de comandos para placa (com identificadores) */
+
+    void mixer(target & tgt, byte track, KMixerSource src, int32 index)
+    {
+        mixer((int32)tgt.device, (int32)tgt.object, track, src, index);
+    }
+
+    void mixerRecord(target & tgt, byte track, KMixerSource src, int32 index)
+    {
+        mixerRecord((int32)tgt.device, (int32)tgt.object, track, src, index);
+    }
+
+    void mixerCTbus(target & tgt, byte track, KMixerSource src, int32 index)
+    {
+        mixerCTbus((int32)tgt.device, (int32)tgt.object, track, src, index);
+    }
+
+    void command (target & tgt, int32 code, std::string & str)
+    {
+        command((int32)tgt.device, (int32)tgt.object, code, str);
+    };
+
+    void command (target & tgt, int32 code, const char * parms = NULL)
+    {
+        command((int32)tgt.device, (int32)tgt.object, code, parms);
+    };
+
+    /* obter dados 'cacheados' (com indentificadores) */
+
+    inline unsigned int channel_count(target & tgt)
+    {
+        return _channel_count[tgt.device];
+    }
+
+    inline unsigned int link_count(target & tgt)
+    {
+        return _link_count[tgt.device];
+    }
+
+    KDeviceType device_type(target & tgt)
+    {
+        return _device_type[tgt.device];
+    }
+
+
+    K3L_DEVICE_CONFIG & device_config(target & tgt)
+    {
+        return _device_config[tgt.device];
+    }
+
+    K3L_CHANNEL_CONFIG & channel_config(target & tgt)
+    {
+        return _channel_config[tgt.device][tgt.object];
+    }
+
+    K3L_LINK_CONFIG & link_config(target & tgt)
+    {
+        return _link_config[tgt.device][tgt.object];
+    }
+
+    /* pega valores em strings de eventos */
+
+    KLibraryStatus get_param(K3L_EVENT *ev, const char *name, std::string &res);
+    std::string get_param(K3L_EVENT *ev, const char *name);
+
+    /* inicializa valores em cache */
+
+    void init(void);
+    void fini(void);
+
+    /* utilidades diversas e informacoes */
+
+    enum DspType
+    {
+        DSP_AUDIO,
+        DSP_SIGNALING,
+    };
+
+    int32 get_dsp(int32, DspType);
+
+ protected:
+
+    const bool           _has_exceptions;
+
+    unsigned int           _device_count;
+    unsigned int *        _channel_count;
+    unsigned int *           _link_count;
+
+         device_conf_type *   _device_config;
+    channel_ptr_conf_type *  _channel_config;
+       link_ptr_conf_type *     _link_config;
+              KDeviceType *     _device_type;
+};
+
+#endif /* _K3LAPI_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/k3lutil.cpp b/src/mod/endpoints/mod_khomp/commons/k3lutil.cpp
new file mode 100644 (file)
index 0000000..83ac82e
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <k3lutil.hpp>
+
+std::string K3LUtil::channelStatus(int32 dev, int32 channel,
+        Verbose::Presentation fmt)
+{
+    try
+    {
+        K3L_CHANNEL_CONFIG & config = _k3lapi.channel_config(dev, channel);
+        K3L_CHANNEL_STATUS   status;
+
+        KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus (dev,
+                channel + ksoChannel, &status, sizeof(status));
+
+        switch (ret)
+        {
+            case ksSuccess:  return Verbose::channelStatus(config.Signaling,
+                    status.AddInfo, fmt);
+            default:         return (fmt == Verbose::EXACT ? "<unknown[fail]>"
+                                                            : "Unknown (fail)");
+        }
+    }
+    catch(K3LAPI::invalid_channel & e)
+    {
+        return (fmt == Verbose::EXACT ? "<unknown[fail]>" : "Unknown (fail)");
+    }
+}
+
+std::string K3LUtil::callStatus(int32 dev, int32 channel,
+        Verbose::Presentation fmt)
+{
+    K3L_CHANNEL_STATUS status;
+
+    KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus(dev,
+            channel + ksoChannel, &status, sizeof(status));
+
+    switch (ret)
+    {
+        case ksSuccess:  return Verbose::callStatus(status.CallStatus, fmt);
+        default:         return (fmt == Verbose::EXACT ? "<unknown[fail]>"
+                                                        : "Unknown (fail)");
+    }
+}
+
+std::string K3LUtil::linkStatus(int32 dev, int32 link,
+        Verbose::Presentation fmt, KSignaling sig)
+{
+    try
+    {
+        if (sig == ksigInactive)
+        {
+            K3L_LINK_CONFIG & config = _k3lapi.link_config(dev, link);
+            sig = config.Signaling;
+        }
+
+               K3L_LINK_STATUS   status;
+
+        KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus (dev,
+                link + ksoLink, &status, sizeof(status));
+
+        switch (ret)
+        {
+            case ksSuccess:  return Verbose::linkStatus(sig, status.E1, fmt);
+            default:         return (fmt == Verbose::EXACT ?
+                                "<unknown[failure]>" : "Unknown (failure)");
+        }
+    }
+    catch(K3LAPI::invalid_channel & e)
+    {
+        return (fmt == Verbose::EXACT ? "<unknown[failure]>"
+                                        : "Unknown (failure)");
+    }
+}
+
+std::string K3LUtil::getLinkStatus(int32 dev, int32 link,
+            Verbose::Presentation fmt)
+{
+    switch (_k3lapi.device_type(dev))
+    {
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXS:
+        case kdtFXSSpx:
+            return linkStatus(dev, link, fmt, ksigAnalogTerminal);
+
+#if K3L_AT_LEAST(2,1,0)
+        case kdtE1FXSSpx:
+            if (link == 1)
+                return linkStatus(dev, link, fmt, ksigAnalogTerminal);
+#endif
+#endif
+        default:
+            break;
+    }
+
+    K3L_LINK_CONFIG & conf = _k3lapi.link_config(dev, link);
+
+    std::string res = linkStatus(dev, link, fmt);
+
+    if (conf.ReceivingClock & 0x01)
+       res += (fmt == Verbose::EXACT ? ",sync" : " (sync)");
+
+    return res;
+}
+
+unsigned int K3LUtil::physicalLinkCount(int32 dev, bool count_virtual)
+{
+    unsigned int number = 0;
+
+    try
+    {
+        switch (_k3lapi.device_type(dev))
+        {
+#if K3L_AT_LEAST(1,6,0)
+            case kdtFXS:
+                number = (count_virtual ? (_k3lapi.channel_count(dev) < 50 ? 1 : 2) : 0);
+                break;
+
+            case kdtFXSSpx:
+                number = (count_virtual ? (_k3lapi.channel_count(dev) < 30 ? 1 : 2) : 0);
+                break;
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+            case kdtE1FXSSpx:
+                number = (count_virtual ? 2 : 1);
+                break;
+#endif
+
+            /* E1 boards */
+            case kdtE1:
+            case kdtE1Spx:
+            case kdtE1IP:
+                number = _k3lapi.link_count(dev);
+                break;
+
+            case kdtPR:
+            case kdtE1GW:
+                number = 1;
+                break;
+
+#if K3L_AT_LEAST(1,6,0)
+            case kdtFXO:
+            case kdtFXOVoIP:
+            case kdtGSM:
+            case kdtGSMSpx:
+#else
+            case kdtFX:
+            case kdtFXVoIP:
+#endif
+            case kdtConf:
+            case kdtGWIP:
+#if K3L_AT_LEAST(2,1,0)
+            case kdtGSMUSB:
+            case kdtGSMUSBSpx:
+            case kdtReserved1:    // just to avoid warnings.
+            case kdtDevTypeCount: // just to avoid warnings.
+#endif
+                number = 0;
+                break;
+        }
+    }
+    catch(K3LAPI::invalid_device & e)
+    {
+        return 0;
+    }
+
+    return number;
+}
+
+
+K3LUtil::ErrorCountType K3LUtil::linkErrorCount(int32 dev, int32 link,
+        Verbose::Presentation fmt)
+{
+    ErrorCountType          result;
+    K3L_LINK_ERROR_COUNTER  status;
+
+    KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus (dev,
+            link + ksoLinkMon, &status, sizeof(status));
+
+    switch (ret)
+    {
+        case ksSuccess:
+            for (unsigned int i = klecChangesToLock; i < klecCount; i++)
+            {
+                result.push_back(ErrorCountPairType(Verbose::linkErrorCounter
+                        ((KLinkErrorCounter)i, fmt), status.ErrorCounters[i]));
+            }
+            /* fall */
+
+        default:
+            return result;
+    }
+}
+
diff --git a/src/mod/endpoints/mod_khomp/commons/k3lutil.hpp b/src/mod/endpoints/mod_khomp/commons/k3lutil.hpp
new file mode 100644 (file)
index 0000000..e547f3d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <string>
+#include <utility>
+#include <list>
+
+#include <k3lapi.hpp>
+#include <verbose.hpp>
+
+#ifndef _K3LUTIL_HPP_
+#define _K3LUTIL_HPP_
+
+struct K3LUtil
+{
+    typedef std::pair < std::string, unsigned int > ErrorCountPairType;
+    typedef std::list < ErrorCountPairType >        ErrorCountType;
+
+    K3LUtil(K3LAPI & k3lapi): _k3lapi(k3lapi) {};
+
+    std::string callStatus(int32 dev, int32 channel,
+            Verbose::Presentation fmt = Verbose::HUMAN);
+
+    std::string channelStatus(int32, int32,
+            Verbose::Presentation fmt = Verbose::HUMAN);
+
+    std::string linkStatus(int32, int32,
+            Verbose::Presentation fmt = Verbose::HUMAN,
+            KSignaling sig = ksigInactive);
+
+    std::string getLinkStatus(int32, int32, 
+            Verbose::Presentation fmt = Verbose::HUMAN);
+
+    unsigned int physicalLinkCount(int32 dev, bool count_virtual = false);
+
+    ErrorCountType linkErrorCount(int32, int32,
+            Verbose::Presentation fmt = Verbose::HUMAN);
+
+ protected:
+    K3LAPI & _k3lapi;
+};
+
+#endif /* _K3LUTIL_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/logger.hpp b/src/mod/endpoints/mod_khomp/commons/logger.hpp
new file mode 100644 (file)
index 0000000..6fcf7bf
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <map>
+#include <string>
+#include <iostream>
+
+#include <tagged_union.hpp>
+#include <format.hpp>
+#include <refcounter.hpp>
+#include <flagger.hpp>
+
+#if defined(COMMONS_LIBRARY_USING_ASTERISK)
+extern "C"
+{
+    #include <asterisk/localtime.h>
+}
+#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER)
+extern "C"
+{
+    #include <callweaver/localtime.h>
+}
+#elif defined(COMMONS_LIBRARY_USING_FREESWITCH)
+extern "C"
+{
+    #include <time.h>
+}
+#endif
+/*
+
+********************************************************************************
+***************************** 'Logger' user manual *****************************
+********************************************************************************
+
+* Description:
+
+This class does the management of log messages for applications. It works with
+the following axioms:
+
+<*> There are several class of messages.
+<*> There are some outputs, which may be files, sockets, or a console device.
+<*> There are options for classes, for outputs and for the association of both.
+
+The last rule also shows the order in which options are processed: first the
+'classes' options are processed, then 'output' options are processed, and then
+the options for the tuple '(class, output)' are processed.
+
+The options are mapped like this:
+
+  <class-of-message>                  -> options [prefix, flags]
+  <output-sink>                       -> options [prefix]
+( <class-of-message>, <output-sink> ) -> options [prefix, flags]
+
+ - "prefix" means a fixed string prefix before the real message.
+ - "flags" means auxiliary flags (DATETIME, THREADID) which are
+   used to add information based on OS or process context info.
+
+* Example of use:
+
+typedef enum
+{
+    C_DBG_FUNC,
+    C_DBG_LOCK,
+    C_WARNING,
+    C_ERROR,
+    C_CLI,
+}
+AstClassId;
+
+typedef enum
+{
+    F_CONSOLE,
+    F_GENERIC,
+    F_TRACE,
+}
+AstOutputId;
+
+// used to indicate the console log //
+struct AstConsoleLog {};
+
+struct AstPrinter: public Logger::DefaultPrinter
+{
+    typedef Logger::DefaultPrinter Super;
+
+    using namespace Tagged;
+
+    using Super::operator()(int);
+
+    // just 2 type of descriptors //
+    typedef Union < int, Union < AstConsoleLog > > Container;
+
+    ast_printer(std::string & msg): Super(msg) {};
+
+    bool operator()(const AstConsoleLog & log)
+    {
+        ast_console_puts(_msg.c_str());
+        return true;
+    };
+
+#if 0
+    bool operator()(int log)
+    {
+        return Super::operator()(log);
+    };
+#endif
+};
+
+bool start_log()
+{
+    typedef Logger::Manager<AstClassId, AstOutputId, AstPrinter, SimpleLock> LogManager;
+
+    LogManager logger;
+
+    // shortcut definition //
+    typedef LogManager::Option LogOption;
+
+    FILE * log_file = fopen( "output.log", "a");
+
+    if (!log_file)
+        return false;
+
+    logger.add( F_CONSOLE, AstConsoleLog(), "chan_khomp: ");
+    logger.add( F_GENERIC, log_file);
+
+    logger.classe( C_WARNING )
+        & LogOption(F_CONSOLE, "WARNING: ", LogOption::Flags(LogOption::Flag(LogOption::DATETIME)))
+        & LogOption(F_GENERIC, "W: ", LogOption::Flags(LogOption::Flag(LogOption::DATETIME)))
+
+    logger.classe( C_DBG_LOCK ).enabled(false);
+
+    logger.classe( C_DBG_LOCK )
+        & LogOption(F_GENERIC, "L: ", LogOption::Flags
+            (LogOption::flag_type(LogOption::ENABLED) &
+             LogOption::flag_type(LogOption::DATETIME))
+
+    logger(C_WARNING, "eu sou uma mensagem de warning");
+
+    logger.classe(C_WARNING).set(F_GENERIC, LogOption::ENABLED, true);
+    logger.classe(C_WARNING).set(F_CONSOLE, LogOption::ENABLED, false);
+
+    logger.classe(C_CLI).prefix("<K>");
+
+    return true;
+}
+
+void message_the_user(int fd)
+{
+    logger(C_CLI, fd, "eu sou uma mensagem de cli!");
+    logger(C_WARNING, "eu sou um warning");
+}
+
+********************************************************************************
+********************************************************************************
+
+Now, the code..!
+
+*/
+
+#ifndef _LOGGER_HPP_
+#define _LOGGER_HPP_
+
+#include <tagged_union.hpp>
+
+struct Logger
+{
+    /*** a base struct for printing messages in many ways ***/
+
+    struct DefaultPrinter
+    {
+        typedef Tagged::Union < int, Tagged::Union < FILE *, Tagged::Union < std::ostream * > > >  BaseType;
+
+        typedef bool ReturnType;
+
+        DefaultPrinter(std::string & msg): _msg(msg) {};
+
+        bool operator()(std::ostream * out)
+        {
+            (*out) << _msg;
+            out->flush();
+
+            return out->good();
+        }
+
+        bool operator()(FILE * out)
+        {
+            if (fputs(_msg.c_str(), out) < 0)
+                return false;
+
+            if (fflush(out) < 0)
+                return false;
+
+            return true;
+        }
+
+        bool operator()(int out)
+        {
+#ifndef KWIN32
+            return (write(out, _msg.c_str(), _msg.size()) == (int)_msg.size());
+#else
+            // no need for file descriptors on windows
+            return false;
+#endif
+        }
+
+        std::string & msg() { return _msg; }
+
+     protected:
+        std::string & _msg;
+    };
+
+    /*** manage the printing of messages ***/
+
+    template <class ClassId, class OutputId, class Printer, class LockType>
+    struct Manager
+    {
+        typedef  typename Printer::BaseType       BaseType;
+
+     protected:
+         /* holds a stream, and an optimal message prefix */
+        struct OutputOptions
+        {
+            OutputOptions(BaseType & stream, std::string & prefix)
+            : _stream(stream), _prefix(prefix) {};
+
+            BaseType     _stream;
+            std::string  _prefix;
+            LockType     _lock;
+        };
+
+        typedef  std::map < OutputId, OutputOptions > OutputMap;
+
+     public:
+
+        /* print in a specific 'message class' */
+        struct ClassType
+        {
+            ClassType(void)
+            : _enabled(true)
+            {};
+
+//            ClassType(ClassType & o)
+//            : _stream_map(o._stream_map), _prefix(o.prefix),
+//              _lock(o._lock),_enabled(o._enabled)
+//            {};
+
+            /* initializes the options of the (class, stream) pair */
+            struct Option
+            {
+                typedef enum { ENABLED, DATETIME, THREADID, DATETIMEMS } EnumType;
+
+                typedef Flagger< EnumType >             Flags;
+                typedef typename Flags::InitFlags   InitFlags;
+
+                Option(OutputId output, const char * prefix,
+                       Flags flags = InitFlags(ENABLED))
+                : _output(output), _prefix(prefix), _flags(flags) {};
+
+                Option(OutputId output, std::string prefix,
+                       Flags flags = InitFlags(ENABLED))
+                : _output(output), _prefix(prefix), _flags(flags) {};
+
+                Option(OutputId output,
+                    Flags flags = InitFlags(ENABLED))
+                : _output(output), _flags(flags) {};
+
+                OutputId     _output;
+                std::string  _prefix;
+                Flags        _flags;
+            };
+
+         protected:
+
+             /* holds a prefix and a activation status */
+            struct OptionContainer
+            {
+                OptionContainer(std::string prefix, typename Option::Flags flags)
+                : _prefix(prefix), _flags(flags) {};
+
+                std::string            _prefix;
+                typename Option::Flags _flags;
+            };
+
+            typedef std::multimap < OutputId, OptionContainer > OptionMap;
+
+            /* utility function for printing */
+            bool print(std::string & msg, BaseType & stream, LockType & lock)
+            {
+                lock.lock();
+
+                Printer p(msg);
+                bool ret = stream.visit(p);
+
+                lock.unlock();
+
+                return ret;
+            };
+
+/*
+            bool print(std::string & msg, BaseType & stream, LockType & lock)
+            {
+                lock.lock();
+
+                Printer p(msg);
+                bool ret = stream.visit(p);
+
+                lock.unlock();
+
+                return ret;
+            };
+*/
+
+         public:
+            ClassType & operator&(const Option & value)
+            {
+                add(value._output, value._prefix, value._flags);
+                return *this;
+            }
+
+            void add(OutputId output_id, std::string prefix,
+                typename Option::Flags      flags)
+            {
+                typedef std::pair < OutputId, OptionContainer > pair_type;
+                _stream_map.insert(pair_type(output_id, OptionContainer(prefix, flags)));
+            }
+
+            /* get and set methods for active mode */
+            void set(OutputId id, typename Option::EnumType flag, bool value = true)
+            {
+                typename OptionMap::iterator iter = _stream_map.find(id);
+
+                if (iter == _stream_map.end())
+                    return;
+
+                (*iter).second._flags.set(flag, value);
+            }
+
+            bool get(OutputId idx, typename Option::EnumType flag)
+            {
+                typename OptionMap::iterator iter = _stream_map.find(idx);
+
+                if (iter == _stream_map.end())
+                    return false;
+
+                return (*iter).second._flags.is_set(flag);
+            }
+
+            /* get/adjust the enable/disable value for the class */
+            void  enabled(bool enabled) { _enabled = enabled; };
+            bool  enabled()             { return _enabled;    };
+
+            /* get/adjust the classe prefix */
+            void          prefix(const char  * prefix) { _prefix = prefix; }
+            void          prefix(std::string & prefix) { _prefix = prefix; }
+            std::string & prefix()                     { return _prefix;   }
+
+            /* printing function (operator, actually) */
+            bool operator()(OutputMap & out_map, std::string & msg)
+            {
+                if (!_enabled)
+                    return true;
+
+                typedef typename OptionMap::iterator Iter;
+
+                bool ret = true;
+
+                for (Iter iter = _stream_map.begin(); iter != _stream_map.end(); iter++)
+                {
+                    OptionContainer & opt = (*iter).second;
+
+                    if (!opt._flags[Option::ENABLED])
+                        continue;
+
+                    typename OutputMap::iterator out_iter = out_map.find((*iter).first);
+
+                    /* this stream have been added already? if not, skip! */
+                    if (out_iter == out_map.end())
+                        continue;
+
+                    /* final message */
+                    std::string out_msg;
+
+                    if (opt._flags[Option::DATETIME])
+                    {
+#if defined(COMMONS_LIBRARY_USING_ASTERISK)
+#if ASTERISK_AT_LEAST(1,6,0)
+                        struct timeval tv;
+                        struct ast_tm  lt;
+
+                        gettimeofday(&tv, NULL);
+
+#else
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+#endif
+
+#if ASTERISK_AT_LEAST(1,4,5)
+                        ast_localtime (&tv, &lt, NULL);
+#else
+                        localtime_r (&tv, &lt);
+#endif
+
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour
+                            % lt.tm_min % lt.tm_sec);
+
+#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER)
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+
+                        localtime_r (&tv, &lt);
+
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour
+                            % lt.tm_min % lt.tm_sec);
+
+#elif defined(COMMONS_LIBRARY_USING_FREESWITCH)
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+
+                        localtime_r (&tv, &lt);
+
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour
+                            % lt.tm_min % lt.tm_sec);
+
+#endif
+                    }
+
+                    if (opt._flags[Option::DATETIMEMS])
+                    {
+#if defined(COMMONS_LIBRARY_USING_ASTERISK)
+#if ASTERISK_AT_LEAST(1,6,0)
+                        struct timeval tv;
+                        struct ast_tm  lt;
+
+                        gettimeofday(&tv, NULL);
+
+#else
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+#endif
+
+#if ASTERISK_AT_LEAST(1,4,5)
+                        ast_localtime (&tv, &lt, NULL);
+#else
+                        localtime_r (&tv, &lt);
+#endif
+
+#if ASTERISK_AT_LEAST(1,6,0)
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min
+                            % lt.tm_sec % (tv.tv_usec / 1000));
+#else
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min
+                            % lt.tm_sec % (tv * 1000));
+#endif
+
+#elif defined(COMMONS_LIBRARY_USING_CALLWEAVER)
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+
+                        localtime_r (&tv, &lt);
+
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min
+                            % lt.tm_sec % (tv * 1000));
+
+#elif defined(COMMONS_LIBRARY_USING_FREESWITCH)
+                        time_t      tv;
+                        struct tm   lt;
+
+                        time (&tv);
+
+                        localtime_r (&tv, &lt);
+
+                        out_msg += STG(FMT("[%04d-%02d-%02d %02d:%02d:%02d:%04d] ")
+                            % (lt.tm_year + 1900) % (lt.tm_mon + 1) % lt.tm_mday % lt.tm_hour % lt.tm_min
+                            % lt.tm_sec % (tv * 1000));
+
+#endif
+                    }
+
+                    OutputOptions & out_opt = (*out_iter).second;
+
+                    if (opt._flags[Option::THREADID])
+                    {
+#if defined (COMMONS_LIBRARY_USING_ASTERISK) || defined(COMMONS_LIBRARY_USING_CALLWEAVER) || defined(COMMONS_LIBRARY_USING_FREESWITCH)
+                        out_msg += STG(FMT("t=%08p ") % ((void*)pthread_self()));
+#endif
+                    }
+
+                    out_msg += _prefix;
+                    out_msg += out_opt._prefix;
+                    out_msg += opt._prefix;
+                    out_msg += msg;
+                    out_msg += "\n";
+
+                    ret |= print(out_msg, out_opt._stream, out_opt._lock);
+                }
+
+                return ret;
+            }
+
+            bool operator()(BaseType & stream, std::string & msg)
+            {
+                std::string final_msg;
+
+                final_msg += _prefix;
+                final_msg += msg;
+                final_msg += "\n";
+
+                return print(final_msg, stream, _lock);
+            }
+
+         protected:
+            OptionMap    _stream_map;
+            std::string  _prefix;
+            LockType     _lock;
+            bool         _enabled;
+        };
+
+        /* util declaration */
+        typedef typename ClassType::Option  Option;
+
+        /* class_id_type -> ClassType mapper */
+        typedef std::map < ClassId, ClassType >  ClassMap;
+
+        /* local option pair */
+        typedef std::pair < OutputId, OutputOptions >  OutputOptionPair;
+
+        void add(OutputId output, BaseType stream, const char * prefix = "")
+        {
+            std::string str_prefix(prefix);
+
+            _output_map.insert(OutputOptionPair(output, OutputOptions(stream, str_prefix)));
+        }
+
+        void add(OutputId output, BaseType stream, std::string prefix)
+        {
+            _output_map.insert(OutputOptionPair(output, OutputOptions(stream, prefix)));
+        }
+
+        ClassType & classe(ClassId classeid)
+        {
+            return _classe_map[classeid];
+        }
+
+        bool operator()(ClassId classeid, const char * msg)
+        {
+            std::string str_msg(msg);
+            return _classe_map[classeid](_output_map, str_msg);
+        }
+
+        bool operator()(ClassId classeid, std::string & msg)
+        {
+            return _classe_map[classeid](_output_map, msg);
+        }
+
+        bool operator()(ClassId classeid, Format fmt)
+        {
+            std::string str_fmt = STG(fmt);
+            return _classe_map[classeid](_output_map, str_fmt);
+        }
+
+        bool operator()(ClassId classeid, BaseType stream, const char * msg)
+        {
+            std::string str_msg(msg);
+            return _classe_map[classeid](stream, str_msg);
+        }
+
+        bool operator()(ClassId classeid, BaseType stream, std::string & msg)
+        {
+            return _classe_map[classeid](stream, msg);
+        }
+
+        bool operator()(ClassId classeid, BaseType stream, Format fmt)
+        {
+            std::string str_fmt = STG(fmt);
+            return _classe_map[classeid](stream, str_fmt);
+        }
+
+     protected:
+        ClassMap   _classe_map;
+        OutputMap  _output_map;
+    };
+
+ private:
+    Logger();
+};
+
+#endif /* _LOGGER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/noncopyable.hpp b/src/mod/endpoints/mod_khomp/commons/noncopyable.hpp
new file mode 100644 (file)
index 0000000..d32faa8
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _NONCOPYABLE_HPP_
+#define _NONCOPYABLE_HPP_
+
+struct NonCopyable
+{
+    NonCopyable() {};
+ private:
+    NonCopyable(NonCopyable const &)             { };
+    NonCopyable & operator=(NonCopyable const &) { return *this; };
+};
+
+#endif /* _NONCOPYABLE_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/refcounter.hpp b/src/mod/endpoints/mod_khomp/commons/refcounter.hpp
new file mode 100644 (file)
index 0000000..6ba8ae8
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the "LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/* This struct uses static polymorphism, and derived classes should implement *
+ * the "unreference()" method, which should release all resources when called */
+
+#ifndef _REFCOUNTER_HPP_
+#define _REFCOUNTER_HPP_
+
+#define NEW_REFCOUNTER(...)    public ReferenceCounter< __VA_ARGS__ >
+#define INC_REFCOUNTER(o, ...) ReferenceCounter< __VA_ARGS__ >(static_cast< const ReferenceCounter < __VA_ARGS__ > & >(o))
+
+#include <stdlib.h>
+
+#include <noncopyable.hpp>
+#include <atomic.hpp>
+
+#ifdef DEBUG
+# include <iostream>
+#endif
+
+struct ReferenceData: public NonCopyable
+{
+    ReferenceData()
+    : _data_count(1)
+    {};
+
+    inline unsigned int increment(void)
+    {
+        if (!_data_count)
+            abort();
+
+        Atomic::doAdd(&_data_count);
+
+        return _data_count;
+    }
+
+    inline unsigned int decrement(void)
+    {
+        if (!_data_count)
+            abort();
+
+        Atomic::doSub(&_data_count);
+        return _data_count;
+    }
+
+    volatile unsigned int _data_count;
+};
+
+template < typename T >
+struct ReferenceCounter
+{
+    typedef T Type;
+
+    ReferenceCounter(bool create_counter = true)
+    : _reference_count(0)
+    {
+        reference_restart(create_counter);
+
+#ifdef DEBUG
+        std::cerr <<  ((void*)this) << ": ReferenceCounter() [ref_count="
+            << (_reference_count ? (*_reference_count) : -1) << "]" << std::endl;
+#endif
+    };
+
+    ReferenceCounter(const ReferenceCounter & o)
+    : _reference_count(0)
+    {
+        reference_reflect(o);
+
+#ifdef DEBUG
+        std::cerr << ((void*)this) << ": ReferenceCounter(" << ((void*)(&o)) << ") [ref_count="
+            << (_reference_count ? (*_reference_count) : -1) << "]" << std::endl;
+#endif
+    };
+
+    virtual ~ReferenceCounter()
+    {
+#ifdef DEBUG
+        std::cerr << ((void*)this) << ": ~ReferenceCounter() [ref_count="
+            << (_reference_count ? (*_reference_count) : -1) << "]" << std::endl;
+#endif
+        reference_disconnect(_reference_count);
+    }
+
+    ReferenceCounter & operator=(const ReferenceCounter & o)
+    {
+        reference_reflect(o);
+
+#ifdef DEBUG
+        std::cerr << ((void*)this) << ": ReferenceCounter::operator=(" << ((void*)(&o)) << ") [ref_count="
+            << (_reference_count ? (*_reference_count) : -1) << "]" << std::endl;
+#endif
+
+        return *this;
+    };
+
+ protected:
+    inline void reference_restart(bool create_counter = false)
+    {
+        ReferenceData * oldref = _reference_count;
+
+        _reference_count = (create_counter ? new ReferenceData() : 0);
+
+        if (oldref) reference_disconnect(oldref);
+    }
+
+    inline void reference_reflect(const ReferenceCounter & other)
+    {
+        ReferenceData * newref = other._reference_count;
+        ReferenceData * oldref = _reference_count;
+
+        /* NOTE: increment before, avoid our reference being zero, even *
+         *       for a short period of time.                            */
+
+        if (newref) newref->increment();
+
+        _reference_count = newref;
+
+        if (oldref) reference_disconnect(oldref);
+    };
+
+    inline void reference_disconnect(ReferenceData *& counter)
+    {
+        if (counter)
+        {
+            unsigned int result = counter->decrement();
+
+            if (!result)
+            {
+                static_cast< Type * >(this)->unreference();
+                delete counter;
+            }
+
+            counter = 0;
+        }
+    };
+
+  private:
+    ReferenceData * _reference_count;
+};
+
+template < typename T >
+struct ReferenceContainer: NEW_REFCOUNTER(ReferenceContainer< T >)
+{
+    /* type */
+    typedef T Type;
+
+    /* shorthand */
+    typedef ReferenceCounter < ReferenceContainer< Type > > Counter;
+
+    // TODO: make this a generic exception someday
+    struct NotFound {};
+
+    ReferenceContainer()
+    : Counter(false),
+      _reference_value(0)
+    {};
+
+    ReferenceContainer(Type * value)
+    : _reference_value(value)
+    {};
+
+    ReferenceContainer(const ReferenceContainer & value)
+    : Counter(false),
+      _reference_value(0)
+    {
+        operator()(value);
+    };
+
+    virtual ~ReferenceContainer()
+    {};
+
+    ReferenceContainer operator=(const ReferenceContainer & value)
+    {
+        operator()(value);
+        return *this;
+    };
+
+    /**/
+
+    void unreference()
+    {
+        if (_reference_value)
+        {
+            delete _reference_value;
+            _reference_value = 0;
+        }
+    }
+
+    // simulates a copy constructor
+    void operator()(const ReferenceContainer & value)
+    {
+        Counter::reference_reflect(value);
+
+        _reference_value = const_cast<Type *>(value._reference_value);
+    };
+
+    // shortcut for operator below
+    void operator=(const Type * value)
+    {
+        operator()(value);
+    };
+
+    // accept value (pointer)!
+    void operator()(const Type * value)
+    {
+         Counter::reference_restart((value != 0));
+
+        _reference_value = const_cast<Type *>(value);
+    };
+
+    // return value (pointer)!
+    Type * operator()(void)
+    {
+        return _reference_value;
+    };
+
+  protected:
+    Type * _reference_value;
+
+  protected:
+};
+
+#endif /* _REFCOUNTER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/regex.cpp b/src/mod/endpoints/mod_khomp/commons/regex.cpp
new file mode 100644 (file)
index 0000000..61f941c
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <regex.hpp>
+
+#include <string.h>
+
+void Regex::Expression::initialize(void)
+{
+    unsigned int tmplen = strlen(_expression);
+
+    bool extflag = (_flags & E_EXTENDED);
+
+    for (unsigned int i = 0; i < tmplen; ++i)
+    {
+        switch (_expression[i])
+        {
+            case '\\':
+                ++i;
+
+                if (!extflag && i < tmplen)
+                    if (_expression[i] == '(')
+                        ++_subcounter;
+
+                break;
+
+            case '(':
+                if (extflag)
+                    ++_subcounter;
+
+            default:
+                break;
+        }
+    }
+
+    _errorstate = regcomp(&_comp_regex, _expression, _flags);
+}
+
+std::string Regex::Expression::regerror_as_string(void)
+{
+    unsigned int count = regerror(_errorstate, &_comp_regex, 0, 0) + 1;
+
+    char * msg = new char[count];
+
+    regerror(_errorstate, &_comp_regex, msg, count);
+
+    std::string tmp(msg, count);
+
+    delete[] msg;
+
+    return tmp;
+}
+
+void Regex::Match::initialize(void)
+{
+    if (_expression.valid())
+    {
+        _subcounter = (_expression.subcount() + 2); // 0 + N.. + invalid
+        _submatches = new regmatch_t[_subcounter];
+        _have_match = (regexec(_expression.repr(), _basestring.c_str(),
+            _subcounter, _submatches, _flags) == 0);
+    }
+}
+
+std::string Regex::Match::replace(std::string rep, unsigned int index)
+{
+    ReplaceMap tmp;
+    tmp.insert(ReplacePair(index,rep));
+    return replace(tmp);
+}
+
+std::string Regex::Match::replace(Regex::ReplaceMap & map)
+{
+    if (!_have_match)
+        return _basestring;
+
+    std::string buffer = _basestring;
+
+    try
+    {
+        if (_submatches[0].rm_so != 0 && (map.find(0) != map.end()))
+            return _basestring.replace(_submatches[0].rm_so, _submatches[0].rm_eo - _submatches[0].rm_so, map.find(0)->second);
+
+        for (unsigned int n = 1; (_submatches[n].rm_so != -1) && (n < _subcounter); n++)
+        {
+            //// s    f RRR s f RRR s    f RRRR s  f
+            //// XXXYYY(ZZZ)AAA(BBB)CCCEEE(FFFF)GGGG
+
+            bool globalsubs = false;
+
+            if (map.find(n) == map.end())
+            {
+                if (map.find(UINT_MAX) == map.end())
+                    continue;
+
+                globalsubs = true;
+            }
+
+            buffer = buffer.replace(_submatches[n].rm_so,
+                _submatches[n].rm_eo - _submatches[n].rm_so,
+                map.find((globalsubs ? UINT_MAX : n))->second);
+        }
+    }
+    catch (std::out_of_range e)
+    {
+        return "";
+    }
+
+    return buffer;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/regex.hpp b/src/mod/endpoints/mod_khomp/commons/regex.hpp
new file mode 100644 (file)
index 0000000..daf2014
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <string.h>
+#include <regex.h>
+
+#include <iostream>
+#include <string>
+#include <stdexcept>
+#include <map>
+
+#include <refcounter.hpp>
+#include <noncopyable.hpp>
+
+#ifndef _REGEX_HPP_
+#define _REGEX_HPP_
+
+struct Regex
+{
+    enum
+    {
+        E_EXTENDED         = REG_EXTENDED,
+        E_IGNORE_CASE      = REG_ICASE,
+        E_NO_SUB_MATCH     = REG_NOSUB,
+        E_EXPLICIT_NEWLINE = REG_NEWLINE,
+    };
+
+    enum
+    {
+        M_NO_BEGIN_OF_LINE    = REG_NOTBOL,
+        M_NO_END_OF_LINE      = REG_NOTEOL,
+    };
+
+    enum
+    {
+        /* mark replace for full match (submatch "0"). */
+        REP_BASE             = 0u,
+        /* mark global string for replace. */
+        REP_ALL              = UINT_MAX,
+    };
+
+    typedef std::pair < unsigned int, std::string >    ReplacePair;
+    typedef std::map  < unsigned int, std::string >     ReplaceMap;
+
+    struct Expression : public NonCopyable
+    {
+        Expression(const char * expression, unsigned int flags = 0)
+        :  _expression(expression), _alloced(false),
+           _subcounter(0), _errorstate(INT_MAX), _flags(flags)
+        {
+            initialize();
+        }
+
+        Expression(std::string & expression, unsigned int flags = 0)
+        :  _expression(strdup(expression.c_str())), _alloced(true),
+           _subcounter(0), _errorstate(INT_MAX), _flags(flags)
+        {
+            initialize();
+        }
+
+        ~Expression()
+        {
+            if (_errorstate != INT_MAX)
+                regfree(&_comp_regex);
+
+            if (_alloced)
+            {
+                delete _expression;
+                _expression = 0;
+            }
+        }
+
+        bool               valid(void) { return (_errorstate == 0); }
+
+        unsigned int    subcount(void) { return  _subcounter; }
+        const regex_t *     repr(void) { return &_comp_regex; }
+
+        std::string error(void)
+        {
+            switch (_errorstate)
+            {
+                case 0:       return "";
+                case INT_MAX: return "uninitialized";
+                default:      return regerror_as_string();
+            }
+        }
+
+     private:
+        void                initialize(void);
+        std::string regerror_as_string(void);
+
+     protected:
+        const char   * _expression;
+        bool           _alloced;
+
+        unsigned int   _subcounter;
+
+        int            _errorstate;
+        regex_t        _comp_regex;
+
+        unsigned int   _flags;
+    };
+
+    struct Match: NEW_REFCOUNTER(Match)
+    {
+        Match(const char * basestring, Expression & expression, unsigned int flags = 0)
+        : _basestring(basestring), _expression(expression), _subcounter(0), _submatches(0),
+           _have_match(false), _flags(flags)
+        {
+            initialize();
+        }
+
+        Match(std::string & basestring, Expression & expression, unsigned int flags = 0)
+        : _basestring(basestring), _expression(expression), _subcounter(0), _submatches(0),
+          _have_match(false), _flags(flags)
+        {
+            initialize();
+        }
+
+        Match(const Match & o)
+        : INC_REFCOUNTER(o, Match),
+          _basestring(o._basestring), _expression(o._expression),
+          _subcounter(o._subcounter), _submatches(o._submatches),
+          _have_match(o._have_match), _flags(o._flags)
+        {
+        }
+
+        void unreference()
+        {
+            delete[] _submatches;
+        }
+
+        bool matched(void)
+        {
+            return _have_match;
+        }
+
+        bool matched(unsigned int number)
+        {
+            if (_have_match && number < _subcounter)
+                return (_submatches[number].rm_so != -1);
+
+            return false;
+        }
+
+        std::string submatch(int number)
+        {
+            if (!matched(number))
+                return "";
+
+            return _basestring.substr(_submatches[number].rm_so,
+                _submatches[number].rm_eo - _submatches[number].rm_so);
+        }
+
+        /**
+        * \brief gets a map with all matches
+        * \return std::map<int,std::string> with all matches
+        * \note index 0 in map, is the complete string
+        * \author Eduardo Nunes Pereira
+        *
+        * If fails the empty map is returned
+        */
+        std::map<int, std::string> obtain_match_map()
+        {
+            int match_counter = 0;
+            std::map<int,std::string> tmp_map;
+            while(matched(match_counter))
+            {
+                tmp_map.insert(std::make_pair(match_counter,submatch(match_counter)));
+                match_counter++;
+            }
+
+            return tmp_map;
+        }
+
+        /**
+        * \brief replaces strings matched by parentesis
+        * \param each item of the vector is a parentesis replaced
+        * \return string replaced
+        * \note The overload method match only one string in parentesis.
+        * \author Eduardo Nunes Pereira
+        *
+        * If fails the empty string is returned.
+        */
+        std::string replace(ReplaceMap &);
+        std::string replace(std::string, unsigned int index = REP_BASE);
+
+        std::string operator[](int number)
+        {
+            return submatch(number);
+        }
+
+        // NOTE: there is already a way to get subcount defined on EXPRESSION class!
+
+     private:
+        void initialize(void);
+
+     protected:
+        std::string    _basestring;
+        Expression   & _expression;
+
+        unsigned int   _subcounter;
+        regmatch_t   * _submatches;
+
+        bool           _have_match;
+        unsigned int   _flags;
+    };
+};
+
+#endif /* _REGEX_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp b/src/mod/endpoints/mod_khomp/commons/ringbuffer.cpp
new file mode 100644 (file)
index 0000000..428bd29
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <ringbuffer.hpp>
+
+/********** BUFFER FUNCTIONS **********/
+
+/* writes everything or nothing */
+bool Ringbuffer_traits::traits_provide(char * buffer, const char * value, unsigned int amount, bool skip_overwrite)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int reader = cache.reader.complete;
+    const unsigned int writer = cache.writer.complete;
+
+    const unsigned int dest = cache.writer.complete - 1;
+
+    const bool reader_less = cache.reader.complete < cache.writer.complete;
+
+    if (amount >= _size)
+        return false;
+
+    bool ret = true;
+
+    /* should we go around the buffer for writing? */
+    if (((writer + amount) > _size) && (reader_less || !skip_overwrite))
+    {
+        /* Documentation of the formula used in the 'if' below.
+         *
+         * [0|1|2|3|4|5|6|7] => size=8
+         *      |   |
+         *  reader  |
+         *         writer
+         *
+         * => writer has places [5,6,7,0,1] to write (5 places).
+         *
+         * =>  8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5
+         *
+         * > writer goes 1 up, amount goes 1 down.
+         * > reader goes 1 up, amount goes 1 up.
+         * > size goes 1 down, amount goes 1 down.
+         *
+         */
+
+        if ((_size - (writer - reader + 1)) <= amount)
+        {
+            if (skip_overwrite)
+                return false;
+
+            do
+            {
+                Buffer_pointer extra(cache.reader);
+                extra.complete = (extra.complete + amount) % _size;
+
+                if (update(cache.reader, extra))
+                    break;
+            }
+            while (true);
+
+            ret = false;
+        }
+
+        unsigned int wr1 = _size - writer + 1; /* writer is already 1 position after */
+        unsigned int wr2 = amount - wr1;
+
+//        fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer);
+
+        /* two partial writes (one at the end, another at the beginning) */
+        memcpy((void *) &(buffer[dest]), (const void *)  (value),      _block * wr1);
+        memcpy((void *)  (buffer),       (const void *) &(value[wr1]), _block * wr2);
+    }
+    else
+    {
+        if (!reader_less && ((reader - writer) <= amount))
+        {
+            if (skip_overwrite)
+                return false;
+
+            do
+            {
+                Buffer_pointer extra(cache.reader);
+                extra.complete = (extra.complete + amount) % _size;
+
+                if (update(cache.reader, extra))
+                    break;
+            }
+            while (true);
+
+            ret = false;
+        }
+
+//        fprintf(stderr, "%p> full write: a=%d/s=%d [r=%d/w=%d]\n", this, amount, _size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        memcpy((void *) &(buffer[dest]), (const void *) value, _block * amount);
+    }
+
+    _pointers.writer.complete = ((dest + amount) % _size) + 1;
+    _pointers.writer.partial  = 1;
+
+//    fprintf(stderr, "%p> write end: %d [block=%d]\n", this, writer, _block);
+
+    return ret;
+}
+
+/* returns the number of itens that have been read */
+unsigned int Ringbuffer_traits::traits_consume(const char * buffer, char * value, unsigned int amount, bool atomic_mode)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int writer = _pointers.writer.complete;
+    const unsigned int reader = _pointers.reader.complete;
+
+    const bool writer_less = writer < reader;
+
+    unsigned int total = 0;
+
+    /* should we go around the buffer for reading? */
+    if (writer_less && (reader + amount >= _size))
+    {
+        total = std::min(_size - (reader - writer + 1), amount);
+
+        if ((total == 0) || (atomic_mode && (total < amount)))
+            return 0;
+
+        unsigned int rd1 = _size - reader;
+        unsigned int rd2 = total - rd1;
+
+//        fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer);
+
+        /* two partial consumes (one at the end, another at the beginning) */
+        memcpy((void *)  (value),      (const void *) &(buffer[reader]), _block * rd1);
+        memcpy((void *) &(value[rd1]), (const void *)  (buffer),         _block * rd2);
+    }
+    else
+    {
+        total = std::min((!writer_less ? writer - (reader + 1) : amount), amount);
+
+        if ((total == 0) || (atomic_mode && (total < amount)))
+            return 0;
+
+//        fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        memcpy((void *) value, (const void *) &(buffer[reader]), _block * total);
+    }
+
+    do
+    {
+        /* jump the reader forward */
+        Buffer_pointer index((cache.reader.complete + total) % _size);
+
+        if (update(cache.reader, index))
+            break;
+    }
+    while (true);
+
+//    fprintf(stderr, "%p> read end: %d [block=%d]\n", this, reader, _block);
+
+    return total;
+}
+
+/********** TWO-PHASE BUFFER FUNCTIONS ***********/
+
+/* returns the number of itens that have been read */
+unsigned int Ringbuffer_traits::traits_consume_begins(const char * buffer, char * value, unsigned int amount, bool atomic_mode)
+{
+    Buffer_table cache = _pointers;
+
+    /* avoid using different values */
+    const unsigned int reader = cache.reader.complete;
+    const unsigned int writer = cache.writer.complete;
+
+    const bool writer_less = writer < reader;
+
+    unsigned int total = 0;
+
+    /* should we go around the buffer for reading? */
+    if (writer_less && (reader + amount >= _size))
+    {
+        total = std::min(_size - (reader - writer + 1), amount);
+
+        if ((total == 0) || (atomic_mode && (total < amount)))
+            return 0;
+
+        unsigned int rd1 = _size - reader;
+        unsigned int rd2 = total - rd1;
+
+//        fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer);
+
+        /* two partial consumes (one at the end, another at the beginning) */
+        memcpy((void *)  (value),      (const void *) &(buffer[reader]), _block * rd1);
+        memcpy((void *) &(value[rd1]), (const void *)  (buffer),         _block * rd2);
+    }
+    else
+    {
+        total = std::min((!writer_less ? writer - (reader + 1) : amount), amount);
+
+        if ((total == 0) || (atomic_mode && (total < amount)))
+            return 0;
+
+//        fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        memcpy((void *) value, (const void *) &(buffer[reader]), _block * total);
+    }
+
+//    fprintf(stderr, "%p> read end: %d [%d]\n", this, _reader, _reader_partial);
+
+    return total;
+}
+
+bool Ringbuffer_traits::traits_consume_commit(unsigned int amount)
+{
+       /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+       const unsigned int writer = cache.writer.complete;
+    const unsigned int reader = cache.reader.complete;
+
+    const bool writer_less = writer < reader;
+
+    unsigned int total = 0;
+
+    /* should we go around the buffer for reading? */
+    if (writer_less && (reader + amount >= _size))
+    {
+        total = std::min(_size - (reader - writer + 1), amount);
+
+        if (total < amount)
+            return false;
+
+//        fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer);
+    }
+    else
+    {
+        total = std::min((!writer_less ? writer - (reader + 1) : amount), amount);
+
+        if (total < amount)
+            return false;
+
+//        fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer);
+    }
+
+    do
+    {
+        /* jump the reader forward */
+        Buffer_pointer index(cache.reader);
+        index.complete = (index.complete + total) % _size;
+
+        if (update(cache.reader, index))
+            break;
+    }
+    while (true);
+
+//    fprintf(stderr, "%p> read end: %d [%d]\n", this, _reader, _reader_partial);
+
+    return true;
+}
+
+/********** PARTIAL BUFFER FUNCTIONS (bytes) ***********/
+
+/* writes everything or nothing */
+bool Ringbuffer_traits::traits_provide_partial(char * buffer, const char * value, unsigned int amount)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int reader = (cache.reader.complete * _block) + cache.reader.partial;
+    const unsigned int writer = ((cache.writer.complete - 1) * _block) + cache.writer.partial;
+
+    const unsigned int size = _size * _block;
+    const unsigned int dest = writer - 1;
+
+//    fprintf(stderr, "%p> provide partial: %d/%d [%d/%d]\n", this, reader, writer, amount, size);
+
+    const bool reader_less = reader < writer;
+
+    /* should we go around the buffer for writing? */
+    if (reader_less && ((writer + amount) > size))
+    {
+        /* Documentation of the formula used in the 'if' below.
+         *
+         * [0|1|2|3|4|5|6|7] => size=8
+         *      |   |
+         *  reader  |
+         *         writer
+         *
+         * => writer has places [5,6,7,0,1] to write (5 places).
+         *
+         * =>  8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5
+         *
+         * > writer goes 1 up, amount goes 1 down.
+         * > reader goes 1 up, amount goes 1 up.
+         * > size goes 1 down, amount goes 1 down.
+         *
+         */
+
+        if ((size - (writer - reader + 1)) <= amount)
+            return false;
+
+        unsigned int wr1 = size - writer + 1; /* writer is already 1 position after */
+        unsigned int wr2 = amount - wr1;
+
+//        fprintf(stderr, "%p> p partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, size, reader, writer);
+
+        /* two partial writes (one at the end, another at the beginning) */
+        memcpy((void *) &(buffer[dest]), (const void *)  (value),      wr1);
+        memcpy((void *)  (buffer),       (const void *) &(value[wr1]), wr2);
+    }
+    else
+    {
+        if (!reader_less && ((reader - writer) <= amount))
+            return false;
+
+//        fprintf(stderr, "%p> p full write: %d/%d [r=%d/w=%d]\n", this, amount, size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        memcpy((void *) &(buffer[dest]), (const void *) value, amount);
+    }
+
+    unsigned int new_writer = ((dest + amount) % size) + 1;
+
+    /* update "full length position" */
+    _pointers.writer.complete = (unsigned int)floor((double) new_writer / (double)_block)+1;
+    _pointers.writer.partial  = (unsigned short)(new_writer % _block);
+
+//    fprintf(stderr, "%p> p write end: %d [block=%d]\n", this, new_writer, _block);
+
+    return true;
+}
+
+/* returns the number of bytes that have been read */
+unsigned int Ringbuffer_traits::traits_consume_partial(const char * buffer, char * value, unsigned int amount)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int writer = ((cache.writer.complete - 1) * _block) + cache.writer.partial;
+    const unsigned int reader = (cache.reader.complete * _block) + cache.reader.partial;
+
+    const unsigned int size = _size * _block;
+
+//    fprintf(stderr, "%p> consume partial: %d/%d [%d/%d]\n", this, reader, writer, amount, size);
+
+    const bool writer_less = writer < reader;
+
+    unsigned int total = 0;
+
+    /* should we go around the buffer for reading? */
+    if (writer_less && (reader + amount >= size))
+    {
+        total = std::min(size - (reader - writer + 1), amount);
+
+        if (total == 0)
+            return 0;
+
+        unsigned int rd1 = size - reader;
+        unsigned int rd2 = total - rd1;
+
+//        fprintf(stderr, "%p> p partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, size, reader, writer);
+
+        /* two partial consumes (one at the end, another at the beginning) */
+        memcpy((void *)  (value),      (const void *) &(buffer[reader]), rd1);
+        memcpy((void *) &(value[rd1]), (const void *)  (buffer),         rd2);
+    }
+    else
+    {
+        total = std::min((writer_less ? amount : writer - (reader + 1)), amount);
+
+        if (total == 0)
+            return 0;
+
+//        fprintf(stderr, "%p> p full read: %d/%d [r=%d/w=%d]\n", this, total, size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        memcpy((void *) value, (const void *) &(buffer[reader]), total);
+    }
+
+    do
+    {
+        unsigned int new_reader = (((cache.reader.complete * _block) + cache.reader.partial) + total) % size;
+
+        /* jump the reader forward */
+        Buffer_pointer index((unsigned int)floor((double)new_reader / (double)_block),
+            (unsigned short)(new_reader % _block));
+
+        if (update(cache.reader, index))
+        {
+//            fprintf(stderr, "%p> p read end: %d [block=%d]\n", this, new_reader, _block);
+            break;
+        }
+    }
+    while (true);
+
+    return total;
+}
+
+
+
+/********** IO FUNCTIONS **********/
+
+/* returns the number of items written to from buffer to stream */
+unsigned int Ringbuffer_traits::traits_put(const char * buffer, std::ostream &fd, unsigned int amount)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int reader = cache.reader.complete;
+    const unsigned int writer = cache.writer.complete;
+
+    const bool writer_less = writer < reader;
+
+    unsigned int total = 0;
+
+    /* should we go around the buffer for reading? */
+    if (writer_less && (reader + amount >= _size))
+    {
+        total = std::min(_size - (reader - writer + 1), amount);
+
+        if (total == 0)
+            return 0;
+
+        unsigned int rd1 = _size - reader;
+        unsigned int rd2 = total - rd1;
+
+//        fprintf(stderr, "%p> partial read: (%d/%d) %d/%d [%d/%d]\n", this, rd1, rd2, total, _size, reader, writer);
+
+        /* two partial consumes (one at the end, another at the beginning) */
+        fd.write((const char *) &(buffer[reader]), _block * rd1);
+        fd.write((const char *)  (buffer),         _block * rd2);
+    }
+    else
+    {
+        total = std::min((!writer_less ? writer - (reader + 1) : amount), amount);
+
+        if (total == 0)
+            return 0;
+
+//        fprintf(stderr, "%p> full read: %d/%d [%d/%d]\n", this, total, _size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        fd.write((const char *) &(buffer[reader]), _block * total);
+    }
+
+    do
+    {
+        /* jump the reader forward */
+        Buffer_pointer index(cache.reader);
+        index.complete = (index.complete + total) % _size;
+
+        if (update(cache.reader, index))
+            break;
+    }
+    while (true);
+
+    return total;
+}
+
+/* returns number of items read from stream to buffer */
+unsigned int Ringbuffer_traits::traits_get(char * buffer, std::istream &fd, unsigned int amount)
+{
+    /* avoid using different values */
+    Buffer_table cache = _pointers;
+
+    const unsigned int reader = cache.reader.complete;
+    const unsigned int writer = cache.writer.complete;
+
+    const unsigned int dest = writer - 1;
+
+    const bool reader_less = reader < writer;
+
+    unsigned int real_amount = 0;
+
+    /* should we go around the buffer for writing? */
+    if (reader_less && ((writer + amount) > _size))
+    {
+        /* Documentation of the formula used in the 'if' below.
+         *
+         * [0|1|2|3|4|5|6|7] => size=8
+         *      |   |
+         *  reader  |
+         *         writer
+         *
+         * => writer has places [5,6,7,0,1] to write (5 places).
+         *
+         * =>  8 - (4-2+1) = 8 - (2+1) = 8 - 3 = 5
+         *
+         * > writer goes 1 up, amount goes 1 down.
+         * > reader goes 1 up, amount goes 1 up.
+         * > size goes 1 down, amount goes 1 down.
+         *
+         */
+
+        if ((_size - (writer - reader + 1)) <= amount)
+            return false;
+
+        unsigned int wr1 = _size - writer + 1; /* writer is already 1 position after */
+        unsigned int wr2 = amount - wr1;
+
+//        fprintf(stderr, "%p> partial write: (%d/%d) %d/%d [%d/%d]\n", this, wr1, wr2, amount, _size, reader, writer);
+
+        unsigned int char_amount = 0;
+
+        /* one partial write on the buffer (at the end) */
+        fd.read((char *) &(buffer[dest]), _block * wr1);
+        char_amount += fd.gcount();
+
+        if (fd.gcount() == (int)(_block * wr1))
+        {
+            /* another partial write on the buffer (at the beginning) */
+            fd.read((char *) (buffer), _block * wr2);
+            char_amount += fd.gcount();
+        }
+
+        real_amount = char_amount / _block;
+    }
+    else
+    {
+        if (!reader_less && ((reader - writer) <= amount))
+            return false;
+
+//        fprintf(stderr, "%p> full write: %d/%d [%d/%d]\n", this, amount, _size, reader, writer);
+
+        /* we are talking about buffers here, man! */
+        fd.read((char *) &(buffer[dest]), _block * amount);
+
+        real_amount = fd.gcount() / _block;
+    }
+
+    _pointers.writer.complete = ((dest + real_amount) % _size) + 1;
+    _pointers.writer.partial  = 1;
+
+    return real_amount;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp b/src/mod/endpoints/mod_khomp/commons/ringbuffer.hpp
new file mode 100644 (file)
index 0000000..39f8ffe
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/* WARNING: This is a generic ringbuffer abstraction, which works for single-sized elements,
+            partial elements, single/multi-elements read/writes. It is not wise to mix some
+            functions (partial element write / full element write), since it was not designed
+            with this use in mind.
+
+            Also, it works only for single-reader + single-writer, since it does not depends
+            on external mutex functions.
+ */
+
+#include <string.h>
+
+#include <cmath>
+#include <iostream>
+
+#include <noncopyable.hpp>
+#include <atomic.hpp>
+
+#ifndef _RINGBUFFER_HPP_
+#define _RINGBUFFER_HPP_
+
+struct Buffer_pointer
+{
+    Buffer_pointer(unsigned int _complete = 0u, unsigned short _partial = 0u)
+    : complete(_complete), partial(_partial)
+    {};
+
+    Buffer_pointer(const Buffer_pointer & o)
+    : complete(o.complete), partial(o.partial)
+    {};
+
+    Buffer_pointer(const volatile Buffer_pointer & o)
+    : complete(o.complete), partial(o.partial)
+    {};
+
+    void operator=(const volatile Buffer_pointer o)
+    {
+        complete = o.complete;
+        partial = o.partial;
+    }
+
+    void operator=(const Buffer_pointer o) volatile
+    {
+        complete = o.complete;
+        partial = o.partial;
+    }
+
+    bool operator==(const Buffer_pointer & o)
+    {
+        return (complete == o.complete && partial == o.partial);
+    }
+
+    unsigned int  complete:20;
+    unsigned short partial:12;
+}
+__attribute__((packed));
+
+struct Buffer_table
+{
+    Buffer_table()
+    : reader(0,0),
+      writer(1,1)
+    {};
+
+    Buffer_table(const Buffer_table & o)
+    : reader(o.reader), writer(o.writer)
+    {};
+
+    Buffer_table(const volatile Buffer_table & o)
+    : reader(o.reader), writer(o.writer)
+    {};
+
+    void operator=(const volatile Buffer_table o)
+    {
+        reader = o.reader;
+        writer = o.writer;
+    }
+
+    void operator=(const Buffer_table o) volatile
+    {
+        reader = o.reader;
+        writer = o.writer;
+    }
+
+    bool operator==(const Buffer_table & o)
+    {
+        return (reader == o.reader && writer == o.writer);
+    }
+
+    Buffer_pointer reader;
+    Buffer_pointer writer;
+}
+__attribute__((packed));
+
+struct Ringbuffer_traits
+{
+    Ringbuffer_traits(unsigned int block, unsigned int size)
+    : _block(block), _size(size)
+    {};
+
+    bool         traits_provide(      char *, const char *, unsigned int, bool);
+    unsigned int traits_consume(const char *,       char *, unsigned int, bool);
+
+    unsigned int traits_consume_begins(const char *, char *, unsigned int, bool);
+    bool         traits_consume_commit(unsigned int);
+
+    bool         traits_provide_partial(      char *, const char *, unsigned int);
+    unsigned int traits_consume_partial(const char *,       char *, unsigned int);
+
+    unsigned int traits_get(      char *, std::istream &, unsigned int);
+    unsigned int traits_put(const char *, std::ostream &, unsigned int);
+
+    bool update(Buffer_pointer & cache, Buffer_pointer & update)
+    {
+        return Atomic::doCAS(&(_pointers.reader), &cache, update);
+    }
+
+ protected:
+    const unsigned int      _block;
+    const unsigned int      _size;
+
+    volatile Buffer_table _pointers;
+};
+
+template <typename T>
+struct Ringbuffer: protected Ringbuffer_traits, public NonCopyable
+{
+    struct BufferFull  {};
+    struct BufferEmpty {};
+
+    Ringbuffer(unsigned int size)
+    : Ringbuffer_traits(sizeof(T), size)
+    {
+        _buffer = new T[_size];
+        _malloc = true;
+    };
+
+    Ringbuffer(unsigned int size, T * buffer)
+    : Ringbuffer_traits(sizeof(T), size)
+    {
+        _buffer = buffer;
+        _malloc = false;
+    };
+
+    ~Ringbuffer()
+    {
+        if (_malloc)
+          delete[] _buffer;
+    }
+
+    /***** GENERIC RANGE/INDEX CALCULATION FUNCTIONS *****/
+    bool may_write(Buffer_table & cache)
+    {
+        const unsigned int r = cache.reader.complete;
+        const unsigned int w = cache.writer.complete;
+
+        return (((r - w) != 1) && (!(r == 0 && w == _size)));
+    }
+
+    bool may_read(Buffer_table & cache)
+    {
+        if ((cache.writer.complete - cache.reader.complete) == 1)
+            return false;
+
+        return true;
+    }
+
+    unsigned int writer_next(Buffer_pointer & cache, Buffer_pointer & index)
+    {
+        unsigned int dest = cache.complete - 1,
+                     temp = cache.complete + 1;
+
+        if (temp > _size) index.complete = 1;
+        else              index.complete = temp;
+
+        index.partial = 1;
+
+        return dest;
+    };
+
+    void reader_next(Buffer_pointer & cache, Buffer_pointer & index)
+    {
+        unsigned int temp = cache.complete + 1;
+
+        if (temp == _size) index.complete = 0;
+        else               index.complete = temp;
+
+        index.partial = 0;
+    }
+
+    /***** BUFFER FUNCTIONS *****/
+
+    bool provide(const T & value)
+    {
+        Buffer_table   cache = _pointers;
+        Buffer_pointer index = _pointers.writer;
+
+        if (!may_write(cache))
+            return false;
+
+//        fprintf(stderr, "%p> provide %d/%d!\n", this, reader, writer);
+
+        unsigned int dest = writer_next(cache.writer, index);
+
+        _buffer[dest] = value;
+
+        _pointers.writer = index;
+
+//        fprintf(stderr, "%p> write: %d/%d [%d/%d]\n", this, _pointers.reader, _pointers.writer, _pointers.reader_partial, _pointers.writer_partial);
+
+        return true;
+    }
+
+    bool consume(T & value)
+    {
+        Buffer_table   cache = _pointers;
+        Buffer_pointer index = _pointers.reader;
+
+        if (!may_read(cache))
+            return false;
+
+//        fprintf(stderr, "%p> consume %d/%d!\n", this, reader, writer);
+
+        value = _buffer[index.complete];
+
+        do
+        {
+            reader_next(cache.reader, index);
+
+            if (update(cache.reader, index))
+                break;
+
+            cache.reader = index;
+        }
+        while (true);
+
+//      fprintf(stderr, "%p> read: %d/%d [%d/%d]\n", this, _pointers.reader, _pointers.writer, _pointers.reader_partial, _pointers.writer_partial);
+
+        return true;
+    }
+
+    /* writes everything or nothing */
+    inline bool provide(const T * value, unsigned int amount, bool skip_overwrite = true)
+    {
+        return traits_provide((char *)_buffer, (const char *) value, amount, skip_overwrite);
+    }
+
+    /* returns the number of items that have been read (atomic_mode == true means 'all or nothing') */
+    inline unsigned int consume(T * value, unsigned int amount, bool atomic_mode = false)
+    {
+        return traits_consume((const char *)_buffer, (char *) value, amount, atomic_mode);
+    }
+
+    /***** TWO-PHASE BUFFER FUNCTIONS *****/
+
+    /* returns the number of items that have been read (atomic_mode == true means 'all or nothing') */
+    inline unsigned int consume_begins(T * value, unsigned int amount, bool atomic_mode = false)
+    {
+        return traits_consume_begins((const char *)_buffer, (char *) value, amount, atomic_mode);
+    }
+
+    /* returns true if we could commit that much of buffer (use only after consume_begins).    *
+     * note: you may commit less bytes that have been read to keep some data inside the buffer */
+    inline bool consume_commit(unsigned int amount)
+    {
+        return traits_consume_commit(amount);
+    }
+
+    /***** TWO-PHASE SINGLE-ELEMENT BUFFER FUNCTIONS *****/
+
+    T & provider_start(void)
+    {
+        Buffer_table  cache = _pointers;
+
+        if (!may_write(cache))
+            throw BufferFull();
+
+        unsigned writer = _pointers.writer.complete - 1;
+
+//        fprintf(stderr, "%p> provider start %d/%d!\n", this, reader, writer);
+
+        return _buffer[writer];
+    }
+
+    void provider_commit(void)
+    {
+        unsigned int temp = _pointers.writer.complete + 1;
+
+//        fprintf(stderr, "%p> provider commit %d!\n", this, temp);
+
+        if (temp > _size)
+            temp = 1;
+
+        _pointers.writer.complete = temp;
+        _pointers.writer.partial  = 1;
+
+//        fprintf(stderr, "%p> write: %d/%d [%d/%d]\n", this, _pointers.reader, _pointers.writer, _pointers.reader_partial, _pointers.writer_partial);
+    }
+
+    T & consumer_start(void)
+    {
+        Buffer_table  cache = _pointers;
+
+        if (!may_read(cache))
+            throw BufferEmpty();
+
+        unsigned int reader = _pointers.reader.complete;
+
+//        fprintf(stderr, "%p> consumer start %d/%d!\n", this, reader, writer);
+
+        return _buffer[reader];
+    }
+
+    void consumer_commit(void)
+    {
+        Buffer_pointer cache = _pointers.reader;
+        Buffer_pointer index(cache);
+
+        do
+        {
+            reader_next(cache, index);
+
+            if (update(cache, index))
+                break;
+
+            cache = index;
+        }
+        while (true);
+
+//        fprintf(stderr, "%p> consumer commit %d!\n", this, temp);
+
+//        fprintf(stderr, "%p> read: %d/%d [%d/%d]\n", this, _pointers.reader, _pointers.writer, _pointers.reader_partial, _pointers.writer_partial);
+    }
+
+    /* writes everything or nothing, but works on bytes (may write incomplete elements) */
+    /* WARNING: do not mix this with full element provider */
+    inline bool provider_partial(const char *buffer, unsigned int amount)
+    {
+        return traits_provide_partial((char *)_buffer, buffer, amount);
+    }
+
+    /* returns the number of bytes that have been read (may read incomplete elements) */
+    /* WARNING: do not mix this with full element consumer */
+    inline unsigned int consumer_partial(char *buffer, unsigned int amount)
+    {
+        return traits_consume_partial((const char *)_buffer, buffer, amount);
+    }
+
+    /***** IO FUNCTIONS *****/
+
+    /* returns the number of items written to from buffer to stream */
+    inline unsigned int put(std::ostream &fd, unsigned int amount)
+    {
+        return traits_put((char *)_buffer, fd, amount);
+    }
+
+    /* returns number of items read from stream to buffer */
+    inline unsigned int get(std::istream &fd, unsigned int amount)
+    {
+        return traits_get((const char *)_buffer, fd, amount);
+    }
+
+    void clear()
+    {
+        _pointers.reader.complete = 0;
+        _pointers.reader.partial  = 0;
+        _pointers.writer.complete = 1;
+        _pointers.writer.partial  = 1;
+    }
+
+ protected:
+    T *  _buffer;
+    bool _malloc;
+};
+
+#endif /* _RINGBUFFER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/saved_condition.cpp b/src/mod/endpoints/mod_khomp/commons/saved_condition.cpp
new file mode 100644 (file)
index 0000000..4c9f80f
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+
+#include <config_commons.hpp>
+
+#include COMMONS_INCLUDE(saved_condition.cpp)
+
diff --git a/src/mod/endpoints/mod_khomp/commons/saved_condition.hpp b/src/mod/endpoints/mod_khomp/commons/saved_condition.hpp
new file mode 100644 (file)
index 0000000..dcfd224
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _SAVED_CONDITION_COMMON_HPP_
+#define _SAVED_CONDITION_COMMON_HPP_
+
+#include <config_commons.hpp>
+
+//#include <refcounter.hpp>
+
+struct SavedConditionCommon
+{
+    SavedConditionCommon() : _signaled(false) {}
+
+ protected:
+    bool _signaled;
+};
+
+
+#include COMMONS_INCLUDE(saved_condition.hpp)
+
+#endif /* _SAVED_CONDITION_COMMON_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/scoped_lock.hpp b/src/mod/endpoints/mod_khomp/commons/scoped_lock.hpp
new file mode 100644 (file)
index 0000000..a85627f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <simple_lock.hpp>
+
+struct ScopedLockBasic
+{
+    ScopedLockBasic(void)
+    : _locked(true) {};
+
+    ScopedLockBasic(bool locked)
+    : _locked(locked) {};
+
+    virtual ~ScopedLockBasic() {};
+
+ protected:
+    bool _locked;
+};
+
+
+struct ScopedLock : public ScopedLockBasic
+{
+    struct LockFailed {};
+
+    ScopedLock(SimpleLock & mutex)
+    : ScopedLockBasic(false), _mutex(mutex)
+    {
+        switch (_mutex.lock())
+        {
+            case SimpleLock::ISINUSE:
+            case SimpleLock::FAILURE:
+                throw LockFailed();
+            default:
+                break;
+        }
+
+        _locked = true;
+    }
+
+    ~ScopedLock()
+    {
+        unlock();
+    }
+
+    void unlock()
+    {
+        if (_locked)
+        {
+            _locked = false;
+            _mutex.unlock();
+        }
+    }
+
+ protected:
+    SimpleLock & _mutex;
+};
+
diff --git a/src/mod/endpoints/mod_khomp/commons/simple_lock.hpp b/src/mod/endpoints/mod_khomp/commons/simple_lock.hpp
new file mode 100644 (file)
index 0000000..4f6619f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _SIMPLE_LOCK_COMMON_HPP_
+#define _SIMPLE_LOCK_COMMON_HPP_
+
+#include <config_commons.hpp>
+
+#include <unistd.h>
+#include <noncopyable.hpp>
+
+#include <refcounter.hpp>
+
+/* This struct uses static polymorphism, and derived classes should implement  *
+ * the "lock/trylock/unlock()" methods for correct code compilation.           *
+ * The base class also features reference counting, so derived classes should  *
+ * implement the "unreference()" method for releasing resources.               */
+
+template < typename Implementor >
+struct SimpleLockCommon: NEW_REFCOUNTER( SimpleLockCommon < Implementor > )
+{
+    friend class ReferenceCounter < SimpleLockCommon < Implementor > >;
+
+    typedef enum
+    {
+        ISINUSE = 0, // operation not succeded (no error)
+        SUCCESS = 1, // operation succeded (no error)
+        FAILURE = 2, // mutex or state is somehow invalid (error! run for your life!)
+    }
+    Result;
+
+    SimpleLockCommon()
+    {};
+
+    SimpleLockCommon(const SimpleLockCommon & o)
+    : INC_REFCOUNTER(o, SimpleLockCommon)
+    {};
+
+    virtual ~SimpleLockCommon()
+    {};
+
+    inline Result lock()
+    {
+        return static_cast<Implementor*>(this)->lock();
+    }
+
+    inline Result trylock()
+    {
+        return static_cast<Implementor*>(this)->trylock();
+    }
+
+    inline void unlock()
+    {
+        static_cast<Implementor*>(this)->unlock();
+    }
+
+  protected:
+    void unreference(void)
+    {
+        static_cast<Implementor*>(this)->unreference();
+    }
+};
+
+#include COMMONS_INCLUDE(simple_lock.hpp)
+
+#endif /* _SIMPLE_LOCK_COMMON_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/strings.cpp b/src/mod/endpoints/mod_khomp/commons/strings.cpp
new file mode 100644 (file)
index 0000000..5e1cbc7
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <strings.hpp>
+
+void Strings::Merger::add(std::string s)
+{
+    _list.push_back(s);
+};
+
+std::string Strings::Merger::merge(const std::string & sep)
+{
+    list_type::iterator i = _list.begin();
+
+    std::string res;
+
+    if (i != _list.end())
+    {
+        res += (*i);
+        ++i;
+    };
+
+    while (i != _list.end())
+    {
+        res += sep;
+        res += (*i);
+        ++i;
+    }
+
+    return res;
+};
+
+std::string Strings::Merger::merge(const char *sep)
+{
+    std::string ssep(sep);
+    return merge(ssep);
+}
+
+unsigned int Strings::tokenize(const std::string & str, Strings::vector_type & tokens,
+    const std::string & delims, long int max_tokens, bool keep_empty)
+{
+    std::string::size_type base = 0;
+
+    std::string::size_type init = str.find_first_not_of(delims, 0);
+    std::string::size_type fini = str.find_first_of(delims, init);
+
+    long int cur_token = 1;
+
+    while (std::string::npos != init)
+    {
+        if (keep_empty && base < init)
+        {
+            std::string::size_type cur_empty = init - base;
+
+            while (cur_empty && cur_token < max_tokens)
+            {
+                tokens.push_back("");
+
+                ++cur_token;
+                --cur_empty;
+            }
+        }
+
+        if (std::string::npos != fini && cur_token < max_tokens)
+        {
+            base = fini + 1;
+
+            tokens.push_back(str.substr(init, fini - init));
+            ++cur_token;
+        }
+        else
+        {
+            base = str.size(); // find_first_of(delims, init);
+
+            tokens.push_back(str.substr(init, str.size() - init));
+               break;
+        }
+
+           init = str.find_first_not_of(delims, fini);
+               fini = str.find_first_of(delims, init);
+    }
+
+    if (keep_empty && base != str.size())
+    {
+        std::string::size_type cur_empty = str.size() - base + 1;
+
+           while (cur_empty && cur_token < max_tokens)
+               {
+            tokens.push_back("");
+
+               ++cur_token;
+                       --cur_empty;
+        }
+
+        if (cur_empty)
+        {
+            std::string::size_type pos = base + cur_empty - 1;
+            tokens.push_back(str.substr(pos, str.size() - pos));
+            ++cur_token;
+        }
+    }
+
+    return (cur_token - 1);
+}
+
+bool Strings::toboolean(std::string str)
+{
+    std::string tmp(str);
+
+    Strings::lower(tmp);
+
+    if ((tmp == "true")  || (tmp == "yes")) return true;
+    if ((tmp == "false") || (tmp == "no"))  return false;
+
+    throw invalid_value(str);
+}
+
+long Strings::tolong(std::string str, int base)
+{
+    char *str_end = 0;
+
+    unsigned long value = strtol(str.c_str(), &str_end, base);
+
+    if (str_end && *str_end == 0)
+        return value;
+
+    throw invalid_value(str);
+}
+
+unsigned long Strings::toulong(std::string str, int base)
+{
+    char *str_end = 0;
+
+    unsigned long value = strtoul(str.c_str(), &str_end, base);
+
+    if (str_end && *str_end == 0)
+        return value;
+
+    throw invalid_value(str);
+}
+
+unsigned long long Strings::toulonglong(std::string str, int base)
+{
+#if defined(_WINDOWS) || defined(_Windows) || defined(_WIN32) || defined(WIN32)
+    throw not_implemented();
+#else
+    char *str_end = 0;
+
+    unsigned long long value = strtoull(str.c_str(), &str_end, base);
+
+    if (str_end && *str_end == 0)
+        return value;
+
+    throw invalid_value(str);
+#endif
+}
+
+double Strings::todouble(std::string str)
+{
+    char *str_end = 0;
+
+    double value = strtod(str.c_str(), &str_end);
+
+    if (str_end && *str_end == 0)
+        return value;
+
+    throw invalid_value(str);
+}
+
+std::string Strings::fromboolean(bool value)
+{
+    if (value) return "true";
+    else       return "false";
+}
+
+std::string Strings::lower(std::string str)
+{
+    std::string res;
+
+    for (std::string::iterator i = str.begin(); i != str.end(); i++)
+        res += tolower((*i));
+
+    return res;
+}
+
+std::string Strings::hexadecimal(std::string value)
+{
+    std::string result;
+
+    for (std::string::iterator i = value.begin(); i != value.end(); i++)
+    {
+        if (i != value.begin())
+            result += " ";
+
+        result += STG(FMT("%2x") % (unsigned int)(*i));
+    }
+
+    return result;
+}
+
+std::string Strings::trim(const std::string& str, const std::string& trim_chars)
+{
+    std::string result(str);
+
+    result.erase( result.find_last_not_of( trim_chars ) + 1 );
+    result.erase( 0, result.find_first_not_of( trim_chars ) );
+
+    return result;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/strings.hpp b/src/mod/endpoints/mod_khomp/commons/strings.hpp
new file mode 100644 (file)
index 0000000..056b933
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <limits.h>
+
+#include <list>
+#include <vector>
+#include <string>
+
+#include <types.hpp>
+
+#include <format.hpp>
+
+/* Generic string funcions */
+
+#ifndef _STRINGS_HPP_
+#define _STRINGS_HPP_
+
+struct Strings
+{
+    typedef std::list<std::string>      list_type;
+    typedef std::vector<std::string>  vector_type;
+
+    struct Merger
+    {
+        void          add(std::string);
+
+        std::string merge(const std::string &);
+        std::string merge(const char *);
+
+        bool empty() { return _list.empty(); };
+
+     protected:
+        list_type   _list;
+    };
+
+ public:
+    struct invalid_value
+    {
+        invalid_value(const char  * value): _value(value) {};
+        invalid_value(std::string   value): _value(value) {};
+
+        std::string & value() { return _value; }
+
+     protected:
+         std::string _value;
+    };
+
+    struct not_implemented {};
+
+    static unsigned int tokenize(const std::string &, vector_type &, const std::string & delims = ",;:",
+                                 long int max_toxens = LONG_MAX, bool keep_empty = true);
+
+    static bool        toboolean(std::string);
+    static std::string fromboolean(bool);
+
+    static long               tolong(std::string, int base = 10);
+    static unsigned long      toulong(std::string, int base = 10);
+    static unsigned long long toulonglong(std::string, int base = 10);
+    static double             todouble(std::string);
+
+    static std::string lower(std::string);
+    static std::string hexadecimal(std::string);
+
+    static std::string trim(const std::string&, const std::string& trim_chars = " \f\n\r\t\v");
+};
+
+#endif // _STRINGS_HPP_ //
diff --git a/src/mod/endpoints/mod_khomp/commons/tagged_union.hpp b/src/mod/endpoints/mod_khomp/commons/tagged_union.hpp
new file mode 100644 (file)
index 0000000..1616268
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _TAGGED_UNION_HPP_
+#define _TAGGED_UNION_HPP_
+
+#include <stdexcept>
+
+#include <iostream>
+#include <unistd.h>
+
+namespace Tagged
+{
+    struct EmptyUnion
+    {
+        friend class Value;
+
+        EmptyUnion()
+        : _adjusted(false) {};
+
+        // copy constructor
+        EmptyUnion(const EmptyUnion & o)
+        : _adjusted(o._adjusted) {};
+
+        // copy assignment operator
+        EmptyUnion & operator=(const EmptyUnion & o)
+        {
+            _adjusted = o._adjusted;
+            return *this;
+        };
+
+        ~EmptyUnion() { _adjusted = false; };
+
+        bool operator==(const EmptyUnion & o)
+        {
+            return true;
+        };
+
+      public:
+        void clear(void) { _adjusted = false; };
+      protected:
+        void setup(void) { _adjusted = true;  };
+
+      protected:
+        bool value_set(void)   { return false; };
+        bool value_get(void)   { return false; };
+
+        bool value_check(void) { return false; };
+
+        template < typename S >
+        bool value_visit(S & visitor, typename S::ReturnType & ret)
+        {
+            return false;
+        };
+
+        template < typename S >
+        bool value_visit_void(S & visitor)
+        {
+            return false;
+        };
+
+        bool adjusted()  { return _adjusted;  };
+
+      private:
+        bool _adjusted;
+    };
+
+    template < typename V, typename E = EmptyUnion >
+    struct Union: public E
+    {
+        friend class Value;
+
+        // default constructor
+        Union()
+        : _value(0) {};
+
+        // constructor with initializer
+        template < typename U >
+        Union( U value )
+        : _value(0)
+        {
+            set(value);
+        };
+
+        // copy constructor
+        Union(const Union & o)
+        : E(static_cast<const E&>(o)),
+          _value( (o._value ? new const V(*(o._value)) : 0) )
+        {};
+
+        // copy assignment operator
+        Union & operator=(const Union & o)
+        {
+            if (_value)
+            {
+                delete _value;
+                _value = 0;
+            }
+
+            if (o._value)
+            {
+                _value = new const V(*(o._value));
+            }
+
+            E::operator=(static_cast<const E&>(o));
+
+            return *this;
+        };
+
+        // destructor
+        ~Union()
+        {
+            if (_value)
+            {
+                delete _value;
+                _value = 0;
+            }
+        };
+
+        // equal sign operator
+        template < typename U >
+        void operator=(U value)
+        {
+            set(value);
+        }
+
+        template < typename U >
+        bool check(void)
+        {
+            return value_check(static_cast<const U * const>(0));
+        };
+
+        template < typename U >
+        const U & get(void)
+        {
+            const U * res = 0;
+
+            if (!value_get(&res) || !res)
+                throw std::runtime_error("type mismatch");
+
+            return *res;
+        };
+
+        template < typename U >
+        void set(U val)
+        {
+            if (E::adjusted())
+                clear();
+
+            if (!value_set(val))
+                throw std::runtime_error("unable to set value of invalid type");
+        };
+
+        template < typename S >
+        typename S::ReturnType visit(S visitor)
+        {
+            typename S::ReturnType ret;
+
+            if (!value_visit(visitor, ret))
+                throw std::runtime_error("unable to visit empty value");
+
+            return ret;
+        };
+
+        template < typename S >
+        void visit_void(S visitor)
+        {
+            if (!value_visit_void(visitor))
+                throw std::runtime_error("unable to visit empty value");
+        };
+
+        void clear()
+        {
+            if (_value)
+            {
+                delete _value;
+                _value = 0;
+            }
+
+            E::clear();
+        };
+
+        // compare (equal) operator
+        bool operator==(const Union & o)
+        {
+            bool are_equal = false;
+
+            if (!_value && !(o._value))
+                are_equal = true;
+
+            if (_value && o._value)
+                are_equal = (*_value == *(o._value));
+
+            if (are_equal)
+                return E::operator==(static_cast<const E&>(o));
+
+            return false;
+        };
+
+        // compare types
+        bool sameType(const Union & o)
+        {
+            if ((!(_value) && !(o._value)) || (_value && o._value))
+                return E::operator==(static_cast<const E&>(o));
+
+            return false;
+        };
+
+      protected:
+        using E::value_set;
+        using E::value_get;
+
+        using E::value_check;
+        using E::value_visit;
+        using E::value_visit_void;
+
+        bool value_set(V val)
+        {
+            _value = new const V(val);
+            E::setup();
+
+            return true;
+        };
+
+        bool value_get(const V ** val)
+        {
+            if (!_value)
+                return false;
+
+            *val = _value;
+            return true;
+        }
+
+        bool value_check(const V * const junk)
+        {
+            (void)junk;
+            return (_value != 0);
+        };
+
+        template < typename S >
+        bool value_visit(S & visitor, typename S::ReturnType & ret)
+        {
+            if (_value)
+            {
+                ret = visitor(*const_cast<V*>(_value));
+                return true;
+            };
+
+            return E::value_visit(visitor, ret);
+        };
+
+        template < typename S >
+        bool value_visit_void(S & visitor)
+        {
+            if (_value)
+            {
+                visitor(*const_cast<V*>(_value));
+                return true;
+            };
+
+            return E::value_visit_void(visitor);
+        };
+
+      private:
+        const V * _value;
+    };
+};
+
+#endif /* _TAGGED_UNION_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/thread.hpp b/src/mod/endpoints/mod_khomp/commons/thread.hpp
new file mode 100644 (file)
index 0000000..e00d7c8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _THREAD_COMMON_HPP_
+#define _THREAD_COMMON_HPP_
+
+#include <config_commons.hpp>
+
+#include <types.hpp>
+//#include <function.hpp>
+
+struct ThreadCommon
+{
+  protected:
+    template<typename FuncPtrType>
+    struct DecomposeFuncPtr;
+
+    template<typename ReturnType, typename ArgType>
+    struct DecomposeFuncPtr<ReturnType(*)(ArgType)>
+    {
+        typedef ReturnType Return;
+    };
+
+    template<typename SomeClass>
+    struct DecomposeFuncPtr
+    {
+        typedef void Return;
+    };
+
+    template<typename ReturnType>
+    struct DecomposeFuncPtr<ReturnType(*)()>
+    {
+        typedef ReturnType Return;
+    };
+
+    template< typename FunctionType >
+    struct DecomposeFunction
+    {
+        typedef typename Select < IsClass< FunctionType >::Result, int,
+            typename DecomposeFuncPtr< FunctionType >::Return >::Result
+        Return;
+    };
+
+  public:
+    struct ThreadDataCommon
+    {
+        ThreadDataCommon() {}
+
+        virtual ~ThreadDataCommon() {}
+
+        virtual int run() = 0;
+
+        ThreadCommon * _thread;
+
+        void * _self;
+        void * _attribute;
+    };
+
+    ThreadCommon() {}
+};
+
+
+#include COMMONS_INCLUDE(thread.hpp)
+
+#endif /* _THREAD_COMMON_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/timer.cpp b/src/mod/endpoints/mod_khomp/commons/timer.cpp
new file mode 100644 (file)
index 0000000..36e32f5
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <timer.hpp>
+
+TimerTraits::TimerTraits()
+: _thread((Thread*)0), _purify(false), _last_tick(0), _age_count(0), _shutdown(false)
+{};
+
+bool TimerTraits::start (void)
+{
+    _shutdown = false;
+
+    _condition.reset();
+    _finalized.reset();
+
+    if (!_thread)
+    {
+        _thread = new Thread(TimerTraits::loop_thread(this));
+        _purify = true;
+    }
+
+#if defined(_WINDOWS) || defined(_Windows) || defined(_WIN32) || defined(WIN32)
+    // set priority ...
+#else
+    pthread_attr_t attrs;
+    sched_param    param;
+
+    if (pthread_attr_init(&attrs) < 0)
+        return false;
+
+    if (pthread_attr_setschedpolicy(&attrs, SCHED_RR) < 0)
+        return false;
+
+    if (pthread_attr_getschedparam(&attrs, &param) < 0)
+        return false;
+
+    param.sched_priority = sched_get_priority_max(SCHED_RR);
+
+    if (pthread_attr_setschedparam(&attrs, &param) < 0)
+        return false;
+
+    // set priority...
+
+//    if (pthread_create(&_thread, &attrs, TimerTraits::loop_thread, NULL) < 0)
+//        return false;
+
+    _thread->start();
+#endif
+
+    return true;
+}
+
+bool TimerTraits::stop (void)
+{
+    _shutdown = true;
+
+    _condition.signal();
+
+    _finalized.wait(10000); /* 10 seconds max wait */
+
+    if (_thread && _purify)
+    {
+        delete _thread;
+
+        _thread = (Thread *)0;
+        _purify = false;
+    }
+
+    return true;
+}
+
+//-----------------------------------------
+
+int TimerTraits::loop_thread::operator()(void)
+{
+    try
+    {
+        _timer->loop();
+    }
+    catch( ... )
+    {
+        /* something wrong happened! */
+    }
+
+    _timer->_finalized.signal();
+
+    return 0;
+}
+
+void TimerTraits::execute(ControlSet::iterator init, const TimerTraits::Control & ctrl)
+{
+    volatile CallbackFuncType func = (volatile CallbackFuncType) ctrl._func;
+    volatile CallbackDataType data = (volatile CallbackDataType) ctrl._data;
+
+    _timer_set.erase(init);
+
+    _mutex.unlock();
+
+    func(data);
+}
+
+void TimerTraits::loop (void)
+{
+    while (true)
+    {
+        if (_shutdown) break;
+
+        _mutex.lock();
+
+        ControlSet::iterator init = _timer_set.begin();
+
+        if (init == _timer_set.end())
+        {
+            _mutex.unlock();
+            _condition.wait();
+        }
+        else
+        {
+            const Control & ctrl = *init;
+
+            unsigned int ts_now    = TimerTraits::tick();
+
+            if (_age_count == ctrl._age)
+            {
+                if (ts_now < ctrl._msecs)
+                {
+                    /* age is right, but it is not time to expire yet... */
+                    volatile unsigned int wait_time = ctrl._msecs - ts_now;
+                    _mutex.unlock();
+                    _condition.wait(wait_time); /* expire - now */
+                }
+                else
+                {
+                    /* age is right, and we should expire! */
+                    execute(init, ctrl); /* called locked, return unlocked */
+                }
+            }
+            else if (_age_count < ctrl._age)
+            {
+                /* age is not there yet (need some time to overlap)... */
+                volatile unsigned int wait_time = (UINT_MAX - ts_now) + ctrl._msecs;
+                _mutex.unlock();
+                _condition.wait(wait_time); /* MAX - now + expire */
+            }
+            else
+            {
+                /* age has passed, we should have expired before! */
+                execute(init, ctrl); /* called locked, return unlocked */
+            }
+        }
+    }
+
+    _finalized.signal();
+}
+
+unsigned int TimerTraits::tick()
+{
+#if defined(_WINDOWS) || defined(_Windows) || defined(_WIN32) || defined(WIN32)
+    unsigned int tick =  GetTickCount();
+#else
+    struct timespec ticks;
+
+    // error condition, make the user notice this..
+    if (clock_gettime(CLOCK_MONOTONIC, &ticks) < 0)
+        return 0;
+
+    unsigned int tick = ( ticks.tv_sec * 1000 ) + ( ticks.tv_nsec / 1000000 );
+#endif
+
+    if (_last_tick > tick)
+        ++_age_count;
+
+    _last_tick = tick;
+
+    return tick;
+}
+
+//-----------------------------------------
+
+TimerTraits::Index TimerTraits::traits_add_unlocked (unsigned int msecs, const void * func, const void * data, unsigned int value)
+{
+    unsigned int ms_tick = TimerTraits::tick();
+
+    unsigned int ms_left =  UINT_MAX - ms_tick;
+    unsigned int ms_real =  msecs;
+
+    unsigned int age_num = _age_count;
+
+    if (ms_left < msecs)
+    {
+        ms_real -= ms_left;
+        ++age_num;
+    }
+    else
+    {
+        ms_real += ms_tick;
+    }
+
+    ControlSet::iterator it = _timer_set.insert(Control(age_num,ms_real,func,data,value));
+
+    if (_timer_set.size() == 1 || _timer_set.begin() == it)
+    {
+        _condition.signal();
+    };
+
+    return Index(age_num, ms_real, msecs, func, data, value);
+}
+
+TimerTraits::Index TimerTraits::traits_add (unsigned int msecs, const void * func, const void * data, unsigned int value)
+{
+    _mutex.lock();
+
+    Index idx = traits_add_unlocked(msecs, func, data, value);
+
+    _mutex.unlock();
+
+    return idx;
+}
+
+bool TimerTraits::traits_restart (TimerTraits::Index & idx, bool force)
+{
+    bool ret = false;
+
+    _mutex.lock();
+
+    if (idx.valid)
+    {
+        if (traits_del_unlocked(idx) || force)
+        {
+            idx = traits_add_unlocked(idx.delta, idx.func, idx.data, idx.value);
+            ret = true;
+        }
+    }
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+bool TimerTraits::traits_del_unlocked (TimerTraits::Index & idx)
+{
+    bool ret = false;
+
+    if (idx.valid)
+    {
+        ControlSet::iterator i = _timer_set.lower_bound(Control(idx.era, idx.msec));
+        ControlSet::iterator j = _timer_set.upper_bound(Control(idx.era, idx.msec));
+
+        for (; i != j; i++)
+        {
+            const Control & ctrl = (*i);
+
+            if ((idx.value && !(ctrl._value & idx.value)))
+                continue;
+
+            if (((idx.func && ctrl._func == idx.func) || !idx.func) && ((idx.data && ctrl._data == idx.data) || !idx.data))
+            {
+                if (_timer_set.begin() == i)
+                    _condition.signal();
+
+                _timer_set.erase(i);
+
+                ret = true;
+                break;
+            }
+        }
+
+        idx.valid = false;
+    }
+
+    return ret;
+}
+
+bool TimerTraits::traits_del (TimerTraits::Index & idx)
+{
+    _mutex.lock();
+
+    bool ret = traits_del_unlocked(idx);
+
+    _mutex.unlock();
+
+    return ret;
+}
+
+bool TimerTraits::traits_del (const void * func, const void * data, unsigned int value)
+{
+    bool ret = false;
+
+    _mutex.lock();
+
+    for (ControlSet::iterator i = _timer_set.begin(); i != _timer_set.end(); i++)
+    {
+        const Control & ctrl = (*i);
+
+        if ((value && !(ctrl._value & value)))
+            continue;
+
+        if (((func && ctrl._func == func) || !func) && ((data && ctrl._data == data) || !data))
+        {
+            if (_timer_set.begin() == i)
+                _condition.signal();
+
+            _timer_set.erase(i);
+
+            ret = true;
+            break;
+        }
+    }
+
+    _mutex.unlock();
+
+    return ret;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/timer.hpp b/src/mod/endpoints/mod_khomp/commons/timer.hpp
new file mode 100644 (file)
index 0000000..382efa1
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#if defined(_WINDOWS) || defined(_Windows) || defined(_WIN32) || defined(WIN32)
+#include <windows.h>
+#else
+#include <sched.h>
+#endif
+
+#include <set>
+
+#include <simple_lock.hpp>
+#include <saved_condition.hpp>
+#include <thread.hpp>
+#include <refcounter.hpp>
+
+#ifndef _TIMER_HPP_
+#define _TIMER_HPP_
+
+struct TimerTraits
+{
+    typedef bool          (* CallbackFuncType)(const void * volatile);
+    typedef const void *     CallbackDataType;
+
+    TimerTraits();
+
+    virtual ~TimerTraits() {};
+
+ protected:
+
+    /* pre-declaration, used below */
+    struct ControlCompare;
+
+    struct Control
+    {
+        Control(unsigned int age, unsigned int msecs, const void * func = 0, const void * data = 0, unsigned int value = 0)
+        : _age(age), _msecs(msecs), _func(func), _data(data), _value(value) {}
+
+        unsigned int  _age;
+
+        unsigned int  _msecs;
+
+        const void * _func;
+        const void * _data;
+
+        unsigned int  _value;
+    };
+
+    struct ControlCompare
+    {
+        bool operator()(const Control & c1, const Control & c2) const
+        {
+            return (c1._age < c2._age ? true : c1._msecs < c2._msecs);
+        }
+    };
+
+    typedef std::multiset < Control, ControlCompare > ControlSet;
+
+ public:
+    struct Index
+    {
+        Index(): era(0), msec(0), valid(false) {};
+
+        Index(unsigned int _era, unsigned int _msec, unsigned int _delta, const void * _func, const void * _data, unsigned int _value)
+        : era(_era), msec(_msec), delta(_delta), func(_func), data(_data), value(_value), valid(true) {};
+
+        unsigned int   era;
+        unsigned int  msec;
+
+        unsigned int  delta;
+
+        const void *  func;
+        const void *  data;
+
+        unsigned int value;
+
+        bool         valid;
+
+        void reset(void) { era = 0; msec = 0; valid = false; };
+    };
+
+    /* timer add/remove functions */
+    Index traits_add (unsigned int msecs, const void * func, const void * data = 0, unsigned int value = 0);
+
+    bool traits_restart (Index & idx, bool force);
+
+    bool traits_del (Index & idx);
+    bool traits_del (const void * func, const void * data = 0, unsigned int value = 0);
+
+    /* timer start/stop functions */
+    bool start(void);
+    bool stop(void);
+
+  protected:
+    Index traits_add_unlocked (unsigned int msecs, const void * func, const void * data, unsigned int value);
+
+    bool traits_del_unlocked (Index & idx);
+
+  protected:
+    void execute(ControlSet::iterator, const Control &);
+
+    void loop(void);
+
+    struct loop_thread
+    {
+        loop_thread(TimerTraits *timer) : _timer(timer) {};
+
+        int operator()(void);
+
+      protected:
+        TimerTraits * _timer;
+    };
+
+    unsigned int tick();
+
+    /* variables */
+
+    SavedCondition   _condition;
+
+    SimpleLock       _mutex;
+    Thread         * _thread;
+    bool             _purify;
+
+    ControlSet       _timer_set;
+
+    unsigned int     _last_tick;
+    unsigned int     _age_count;
+
+    SavedCondition   _finalized;
+    bool             _shutdown;
+};
+
+template < typename F, typename D >
+struct TimerTemplate: NEW_REFCOUNTER(TimerTemplate< F, D >)
+{
+    typedef TimerTraits::Index   Index;
+    typedef TimerTraits::Control Control;
+
+    TimerTemplate()
+    : _timer(new TimerTraits())
+    {};
+
+    TimerTemplate(const TimerTemplate< F, D > & o)
+    : INC_REFCOUNTER(o, TimerTemplate< F, D >),
+      _timer(o._timer)
+    {};
+
+    void unreference(void)
+    {
+        if (_timer)
+            delete _timer;
+    };
+
+    bool start() { return _timer->start(); }
+    bool stop()  { return _timer->stop();  }
+
+    inline Index add(unsigned int msecs, F * func, D data = 0, unsigned int value = 0)
+    {
+        return _timer->traits_add(msecs, (const void *)func, (void *)(data), value);
+    }
+
+    inline bool restart(Index & idx, bool force = false)
+    {
+        return _timer->traits_restart(idx, force);
+    }
+
+    inline bool del(Index & idx)
+    {
+        return _timer->traits_del(idx);
+    }
+
+    inline bool del(F * func, D data, unsigned int value = 0)
+    {
+        return _timer->traits_del((const void *)func, (void *)(data), value);
+    }
+
+    inline bool del(unsigned int value)
+    {
+        return _timer->traits_del((const void *)0, (void *)0, value);
+    }
+
+  protected:
+    TimerTraits * _timer;
+};
+
+#endif /* _TIMER_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/types.hpp b/src/mod/endpoints/mod_khomp/commons/types.hpp
new file mode 100644 (file)
index 0000000..adbd8ab
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#ifndef _TYPES_HPP_
+#define _TYPES_HPP_
+
+/*** Used for conditional compilation based on K3L version ***/
+
+#define K3L_AT_LEAST(major,minor,build) \
+    (((k3lApiMajorVersion == major) && ((k3lApiMinorVersion == minor) && (k3lApiBuildVersion >= build)) || \
+     ((k3lApiMajorVersion == major) && (k3lApiMinorVersion > minor))) || \
+      (k3lApiMajorVersion  > major))
+
+#define K3L_EXACT(major,minor,build) \
+    ((k3lApiMajorVersion == major) && (k3lApiMinorVersion == minor) && (k3lApiBuildVersion >= build))
+
+/*** Used for checking information on classes and stuff.. ***/
+
+template< typename T >
+class IsClass
+{
+  protected:
+    template< typename X > static char ( &A( void(X::*)() ) )[1];
+    template< typename X > static char ( &A( X ) )[2];
+  public:
+    static bool const Result = sizeof( A< T >(0) ) == 1;
+};
+
+/*** Used for template metaprogramming ***/
+
+template < bool Value, typename Then, typename Else >
+struct Select
+{
+    typedef Then Result;
+};
+
+template < typename Then, typename Else >
+struct Select < false, Then, Else >
+{
+    typedef Else Result;
+};
+
+#endif /* _TYPES_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/commons/variant.hpp b/src/mod/endpoints/mod_khomp/commons/variant.hpp
new file mode 100644 (file)
index 0000000..410a770
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <refcounter.hpp>
+
+#include <typeinfo>
+
+#ifndef _VARIANT_H_
+#define _VARIANT_H_
+
+/* this is internal, should not be used by the user */
+struct NoArgumentDefined {};
+
+template < typename UserReturnType, typename UserArgumentType = NoArgumentDefined >
+struct VariantBaseType
+{
+    typedef UserReturnType       ReturnType;
+    typedef UserArgumentType   ArgumentType;
+
+    virtual ~VariantBaseType() {};
+
+    virtual int which() = 0;
+
+    virtual ReturnType visit(void)           { return ReturnType(); };
+    virtual ReturnType visit(ArgumentType)   { return ReturnType(); };
+};
+
+template < typename BaseType = VariantBaseType < void > >
+struct Variant: NEW_REFCOUNTER(Variant < BaseType >)
+{
+    typedef typename BaseType::ReturnType        ReturnType;
+    typedef typename BaseType::ArgumentType    ArgumentType;
+
+    struct InvalidType {};
+
+    Variant(BaseType * value, bool is_owner = false)
+    : _value(value), _is_owner(is_owner) {};
+
+    Variant(const Variant & v)
+    : INC_REFCOUNTER(v, Variant < BaseType >),
+      _value(v._value), _is_owner(v._is_owner) {};
+
+    virtual ~Variant() {};
+
+    void unreference()
+    {
+        if (_is_owner && _value)
+        {
+            delete _value;
+            _value = 0;
+        }
+    };
+
+    template < typename ValueType >
+    ValueType & get(void)
+    {
+        try
+        {
+            ValueType & ret = dynamic_cast < ValueType & > (*_value);
+            return ret;
+        }
+        catch (std::bad_cast & e)
+        {
+            throw InvalidType();
+        }
+    };
+
+    int which()
+    {
+        return _value->which();
+    }
+
+    ReturnType visit(void)
+    {
+        return _value->visit();
+    }
+
+    ReturnType visit(ArgumentType arg)
+    {
+        return _value->visit(arg);
+    }
+
+ protected:
+    BaseType * _value;
+    bool       _is_owner;
+};
+
+#endif /* _VARIANT_H_ */
+
diff --git a/src/mod/endpoints/mod_khomp/commons/verbose.cpp b/src/mod/endpoints/mod_khomp/commons/verbose.cpp
new file mode 100644 (file)
index 0000000..182d159
--- /dev/null
@@ -0,0 +1,3188 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <strings.hpp>
+#include <verbose.hpp>
+
+#define PRESENTATION_CHECK_RETURN(fmt, txtexact, txthuman) \
+    { \
+        switch(fmt) \
+        { \
+            case EXACT: return txtexact; \
+            case HUMAN: return txthuman; \
+        } \
+        return txtexact; \
+    }
+
+/********************************************/
+
+std::string Verbose::channelStatus(int32 dev, int32 obj, int32 cs, Verbose::Presentation fmt)
+{
+    try
+    {
+        K3L_CHANNEL_CONFIG & config = _api.channel_config(dev, obj);
+        return Verbose::channelStatus(config.Signaling, cs, fmt);
+    }
+    catch (...)
+    {
+        return presentation(fmt, "<unknown>", "Unknown");
+    }
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::event(int32 obj, K3L_EVENT *ev, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::event(int32 obj, K3L_EVENT *ev, Verbose::Presentation fmt)
+#endif
+{
+    try
+    {
+        K3L_CHANNEL_CONFIG & config = _api.channel_config(ev->DeviceId, obj);
+#if K3L_AT_LEAST(2,0,0)
+        return Verbose::event(config.Signaling, obj, ev, r2_country, fmt);
+#else
+        return Verbose::event(config.Signaling, obj, ev, fmt);
+#endif
+    }
+    catch (...)
+    {
+#if K3L_AT_LEAST(2,0,0)
+        return Verbose::event(ksigInactive, obj, ev, r2_country, fmt);
+#else
+        return Verbose::event(ksigInactive, obj, ev, fmt);
+#endif
+    }
+}
+
+/********************************************/
+
+std::string Verbose::echoLocation(KEchoLocation ec, Verbose::Presentation fmt)
+{
+    switch (ec)
+    {
+#if K3L_AT_LEAST(1,5,4)
+        case kelNetwork: return presentation(fmt, "kelNetwork", "Network");
+#else
+        case kelE1:      return presentation(fmt, "kelE1",      "Network");
+#endif
+        case kelCtBus:   return presentation(fmt, "kelCtBus",   "CT-Bus");
+    };
+
+    return presentation(fmt, "<unknown>", "Unknown");
+};
+
+std::string Verbose::echoCancellerConfig(KEchoCancellerConfig ec, Verbose::Presentation fmt)
+{
+    switch (ec)
+    {
+        case keccNotPresent:    return presentation(fmt, "keccNotPresent",    "Not Present");
+        case keccOneSingleBank: return presentation(fmt, "keccOneSingleBank", "One, Single Bank");
+        case keccOneDoubleBank: return presentation(fmt, "keccOneDoubleBank", "One, Double Bank");
+        case keccTwoSingleBank: return presentation(fmt, "keccTwoSingleBank", "Two, Single Bank");
+        case keccTwoDoubleBank: return presentation(fmt, "keccTwoDoubleBank", "Two, Double Bank");
+        case keccFail:          return presentation(fmt, "keccFail",          "Failure");
+    };
+
+    return presentation(fmt, "<unknown>", "Unknown");
+};
+
+// TODO: internal_deviceType / internal_deviceModel
+
+std::string Verbose::deviceName(KDeviceType dt, int32 model, Verbose::Presentation fmt)
+{
+    try
+    {
+        std::string value;
+
+        value += internal_deviceType(dt);
+        value += "-";
+        value += internal_deviceModel(dt, model);
+
+        return value;
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[type/model='%d/%d']") % (int)dt % (int)model),
+            STG(FMT("Unknown device type/model (%d/%d)") % (int)dt % (int)model));
+    }
+}
+
+std::string Verbose::deviceType(KDeviceType dt, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_deviceType(dt);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[type='%d']") % (int)dt),
+            STG(FMT("Unknown device type (%d)") % (int)dt));
+    }
+}
+
+std::string Verbose::internal_deviceType(KDeviceType dt)
+{
+    switch (dt)
+    {
+        case kdtE1:            return "K2E1";
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXO:           return "KFXO";
+#else
+        case kdtFX:            return "KFXO";
+#endif
+
+        case kdtConf:          return "KCONF";
+        case kdtPR:            return "KPR";
+        case kdtE1GW:          return "KE1GW";
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXOVoIP:       return "KFXVoIP";
+#else
+        case kdtFXVoIP:        return "KFXVoIP";
+#endif
+
+#if K3L_AT_LEAST(1,5,0)
+        case kdtE1IP:          return "K2E1";
+#endif
+#if K3L_AT_LEAST(1,5,1)
+        case kdtE1Spx:         return "K2E1";
+        case kdtGWIP:          return "KGWIP";
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXS:           return "KFXS";
+        case kdtFXSSpx:        return "KFXS";
+        case kdtGSM:           return "KGSM";
+        case kdtGSMSpx:        return "KGSM";
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        case kdtGSMUSB:        return "KGSMUSB";
+        case kdtGSMUSBSpx:     return "KGSMUSB";
+
+        case kdtE1FXSSpx:      return "KE1FXS";
+        case kdtDevTypeCount:  return "DevTypeCount";
+#endif
+
+#if K3L_EXACT(2,1,0)
+        case kdtReserved1:     return "Reserved1";
+#endif
+
+#if K3L_AT_LEAST(2,2,0)
+        case kdtE1AdHoc:       return "KE1AdHoc";
+#endif
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::deviceModel(KDeviceType dt, int32 model, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_deviceModel(dt, model);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[model='%d']") % (int)model),
+            STG(FMT("Unknown device model (%d)") % (int)model));
+    }
+}
+
+std::string Verbose::internal_deviceModel(KDeviceType dt, int32 model)
+{
+    switch (dt)
+    {
+        case kdtE1:
+            switch ((KE1DeviceModel)model)
+            {
+                case kdmE1600:   return "600";
+                case kdmE1600E:  return "600E";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmE1600EX: return "600EX";
+#endif
+            }
+            throw internal_not_found();
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXO:
+            switch ((KFXODeviceModel)model)
+#else
+        case kdtFX:
+            switch ((KFXDeviceModel)model)
+#endif
+            {
+#if K3L_AT_LEAST(1,6,0)
+                case kdmFXO80:    return "80";
+                case kdmFXOHI:    return "HI";
+                case kdmFXO160HI: return "160HI";
+#if K3L_AT_LEAST(2,1,0)
+        case kdmFXO240HI: return "240HI";
+#endif
+#else
+                case kdmFXO80:    return "80";
+#endif
+            }
+
+            throw internal_not_found();
+
+        case kdtConf:
+            switch ((KConfDeviceModel)model)
+            {
+                case kdmConf240:   return "240";
+                case kdmConf120:   return "120";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmConf240EX: return "240EX";
+                case kdmConf120EX: return "120EX";
+#endif
+            }
+
+            throw internal_not_found();
+
+        case kdtPR:
+            switch ((KPRDeviceModel)model)
+            {
+#if K3L_AT_LEAST(1,6,0)
+                case kdmPR300v1:       return "300v1";
+                case kdmPR300SpxBased: return "300S";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmPR300EX:       return "300EX";
+#endif
+                case kdmPR300:         return "300";
+            }
+#endif
+            throw internal_not_found();
+
+#if K3L_AT_LEAST(1,4,0)
+        case kdtE1GW:
+            switch ((KE1GWDeviceModel)model)
+            {
+#if K3L_AT_LEAST(1,6,0)
+                case kdmE1GW640:  return "640";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmE1GW640EX:  return "640EX";
+#endif
+#else
+                case kdmE1600V:  return "600V";
+                case kdmE1600EV: return "600EV";
+#endif
+            }
+
+            throw internal_not_found();
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXOVoIP:
+            switch ((KFXOVoIPDeviceModel)model)
+            {
+                case kdmFXGW180:  return "180";
+            }
+
+            throw internal_not_found();
+
+#elif K3L_AT_LEAST(1,4,0)
+        case kdtFXVoIP:
+            switch ((KFXVoIPDeviceModel)model)
+            {
+                case kdmFXO80V: return "80V";
+            }
+
+            throw internal_not_found();
+#endif
+
+#if K3L_AT_LEAST(1,5,0)
+        case kdtE1IP:
+            switch ((KE1IPDeviceModel)model)
+            {
+#if K3L_AT_LEAST(1,6,0)
+                case kdmE1IP:  return "E1IP";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmE1IPEX:  return "E1IPEX";
+#endif
+#else
+                case kdmE1600EG: return "600EG";
+#endif
+            }
+
+            throw internal_not_found();
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+        case kdtE1Spx:
+            switch ((KE1SpxDeviceModel)model)
+            {
+                case kdmE1Spx:    return "SPX";
+                case kdm2E1Based: return "SPX-2E1";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmE1SpxEX:    return "SPXEX";
+#endif
+            }
+            throw internal_not_found();
+
+        case kdtGWIP:
+            switch ((KGWIPDeviceModel)model)
+            {
+#if K3L_AT_LEAST(1,6,0)
+                case kdmGWIP:     return "GWIP";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmGWIPEX:     return "GWIPEX";
+#endif
+#else
+                case kdmGW600G:   return "600G";
+                case kdmGW600EG:  return "600EG";
+#endif
+            }
+
+            throw internal_not_found();
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case kdtFXS:
+            switch ((KFXSDeviceModel)model)
+            {
+                case kdmFXS300:   return "300";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmFXS300EX:   return "300EX";
+#endif
+            }
+
+            throw internal_not_found();
+
+        case kdtFXSSpx:
+            switch ((KFXSSpxDeviceModel)model)
+            {
+                case kdmFXSSpx300:       return "SPX";
+                case kdmFXSSpx2E1Based:  return "SPX-2E1";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmFXSSpx300EX:       return "SPXEX";
+#endif
+            }
+
+            throw internal_not_found();
+
+        case kdtGSM:
+            switch ((KGSMDeviceModel)model)
+            {
+                case kdmGSM:       return "40";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmGSMEX:     return "40EX";
+#endif
+            }
+
+            throw internal_not_found();
+
+        case kdtGSMSpx:
+            switch ((KGSMSpxDeviceModel)model)
+            {
+                case kdmGSMSpx:    return "SPX";
+#if K3L_AT_LEAST(2,0,0)
+                case kdmGSMSpxEX:  return "SPXEX";
+#endif
+            }
+
+            throw internal_not_found();
+
+#if K3L_AT_LEAST(2,1,0)
+        case kdtGSMUSB:
+            switch ((KGSMUSBDeviceModel)model)
+            {
+                case kdmGSMUSB:    return "20";
+            }
+
+            throw internal_not_found();
+
+        case kdtGSMUSBSpx:
+            switch ((KGSMUSBSpxDeviceModel)model)
+            {
+                case kdmGSMUSBSpx: return "SPX";
+            }
+
+            throw internal_not_found();
+
+        case kdtE1FXSSpx:
+            switch ((KGSMSpxDeviceModel)model)
+            {
+                case kdmE1FXSSpx:   return "SPX";
+                case kdmE1FXSSpxEX: return "SPXEX";
+            }
+
+            throw internal_not_found();
+#if K3L_AT_LEAST(2,2,0)
+        case kdtE1AdHoc:
+            switch((KE1AdHocModel)model)
+            {
+                case kdmE1AdHoc100:  return "E1AdHoc100";
+                case kdmE1AdHoc100E: return "E1AdHoc100E";
+                case kdmE1AdHoc240:  return "E1AdHoc240";
+                case kdmE1AdHoc240E: return "E1AdHoc240E";
+                case kdmE1AdHoc400:  return "E1AdHoc240";
+                case kdmE1AdHoc400E: return "E1AdHoc240E";
+            }
+            throw internal_not_found();
+#endif
+
+#if K3L_EXACT(2,1,0)
+        case kdtReserved1:
+#endif
+        case kdtDevTypeCount:
+            throw internal_not_found();
+
+#endif
+#endif
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::signaling(KSignaling sig, Verbose::Presentation fmt)
+{
+    switch (sig)
+    {
+        case ksigInactive:      return presentation(fmt, "ksigInactive",        "Inactive");
+        case ksigAnalog:        return presentation(fmt, "ksigAnalog",          "FXO (analog)");
+        case ksigContinuousEM:  return presentation(fmt, "ksigContinuousEM",    "E+M Continuous");
+        case ksigPulsedEM:      return presentation(fmt, "ksigPulsedEM",        "E+M PUlsed");
+        case ksigOpenCAS:       return presentation(fmt, "ksigOpenCAS",         "Open CAS");
+        case ksigOpenR2:        return presentation(fmt, "ksigOpenR2",          "Open R2");
+        case ksigR2Digital:     return presentation(fmt, "ksigR2Digital",       "R2/MFC");
+        case ksigUserR2Digital: return presentation(fmt, "ksigUserR2Digital",   "R2/Other");
+#if K3L_AT_LEAST(1,4,0)
+        case ksigSIP:           return presentation(fmt, "ksigSIP",             "SIP");
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+        case ksigOpenCCS:       return presentation(fmt, "ksigOpenCCS",         "Open CCS");
+        case ksigPRI_EndPoint:  return presentation(fmt, "ksigPRI_EndPoint",    "ISDN Endpoint");
+        case ksigPRI_Network:   return presentation(fmt, "ksigPRI_Network",     "ISDN Network");
+        case ksigPRI_Passive:   return presentation(fmt, "ksigPRI_Passive",     "ISDN Passive");
+#endif
+#if K3L_AT_LEAST(1,5,3)
+        case ksigLineSide:        return presentation(fmt, "ksigLineSide",      "Line Side");
+#endif
+#if K3L_AT_LEAST(1,6,0)
+        case ksigAnalogTerminal: return presentation(fmt, "ksigAnalogTerminal", "FXS (analog)");
+        case ksigGSM:            return presentation(fmt, "ksigGSM",            "GSM");
+        case ksigCAS_EL7:        return presentation(fmt, "ksigCAS_EL7",        "CAS EL7");
+        case ksigE1LC:           return presentation(fmt, "ksigE1LC",           "E1 LC");
+#endif
+#if K3L_AT_LEAST(2,1,0)
+        case ksigISUP:           return presentation(fmt, "ksigISUP",           "ISUP");
+#endif
+#if K3L_EXACT(2,1,0)
+        case ksigFax:            return presentation(fmt, "ksigFax",            "Fax");
+#endif
+#if K3L_AT_LEAST(2,2,0)
+        case ksigISUPPassive:    return presentation(fmt, "ksigISUPPassive",    "ISUP Passive");
+#endif
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KSignaling='%d']") % (int)sig),
+        STG(FMT("Unknown signaling (%d)") % (int)sig));
+}
+
+std::string Verbose::systemObject(KSystemObject so, Verbose::Presentation fmt)
+{
+    switch (so)
+    {
+        case ksoLink:      return presentation(fmt, "ksoLink",      "Link");
+        case ksoLinkMon:   return presentation(fmt, "ksoLinkMon",   "Link Monitor");
+        case ksoChannel:   return presentation(fmt, "ksoChannel",   "Channel");
+#if K3L_AT_LEAST(2,1,0)
+        case ksoGsmChannel:return presentation(fmt, "ksoGsmChannel","GsmChannel");
+#endif
+        case ksoH100:      return presentation(fmt, "ksoH100",      "H.100");
+        case ksoFirmware:  return presentation(fmt, "ksoFirmware",  "Firmware");
+        case ksoDevice:    return presentation(fmt, "ksoDevice",    "Device");
+        case ksoAPI:       return presentation(fmt, "ksoAPI",       "Software Layer");
+    }
+
+    return presentation(fmt,
+        STG(FMT("[KSystemObject='%d']") % (int)so),
+        STG(FMT("Unknown object (%d)") % (int)so));
+}
+
+std::string Verbose::mixerTone(KMixerTone mt, Verbose::Presentation fmt)
+{
+    switch (mt)
+    {
+        case kmtSilence:   return presentation(fmt, "kmtSilence",   "Silence");
+        case kmtDial:      return presentation(fmt, "kmtDial",      "Dialtone begin");
+        case kmtEndOf425:  return presentation(fmt, "kmtEndOf425",  "Dialtone end");
+        case kmtBusy:      return presentation(fmt, "kmtBusy",      "Busy");
+        case kmtFax:       return presentation(fmt, "kmtFax",       "Fax");
+        case kmtVoice:     return presentation(fmt, "kmtVoice",     "Voice");
+#if K3L_AT_LEAST(1,5,0)
+        case kmtCollect:   return presentation(fmt, "kmtCollect",   "Collect Call");
+#endif
+#if K3L_AT_LEAST(1,5,1)
+        case kmtEndOfDtmf: return presentation(fmt, "kmtEndOfDtmf", "DTMF end");
+#endif
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KMixerTone='%d']") % (int)mt),
+        STG(FMT("Unknonwn tone (%d)") % (int)mt));
+}
+
+std::string Verbose::mixerSource(KMixerSource ms, Verbose::Presentation fmt)
+{
+    switch (ms)
+    {
+        case kmsChannel:        return presentation(fmt, "kmsChannel",        "Channel");
+        case kmsPlay:           return presentation(fmt, "kmsPlay",           "Player");
+        case kmsGenerator:      return presentation(fmt, "kmsGenerator",      "Generator");
+        case kmsCTbus:          return presentation(fmt, "kmsCTbus",          "CT-bus");
+#if (K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(1,6,0))
+        case kmsVoIP:           return presentation(fmt, "kmsVoIP",           "VoIP");
+#endif
+#if K3L_AT_LEAST(1,6,0)
+        case kmsNoDelayChannel: return presentation(fmt, "kmsNoDelayChannel", "No delay channel");
+#endif
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KMixerSource='%d']") % (int)ms),
+        STG(FMT("Unknonwn source (%d)") % (int)ms));
+}
+
+std::string Verbose::channelFeatures(int32 flags, Verbose::Presentation fmt)
+{
+    if (0x00 != flags)
+    {
+        Strings::Merger strs;
+
+        if (kcfDtmfSuppression & flags)   strs.add(presentation(fmt, "DtmfSuppression",   "DTMF Suppression"));
+        if (kcfCallProgress & flags)      strs.add(presentation(fmt, "CallProgress",      "Call Progress"));
+        if (kcfPulseDetection & flags)    strs.add(presentation(fmt, "PulseDetection",    "Pulse Detection"));
+        if (kcfAudioNotification & flags) strs.add(presentation(fmt, "AudioNotification", "Audio Notification"));
+        if (kcfEchoCanceller & flags)     strs.add(presentation(fmt, "EchoCanceller",     "Echo Canceller"));
+        if (kcfAutoGainControl & flags)   strs.add(presentation(fmt, "AutoGainControl",   "Input AGC"));
+        if (kcfHighImpEvents & flags)     strs.add(presentation(fmt, "HighImpEvents",     "High Impedance Events"));
+#if K3L_AT_LEAST(1,6,0)
+        if (kcfCallAnswerInfo & flags)    strs.add(presentation(fmt, "CallAnswerInfo",    "Call Answer Info"));
+#if !K3L_AT_LEAST(2,2,0)
+        if (kcfOutputVolume & flags)      strs.add(presentation(fmt, "OutputVolume",      "Output Volume"));
+#endif
+        if (kcfPlayerAGC & flags)         strs.add(presentation(fmt, "PlayerAGC",         "Player AGC"));
+#endif
+
+        return presentation(fmt,
+            STG(FMT("kcf{%s}") % strs.merge(",")),
+            STG(FMT("%s") % strs.merge(", ")));
+    };
+
+    PRESENTATION_CHECK_RETURN(fmt, "", "No features");
+}
+
+std::string Verbose::seizeFail(KSeizeFail sf, Verbose::Presentation fmt)
+{
+    switch (sf)
+    {
+        case ksfChannelLocked:   return presentation(fmt, "ksfChannelLocked",   "Channel Locked");
+        case ksfChannelBusy:     return presentation(fmt, "ksfChannelBusy",     "Channel Busy");
+        case ksfIncomingChannel: return presentation(fmt, "ksfIncomingChannel", "Incoming Channel");
+        case ksfDoubleSeizure:   return presentation(fmt, "ksfDoubleSeizure",   "Double Seizure");
+        case ksfCongestion:      return presentation(fmt, "ksfCongestion",      "Congestion");
+        case ksfNoDialTone:      return presentation(fmt, "ksfNoDialTone",      "No Dial Tone");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KSeizeFail='%d']") % (int)sf),
+        STG(FMT("Unknown seize fail (%d)") % (int)sf));
+}
+
+#if K3L_AT_LEAST(1,5,0)
+std::string Verbose::internal_sipFailures(KSIP_Failures code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+#if K3L_AT_LEAST(1,6,0)
+        case kveResponse_200_OK_Success:                 return presentation(fmt, "kveResponse_200_OK_Success",                 "200 OK");
+#endif
+        case kveRedirection_300_MultipleChoices:         return presentation(fmt, "kveRedirection_300_MultipleChoices",         "300 Multiple Choices");
+        case kveRedirection_301_MovedPermanently:        return presentation(fmt, "kveRedirection_301_MovedPermanently",        "301 Moved Permanently");
+        case kveRedirection_302_MovedTemporarily:        return presentation(fmt, "kveRedirection_302_MovedTemporarily",        "302 Moved Temporarily");
+        case kveRedirection_305_UseProxy:                return presentation(fmt, "kveRedirection_305_UseProxy",                "305 Use Proxy");
+        case kveRedirection_380_AlternativeService:      return presentation(fmt, "kveRedirection_380_AlternativeService",      "380 Alternate Service");
+        case kveFailure_400_BadRequest:                  return presentation(fmt, "kveFailure_400_BadRequest",                  "400 Bad Request");
+        case kveFailure_401_Unauthorized:                return presentation(fmt, "kveFailure_401_Unauthorized",                "401 Unauthorized");
+        case kveFailure_402_PaymentRequired:             return presentation(fmt, "kveFailure_402_PaymentRequired",             "402 Payment Required");
+        case kveFailure_403_Forbidden:                   return presentation(fmt, "kveFailure_403_Forbidden",                   "403 Forbidden");
+        case kveFailure_404_NotFound:                    return presentation(fmt, "kveFailure_404_NotFound",                    "404 Not Found");
+        case kveFailure_405_MethodNotAllowed:            return presentation(fmt, "kveFailure_405_MethodNotAllowed",            "405 Method Not Allowed");
+        case kveFailure_406_NotAcceptable:               return presentation(fmt, "kveFailure_406_NotAcceptable",               "406 Not Acceptable");
+        case kveFailure_407_ProxyAuthenticationRequired: return presentation(fmt, "kveFailure_407_ProxyAuthenticationRequired", "407 Proxy Authentication Required");
+        case kveFailure_408_RequestTimeout:              return presentation(fmt, "kveFailure_408_RequestTimeout",              "408 Request Timeout");
+        case kveFailure_410_Gone:                        return presentation(fmt, "kveFailure_410_Gone",                        "410 Gone");
+        case kveFailure_413_RequestEntityTooLarge:       return presentation(fmt, "kveFailure_413_RequestEntityTooLarge",       "413 Request Entity Too Large");
+        case kveFailure_414_RequestURI_TooLong:          return presentation(fmt, "kveFailure_414_RequestURI_TooLong",          "414 Request URI Too Long");
+        case kveFailure_415_UnsupportedMediaType:        return presentation(fmt, "kveFailure_415_UnsupportedMediaType",        "415 Unsupported Media Type");
+        case kveFailure_416_UnsupportedURI_Scheme:       return presentation(fmt, "kveFailure_416_UnsupportedURI_Scheme",       "416 Unsupported URI Scheme");
+        case kveFailure_420_BadExtension:                return presentation(fmt, "kveFailure_420_BadExtension",                "420 Bad Extension");
+        case kveFailure_421_ExtensionRequired:           return presentation(fmt, "kveFailure_421_ExtensionRequired",           "421 Extension Required");
+        case kveFailure_423_IntervalTooBrief:            return presentation(fmt, "kveFailure_423_IntervalTooBrief",            "423 Internal Too Brief");
+        case kveFailure_480_TemporarilyUnavailable:      return presentation(fmt, "kveFailure_480_TemporarilyUnavailable",      "480 Temporarily Unavailable");
+        case kveFailure_481_CallDoesNotExist:            return presentation(fmt, "kveFailure_481_CallDoesNotExist",            "481 Call Does Not Exist");
+        case kveFailure_482_LoopDetected:                return presentation(fmt, "kveFailure_482_LoopDetected",                "482 Loop Detected");
+        case kveFailure_483_TooManyHops:                 return presentation(fmt, "kveFailure_483_TooManyHops",                 "483 Too Many Hops");
+        case kveFailure_484_AddressIncomplete:           return presentation(fmt, "kveFailure_484_AddressIncomplete",           "484 Address Incomplete");
+        case kveFailure_485_Ambiguous:                   return presentation(fmt, "kveFailure_485_Ambiguous",                   "485 Ambiguous");
+        case kveFailure_486_BusyHere:                    return presentation(fmt, "kveFailure_486_BusyHere",                    "486 Busy Here");
+        case kveFailure_487_RequestTerminated:           return presentation(fmt, "kveFailure_487_RequestTerminated",           "487 Request Terminated");
+        case kveFailure_488_NotAcceptableHere:           return presentation(fmt, "kveFailure_488_NotAcceptableHere",           "488 Not Acceptable Here");
+        case kveFailure_491_RequestPending:              return presentation(fmt, "kveFailure_491_RequestPending",              "491 Request Pending");
+        case kveFailure_493_Undecipherable:              return presentation(fmt, "kveFailure_493_Undecipherable",              "493 Undecipherable");
+        case kveServer_500_InternalError:                return presentation(fmt, "kveServer_500_InternalError",                "500 Internal Error");
+        case kveServer_501_NotImplemented:               return presentation(fmt, "kveServer_501_NotImplemented",               "501 Not Implemented");
+        case kveServer_502_BadGateway:                   return presentation(fmt, "kveServer_502_BadGateway",                   "502 Bad Gateway");
+        case kveServer_503_ServiceUnavailable:           return presentation(fmt, "kveServer_503_ServiceUnavailable",           "503 Service Unavailable");
+        case kveServer_504_TimeOut:                      return presentation(fmt, "kveServer_504_TimeOut",                      "504 Timed Out");
+        case kveServer_505_VersionNotSupported:          return presentation(fmt, "kveServer_505_VersionNotSupported",          "505 Version Not Supported");
+        case kveServer_513_MessageTooLarge:              return presentation(fmt, "kveServer_513_MessageTooLarge",              "513 Message Too Large");
+        case kveGlobalFailure_600_BusyEverywhere:        return presentation(fmt, "kveGlobalFailure_600_BusyEverywhere",        "600 Busy Everywhere");
+        case kveGlobalFailure_603_Decline:               return presentation(fmt, "kveGlobalFailure_603_Decline",               "603 Decline");
+        case kveGlobalFailure_604_DoesNotExistAnywhere:  return presentation(fmt, "kveGlobalFailure_604_DoesNotExistAnywhere",  "604 Does Not Exist Anywhere");
+        case kveGlobalFailure_606_NotAcceptable:         return presentation(fmt, "kveGlobalFailure_606_NotAcceptable",         "606 Not Acceptable");
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::sipFailures(KSIP_Failures code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_sipFailures(code, fmt);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KSIP_Failures='%d']") % (int)code),
+            STG(FMT("Unknown SIP failure (%d)") % (int)code));
+    }
+}
+
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+std::string Verbose::internal_isdnCause(KQ931Cause code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kq931cNone:                           return presentation(fmt, "kq931cNone",                           "None");
+        case kq931cUnallocatedNumber:              return presentation(fmt, "kq931cUnallocatedNumber",              "Unallocated number");
+        case kq931cNoRouteToTransitNet:            return presentation(fmt, "kq931cNoRouteToTransitNet",            "No route to transmit to network");
+        case kq931cNoRouteToDest:                  return presentation(fmt, "kq931cNoRouteToDest",                  "No route to destination");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cSendSpecialInfoTone:            return presentation(fmt, "kq931cSendSpecialInfoTone",            "Send special information tone");
+        case kq931cMisdialedTrunkPrefix:           return presentation(fmt, "kq931cMisdialedTrunkPrefix",           "Misdialed trunk prefix");
+#endif
+        case kq931cChannelUnacceptable:            return presentation(fmt, "kq931cChannelUnacceptable",            "Channel unacceptable");
+        case kq931cCallAwarded:                    return presentation(fmt, "kq931cCallAwarded",                    "Call awarded");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cPreemption:                     return presentation(fmt, "kq931cPreemption",                     "Preemption");
+        case kq931cPreemptionCircuitReuse:         return presentation(fmt, "kq931cPreemptionCircuitReuse",         "Preemption circuit reuse");
+        case kq931cQoR_PortedNumber:               return presentation(fmt, "kq931cQoR_PortedNumber",               "QoR ported number");
+#endif
+        case kq931cNormalCallClear:                return presentation(fmt, "kq931cNormalCallClear",                "Normal call clear");
+        case kq931cUserBusy:                       return presentation(fmt, "kq931cUserBusy",                       "User busy");
+        case kq931cNoUserResponding:               return presentation(fmt, "kq931cNoUserResponding",               "No user responding");
+        case kq931cNoAnswerFromUser:               return presentation(fmt, "kq931cNoAnswerFromUser",               "No answer from user");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cSubscriberAbsent:               return presentation(fmt, "kq931cSubscriberAbsent",               "Subscriber absent");
+#endif
+        case kq931cCallRejected:                   return presentation(fmt, "kq931cCallRejected",                   "Call rejected");
+        case kq931cNumberChanged:                  return presentation(fmt, "kq931cNumberChanged",                  "Number changed");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cRedirectionToNewDest:           return presentation(fmt, "kq931cRedirectionToNewDest",           "Redirection to new destination");
+        case kq931cCallRejectedFeatureDest:        return presentation(fmt, "kq931cCallRejectedFeatureDest",        "Call rejected feature destination");
+        case kq931cExchangeRoutingError:           return presentation(fmt, "kq931cExchangeRoutingError",           "Exchange routing error");
+#endif
+        case kq931cNonSelectedUserClear:           return presentation(fmt, "kq931cNonSelectedUserClear",           "Non selected user clear");
+        case kq931cDestinationOutOfOrder:          return presentation(fmt, "kq931cDestinationOutOfOrder",          "Destination out of order");
+        case kq931cInvalidNumberFormat:            return presentation(fmt, "kq931cInvalidNumberFormat",            "Invalid number format");
+        case kq931cFacilityRejected:               return presentation(fmt, "kq931cFacilityRejected",               "Facility rejected");
+        case kq931cRespStatusEnquiry:              return presentation(fmt, "kq931cRespStatusEnquiry",              "Response status enquiry");
+        case kq931cNormalUnspecified:              return presentation(fmt, "kq931cNormalUnspecified",              "Normal unespecified");
+        case kq931cNoCircuitChannelAvail:          return presentation(fmt, "kq931cNoCircuitChannelAvail",          "No circuit channel available");
+        case kq931cNetworkOutOfOrder:              return presentation(fmt, "kq931cNetworkOutOfOrder",              "Network out of order");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cPermanentFrameConnOutOfService: return presentation(fmt, "kq931cPermanentFrameConnOutOfService", "Permanent frame connection out of service");
+        case kq931cPermanentFrameConnOperational:  return presentation(fmt, "kq931cPermanentFrameConnOperational",  "Permanent frame connection operational");
+#endif
+        case kq931cTemporaryFailure:               return presentation(fmt, "kq931cTemporaryFailure",               "Temporary failure");
+        case kq931cSwitchCongestion:               return presentation(fmt, "kq931cSwitchCongestion",               "Switch congestion");
+        case kq931cAccessInfoDiscarded:            return presentation(fmt, "kq931cAccessInfoDiscarded",            "Access information discarded");
+        case kq931cRequestedChannelUnav:           return presentation(fmt, "kq931cRequestedChannelUnav",           "Requested channel unavailable");
+        case kq931cPrecedenceCallBlocked:          return presentation(fmt, "kq931cPrecedenceCallBlocked",          "Precedence call blocked");
+        case kq931cResourceUnavailable:            return presentation(fmt, "kq931cResourceUnavailable",            "Request resource unavailable");
+        case kq931cQosUnavailable:                 return presentation(fmt, "kq931cQosUnavailable",                 "QoS unavailable");
+        case kq931cReqFacilityNotSubsc:            return presentation(fmt, "kq931cReqFacilityNotSubsc",            "Request facility not subscribed");
+        case kq931cOutCallsBarredWithinCUG:        return presentation(fmt, "kq931cOutCallsBarredWithinCUG",        "Out calls barred within UG");
+        case kq931cInCallsBarredWithinCUG:         return presentation(fmt, "kq931cInCallsBarredWithinCUG",         "In calls barred within UG");
+        case kq931cBearerCapabNotAuthor:           return presentation(fmt, "kq931cBearerCapabNotAuthor",           "Bearer capability not authorized");
+        case kq931cBearerCapabNotAvail:            return presentation(fmt, "kq931cBearerCapabNotAvail",            "Bearer capability not available");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cInconsistency:                  return presentation(fmt, "kq931cInconsistency",                  "Inconsistency");
+#endif
+        case kq931cServiceNotAvailable:            return presentation(fmt, "kq931cServiceNotAvailable",            "Service not available");
+        case kq931cBcNotImplemented:               return presentation(fmt, "kq931cBcNotImplemented",               "Bearer capability not implemented");
+        case kq931cChannelTypeNotImplem:           return presentation(fmt, "kq931cChannelTypeNotImplem",           "Channel type not implemented");
+        case kq931cReqFacilityNotImplem:           return presentation(fmt, "kq931cReqFacilityNotImplem",           "Request facility not implemented");
+        case kq931cOnlyRestrictedBcAvail:          return presentation(fmt, "kq931cOnlyRestrictedBcAvail",          "Only restricted bearer capability available");
+        case kq931cServiceNotImplemented:          return presentation(fmt, "kq931cServiceNotImplemented",          "Service not implemented");
+        case kq931cInvalidCrv:                     return presentation(fmt, "kq931cInvalidCrv",                     "Invalid call reference value");
+        case kq931cChannelDoesNotExist:            return presentation(fmt, "kq931cChannelDoesNotExist",            "Channel does not exist");
+        case kq931cCallIdDoesNotExist:             return presentation(fmt, "kq931cCallIdDoesNotExist",             "Call identification does not exist");
+        case kq931cCallIdInUse:                    return presentation(fmt, "kq931cCallIdInUse",                    "Call identification in use");
+        case kq931cNoCallSuspended:                return presentation(fmt, "kq931cNoCallSuspended",                "No call suspended");
+        case kq931cCallIdCleared:                  return presentation(fmt, "kq931cCallIdCleared",                  "Call identification cleared");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cUserNotMemberofCUG:             return presentation(fmt, "kq931cUserNotMemberofCUG",             "User not member of UG");
+#endif
+        case kq931cIncompatibleDestination:        return presentation(fmt, "kq931cIncompatibleDestination",        "Incompatible destination");
+        case kq931cInvalidTransitNetSel:           return presentation(fmt, "kq931cInvalidTransitNetSel",           "Invalid transit network selected");
+        case kq931cInvalidMessage:                 return presentation(fmt, "kq931cInvalidMessage",                 "Invalid message");
+        case kq931cMissingMandatoryIe:             return presentation(fmt, "kq931cMissingMandatoryIe",             "Missing mandatory information element");
+        case kq931cMsgTypeNotImplemented:          return presentation(fmt, "kq931cMsgTypeNotImplemented",          "Message type not implemented");
+        case kq931cMsgIncompatWithState:           return presentation(fmt, "kq931cMsgIncompatWithState",           "Message incompatible with state");
+        case kq931cIeNotImplemented:               return presentation(fmt, "kq931cIeNotImplemented",               "Information element not implemented");
+        case kq931cInvalidIe:                      return presentation(fmt, "kq931cInvalidIe",                      "Invalid information element");
+        case kq931cMsgIncompatWithState2:          return presentation(fmt, "kq931cMsgIncompatWithState2",          "Message incompatible with state (2)");
+        case kq931cRecoveryOnTimerExpiry:          return presentation(fmt, "kq931cRecoveryOnTimerExpiry",          "Recovery on timer expiry");
+        case kq931cProtocolError:                  return presentation(fmt, "kq931cProtocolError",                  "Protocol error");
+#if 1 /* this changed during K3L 1.6.0 development cycle... */
+        case kq931cMessageWithUnrecognizedParam:   return presentation(fmt, "kq931cMessageWithUnrecognizedParam",   "Message with unrecognized parameters");
+        case kq931cProtocolErrorUnspecified:       return presentation(fmt, "kq931cProtocolErrorUnspecified",       "Protocol error unspecified");
+#endif
+        case kq931cInterworking:                   return presentation(fmt, "kq931cInterworking",                   "Interworking");
+        case kq931cCallConnected:                  return presentation(fmt, "kq931cCallConnected",                  "Call connected");
+        case kq931cCallTimedOut:                   return presentation(fmt, "kq931cCallTimedOut",                   "Call timeout");
+        case kq931cCallNotFound:                   return presentation(fmt, "kq931cCallNotFound",                   "Call not found");
+        case kq931cCantReleaseCall:                return presentation(fmt, "kq931cCantReleaseCall",                "Cannot realese call");
+        case kq931cNetworkFailure:                 return presentation(fmt, "kq931cNetworkFailure",                 "Network failure");
+        case kq931cNetworkRestart:                 return presentation(fmt, "kq931cNetworkRestart",                 "Network restart");
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::isdnCause(KQ931Cause code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_isdnCause(code);
+    }
+    catch (internal_not_found & e)
+    {
+        return STG(FMT("[KQ931Cause='%d']") % (int)code);
+    }
+}
+#endif
+
+#if K3L_AT_LEAST(1,5,2)
+std::string Verbose::isdnDebug(int32 flags, Verbose::Presentation fmt)
+{
+    if (0x00 != flags)
+    {
+        Strings::Merger strs;
+
+        if (flags & kidfQ931)   strs.add("Q931");
+        if (flags & kidfLAPD)   strs.add("LAPD");
+        if (flags & kidfSystem) strs.add("System");
+
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("kidf{%s}") % strs.merge(",")),
+            strs.merge(", "));
+    }
+
+    return presentation(fmt, "", "No debug active");
+}
+#endif
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::internal_signGroupB(KSignGroupB group, R2CountryType country, Verbose::Presentation fmt)
+#else
+std::string Verbose::internal_signGroupB(KSignGroupB group, Verbose::Presentation fmt)
+#endif
+{
+#if K3L_AT_LEAST(2,0,0)
+    switch (country)
+    {
+        case R2_COUNTRY_ARG:
+            switch ((KSignGroupB_Argentina)group)
+            {
+                case kgbArNumberChanged:       return presentation(fmt, "kgbArNumberChanged",      "Number Changed");
+                case kgbArBusy:                return presentation(fmt, "kgbArBusy",               "Busy");
+                case kgbArCongestion:          return presentation(fmt, "kgbArCongestion",         "Congestion");
+                case kgbArInvalidNumber:       return presentation(fmt, "kgbArInvalidNumber",      "Invalid Number");
+                case kgbArLineFreeCharged:     return presentation(fmt, "kgbArLineFreeCharged",    "Line Free Charged");
+                case kgbArLineFreeNotCharged:  return presentation(fmt, "kgbArLineFreeNotCharged", "Line Free Not Charged");
+                case kgbArLineOutOfOrder:      return presentation(fmt, "kgbArLineOutOfOrder",     "Line Out Of Order");
+                case kgbArNone:                return presentation(fmt, "kgbArNone",               "None");
+            }
+            break;
+
+        case R2_COUNTRY_BRA:
+            switch ((KSignGroupB_Brazil)group)
+            {
+                case kgbBrLineFreeCharged:     return presentation(fmt, "kgbBrLineFreeCharged",    "Line Free Charged");
+                case kgbBrLineFreeNotCharged:  return presentation(fmt, "kgbBrLineFreeNotCharged", "Line Free Not Charged");
+                case kgbBrLineFreeChargedLPR:  return presentation(fmt, "kgbBrLineFreeChargedLPR", "Line Free Charged PLR");
+                case kgbBrBusy:                return presentation(fmt, "kgbBrBusy",               "Busy");
+                case kgbBrNumberChanged:       return presentation(fmt, "kgbBrNumberChanged",      "Number Changed");
+                case kgbBrCongestion:          return presentation(fmt, "kgbBrCongestion",         "Congestion");
+                case kgbBrInvalidNumber:       return presentation(fmt, "kgbBrInvalidNumber",      "Invalid Number");
+                case kgbBrLineOutOfOrder:      return presentation(fmt, "kgbBrLineOutOfOrder",     "Line Out Of Order");
+                case kgbBrNone:                return presentation(fmt, "kgbBrNone",               "None");
+            }
+            break;
+
+        case R2_COUNTRY_CHI:
+            switch ((KSignGroupB_Chile)group)
+            {
+                case kgbClNumberChanged:       return presentation(fmt, "kgbClNumberChanged",      "Number Changed");
+                case kgbClBusy:                return presentation(fmt, "kgbClBusy",               "Busy");
+                case kgbClCongestion:          return presentation(fmt, "kgbClCongestion",         "Congestion");
+                case kgbClInvalidNumber:       return presentation(fmt, "kgbClInvalidNumber",      "Invalid Number");
+                case kgbClLineFreeCharged:     return presentation(fmt, "kgbClLineFreeCharged",    "Line Free Charged");
+                case kgbClLineFreeNotCharged:  return presentation(fmt, "kgbClLineFreeNotCharged", "Line Free Not Charged");
+                case kgbClLineOutOfOrder:      return presentation(fmt, "kgbClLineOutOfOrder",     "Line Out Of Order");
+                case kgbClNone:                return presentation(fmt, "kgbClNone",               "None");
+            }
+            break;
+
+        case R2_COUNTRY_MEX:
+            switch ((KSignGroupB_Mexico)group)
+            {
+                case kgbMxLineFreeCharged:     return presentation(fmt, "kgbMxLineFreeCharged",    "Line Free Charged");
+                case kgbMxBusy:                return presentation(fmt, "kgbMxBusy",               "Busy");
+                case kgbMxLineFreeNotCharged:  return presentation(fmt, "kgbMxLineFreeNotCharged", "Line Free Not Charged");
+                case kgbMxNone:                return presentation(fmt, "kgbMxNone",               "None");
+            }
+            break;
+
+        case R2_COUNTRY_URY:
+            switch ((KSignGroupB_Uruguay)group)
+            {
+                case kgbUyNumberChanged:       return presentation(fmt, "kgbUyNumberChanged",      "Number Changed");
+                case kgbUyBusy:                return presentation(fmt, "kgbUyBusy",               "Busy");
+                case kgbUyCongestion:          return presentation(fmt, "kgbUyCongestion",         "Congestion");
+                case kgbUyInvalidNumber:       return presentation(fmt, "kgbUyInvalidNumber",      "Invalid Number");
+                case kgbUyLineFreeCharged:     return presentation(fmt, "kgbUyLineFreeCharged",    "Line Free Charged");
+                case kgbUyLineFreeNotCharged:  return presentation(fmt, "kgbUyLineFreeNotCharged", "Line Free Not Charged");
+                case kgbUyLineOutOfOrder:      return presentation(fmt, "kgbUyLineOutOfOrder",     "Line Out Of Order");
+                case kgbUyNone:                return presentation(fmt, "kgbUyNone",               "None");
+            }
+            break;
+
+        case R2_COUNTRY_VEN:
+            switch ((KSignGroupB_Venezuela)group)
+            {
+                case kgbVeLineFreeChargedLPR:  return presentation(fmt, "kgbVeLineFreeChargedLPR", "Line Free Charged PLR");
+                case kgbVeNumberChanged:       return presentation(fmt, "kgbVeNumberChanged",      "Number Changed");
+                case kgbVeBusy:                return presentation(fmt, "kgbVeBusy",               "Busy");
+                case kgbVeCongestion:          return presentation(fmt, "kgbVeCongestion",         "Congestion");
+                case kgbVeInformationTone:     return presentation(fmt, "kgbVeInformationTone",    "Information Tone");
+                case kgbVeLineFreeCharged:     return presentation(fmt, "kgbVeLineFreeCharged",    "Line Free Charged");
+                case kgbVeLineFreeNotCharged:  return presentation(fmt, "kgbVeLineFreeNotCharged", "Line Free Not Charged");
+                case kgbVeLineBlocked:         return presentation(fmt, "kgbVeLineBlocked",        "Line Blocked");
+                case kgbVeIntercepted:         return presentation(fmt, "kgbVeIntercepted",        "Intercepted");
+                case kgbVeDataTrans:           return presentation(fmt, "kgbVeDataTrans",          "Data Transfer");
+                case kgbVeNone:                return presentation(fmt, "kgbVeNone",               "None");
+            }
+            break;
+    }
+#else
+    switch ((KSignGroupB)group)
+    {
+        case kgbLineFreeCharged:     return presentation(fmt, "kgbLineFreeCharged",    "Line Free Charged");
+        case kgbLineFreeNotCharged:  return presentation(fmt, "kgbLineFreeNotCharged", "Line Free Not Charged");
+        case kgbLineFreeChargedLPR:  return presentation(fmt, "kgbLineFreeChargedLPR", "Line Free Charged PLR");
+        case kgbBusy:                return presentation(fmt, "kgbBusy",               "Busy");
+        case kgbNumberChanged:       return presentation(fmt, "kgbNumberChanged",      "Number Changed");
+        case kgbCongestion:          return presentation(fmt, "kgbCongestion",         "Congestion");
+        case kgbInvalidNumber:       return presentation(fmt, "kgbInvalidNumber",      "Invalid Number");
+        case kgbLineOutOfOrder:      return presentation(fmt, "kgbLineOutOfOrder",     "Line Out Of Order");
+        case kgbNone:                return presentation(fmt, "kgbNone",               "None");
+    }
+#endif
+
+    throw internal_not_found();
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::signGroupB(KSignGroupB group, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::signGroupB(KSignGroupB group, Verbose::Presentation fmt)
+#endif
+{
+    try
+    {
+#if K3L_AT_LEAST(2,0,0)
+        return internal_signGroupB(group, r2_country, fmt);
+#else
+        return internal_signGroupB(group, fmt);
+#endif
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KSignGroupB='%d']") % (int)group),
+            STG(FMT("Unknown group B (%d)") % (int)group));
+    }
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::internal_signGroupII(KSignGroupII group, R2CountryType country, Verbose::Presentation fmt)
+#else
+std::string Verbose::internal_signGroupII(KSignGroupII group, Verbose::Presentation fmt)
+#endif
+{
+#if K3L_AT_LEAST(2,0,0)
+    switch (country)
+    {
+        case R2_COUNTRY_ARG:
+            switch ((KSignGroupII_Argentina)group)
+            {
+                case kg2ArOrdinary:             return presentation(fmt, "kg2ArOrdinary",            "Ordinary");
+                case kg2ArPriority:             return presentation(fmt, "kg2ArPriority",            "Priority");
+                case kg2ArMaintenance:          return presentation(fmt, "kg2ArMaintenance",         "Maintenance");
+                case kg2ArLocalPayPhone:        return presentation(fmt, "kg2ArLocalPayPhone",       "Local pay phone");
+                case kg2ArTrunkOperator:        return presentation(fmt, "kg2ArTrunkOperator",       "Trunk operator");
+                case kg2ArDataTrans:            return presentation(fmt, "kg2ArDataTrans",           "Data transfer");
+                case kg2ArCPTP:                 return presentation(fmt, "kg2ArCPTP",                "CPTP");
+                case kg2ArSpecialLine:          return presentation(fmt, "kg2ArSpecialLine",         "Special line");
+                case kg2ArMobileUser:           return presentation(fmt, "kg2ArMobileUser",          "Mobile user");
+                case kg2ArPrivateRedLine:       return presentation(fmt, "kg2ArPrivateRedLine",      "Private red line");
+                case kg2ArSpecialPayPhoneLine:  return presentation(fmt, "kg2ArSpecialPayPhoneLine", "Special pay phone line");
+            }
+            break;
+
+        case R2_COUNTRY_BRA:
+            switch ((KSignGroupII_Brazil)group)
+            {
+                case kg2BrOrdinary:         return presentation(fmt, "kg2BrOrdinary",            "Ordinary");
+                case kg2BrPriority:         return presentation(fmt, "kg2BrPriority",            "Priority");
+                case kg2BrMaintenance:      return presentation(fmt, "kg2BrMaintenance",         "Maintenance");
+                case kg2BrLocalPayPhone:    return presentation(fmt, "kg2BrLocalPayPhone",       "Local pay phone");
+                case kg2BrTrunkOperator:    return presentation(fmt, "kg2BrTrunkOperator",       "Trunk operator");
+                case kg2BrDataTrans:        return presentation(fmt, "kg2BrDataTrans",           "Data transfer");
+                case kg2BrNonLocalPayPhone: return presentation(fmt, "kg2BrNonLocalPayPhone",    "Non local pay phone");
+                case kg2BrCollectCall:      return presentation(fmt, "kg2BrCollectCall",         "Collect call");
+                case kg2BrOrdinaryInter:    return presentation(fmt, "kg2BrOrdinaryInter",       "Ordinary international");
+                case kg2BrTransfered:       return presentation(fmt, "kg2BrTransfered",          "Transfered");
+            }
+            break;
+
+        case R2_COUNTRY_CHI:
+            switch ((KSignGroupII_Chile)group)
+            {
+                case kg2ClOrdinary:               return presentation(fmt, "kg2ClOrdinary",               "Ordinary");
+                case kg2ClPriority:               return presentation(fmt, "kg2ClPriority",               "Priority");
+                case kg2ClMaintenance:            return presentation(fmt, "kg2ClMaintenance",            "Maintenance");
+                case kg2ClTrunkOperator:          return presentation(fmt, "kg2ClTrunkOperator",          "Trunk operator");
+                case kg2ClDataTrans:              return presentation(fmt, "kg2ClDataTrans",              "Data transfer");
+                case kg2ClUnidentifiedSubscriber: return presentation(fmt, "kg2ClUnidentifiedSubscriber", "Unidentified subscriber");
+            }
+            break;
+
+        case R2_COUNTRY_MEX:
+            switch ((KSignGroupII_Mexico)group)
+            {
+                case kg2MxTrunkOperator:    return presentation(fmt, "kg2MxTrunkOperator",       "Trunk operator");
+                case kg2MxOrdinary:         return presentation(fmt, "kg2MxOrdinary",            "Ordinary");
+                case kg2MxMaintenance:      return presentation(fmt, "kg2MxMaintenance",         "Maintenance");
+            }
+            break;
+
+        case R2_COUNTRY_URY:
+            switch ((KSignGroupII_Uruguay)group)
+            {
+                case kg2UyOrdinary:         return presentation(fmt, "kg2UyOrdinary",            "Ordinary");
+                case kg2UyPriority:         return presentation(fmt, "kg2UyPriority",            "Priority");
+                case kg2UyMaintenance:      return presentation(fmt, "kg2UyMaintenance",         "Maintenance");
+                case kg2UyLocalPayPhone:    return presentation(fmt, "kg2UyLocalPayPhone",       "Local pay phone");
+                case kg2UyTrunkOperator:    return presentation(fmt, "kg2UyTrunkOperator",       "Trunk operator");
+                case kg2UyDataTrans:        return presentation(fmt, "kg2UyDataTrans",           "Data transfer");
+                case kg2UyInternSubscriber: return presentation(fmt, "kg2UyInternSubscriber",    "International subscriber");
+            }
+            break;
+
+        case R2_COUNTRY_VEN:
+            switch ((KSignGroupII_Venezuela)group)
+            {
+                case kg2VeOrdinary:           return presentation(fmt, "kg2VeOrdinary",            "Ordinary");
+                case kg2VePriority:           return presentation(fmt, "kg2VePriority",            "Priority");
+                case kg2VeMaintenance:        return presentation(fmt, "kg2VeMaintenance",         "Maintenance");
+                case kg2VeLocalPayPhone:      return presentation(fmt, "kg2VeLocalPayPhone",       "Local pay phone");
+                case kg2VeTrunkOperator:      return presentation(fmt, "kg2VeTrunkOperator",       "Trunk operator");
+                case kg2VeDataTrans:          return presentation(fmt, "kg2VeDataTrans",           "Data transfer");
+                case kg2VeNoTransferFacility: return presentation(fmt, "kg2VeNoTransferFacility",  "No transfer facility");
+            }
+            break;
+    }
+#else
+    switch ((KSignGroupII)group)
+    {
+        case kg2Ordinary:         return presentation(fmt, "kg2Ordinary",            "Ordinary");
+        case kg2Priority:         return presentation(fmt, "kg2Priority",            "Priority");
+        case kg2Maintenance:      return presentation(fmt, "kg2Maintenance",         "Maintenance");
+        case kg2LocalPayPhone:    return presentation(fmt, "kg2LocalPayPhone",       "Local pay phone");
+        case kg2TrunkOperator:    return presentation(fmt, "kg2TrunkOperator",       "Trunk operator");
+        case kg2DataTrans:        return presentation(fmt, "kg2DataTrans",           "Data transfer");
+        case kg2NonLocalPayPhone: return presentation(fmt, "kg2NonLocalPayPhone",    "Non local pay phone");
+        case kg2CollectCall:      return presentation(fmt, "kg2CollectCall",         "Collect call");
+        case kg2OrdinaryInter:    return presentation(fmt, "kg2OrdinaryInter",       "Ordinary international");
+        case kg2Transfered:       return presentation(fmt, "kg2Transfered",          "Transfered");
+    }
+#endif
+
+    throw internal_not_found();
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::signGroupII(KSignGroupII group, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::signGroupII(KSignGroupII group, Verbose::Presentation fmt)
+#endif
+{
+    try
+    {
+#if K3L_AT_LEAST(2,0,0)
+        return internal_signGroupII(group, r2_country);
+#else
+        return internal_signGroupII(group);
+#endif
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KSignGroupII='%d']") % (int)group),
+            STG(FMT("Unknown group II (%d)") % (int)group));
+    }
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::callFail(KSignaling sig, R2CountryType country, int32 info, Verbose::Presentation fmt)
+#else
+std::string Verbose::callFail(KSignaling sig, int32 info, Verbose::Presentation fmt)
+#endif
+{
+    try
+    {
+        switch (sig)
+        {
+            case ksigInactive:
+                throw internal_not_found();
+
+            case ksigAnalog:
+                if (('a' <= ((char)info) && 'z' >= ((char)info)) || ('A' <= ((char)info) && 'Z' >= ((char)info)))
+                    return STG(FMT("%c") % (char)info);
+                else
+                    throw internal_not_found();
+
+#if K3L_AT_LEAST(1,5,4)
+            case ksigLineSide:
+#endif
+#if K3L_EXACT(2,1,0)
+            case ksigISUP:
+            case ksigFax:
+#endif
+#if K3L_AT_LEAST(1,6,0)
+            case ksigCAS_EL7:
+            case ksigE1LC:
+                return "NOT IMPLEMENTED";
+
+            case ksigAnalogTerminal:
+#endif
+            case ksigContinuousEM:
+            case ksigPulsedEM:
+
+            case ksigR2Digital:
+            case ksigOpenR2:
+#if K3L_AT_LEAST(2,0,0)
+                return internal_signGroupB((KSignGroupB)info, country);
+#else
+                return internal_signGroupB((KSignGroupB)info);
+#endif
+
+            case ksigOpenCAS:
+            case ksigUserR2Digital:
+#if K3L_AT_LEAST(2,0,0)
+                return internal_signGroupB((KSignGroupB)info, R2_COUNTRY_BRA);
+#else
+                return internal_signGroupB((KSignGroupB)info);
+#endif
+
+#if K3L_AT_LEAST(1,5,0)
+            case ksigSIP:
+                return internal_sipFailures((KSIP_Failures)info);
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+            case ksigOpenCCS:
+            case ksigPRI_EndPoint:
+            case ksigPRI_Network:
+            case ksigPRI_Passive:
+#if K3L_AT_LEAST(2,2,0)
+            case ksigISUP:
+            case ksigISUPPassive:
+#endif
+                return internal_isdnCause((KQ931Cause)info);
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+            case ksigGSM:
+                return internal_gsmCallCause((KGsmCallCause)info);
+#endif
+        }
+    }
+    catch (internal_not_found & e)
+    {
+        /* this exception is used for breaking the control flow */
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[%s, callFail='%d']") % signaling(sig, fmt) % (int)info),
+        STG(FMT("Unknown call fail code for '%s' (%d)") % signaling(sig, fmt) % (int)info));
+}
+
+std::string Verbose::channelFail(KSignaling sig, int32 code, Verbose::Presentation fmt)
+{
+    try
+    {
+        switch (sig)
+        {
+            case ksigInactive:
+            case ksigAnalog:
+            case ksigSIP:
+#if K3L_EXACT(2,1,0)
+            case ksigISUP:
+            case ksigFax:
+#endif
+                throw internal_not_found();
+
+#if K3L_AT_LEAST(1,6,0)
+            case ksigGSM:
+                return internal_gsmMobileCause((KGsmMobileCause)code);
+
+            case ksigAnalogTerminal:
+            case ksigCAS_EL7:
+            case ksigE1LC:
+#endif
+
+            case ksigContinuousEM:
+            case ksigPulsedEM:
+
+            case ksigLineSide:
+
+            case ksigOpenCAS:
+            case ksigOpenR2:
+            case ksigR2Digital:
+            case ksigUserR2Digital:
+                switch ((KChannelFail)code)
+                {
+                    case kfcRemoteFail:         return presentation(fmt, "kfcRemoteFail",         "Remote failure");
+                    case kfcLocalFail:          return presentation(fmt, "kfcLocalFail",          "Local failure");
+                    case kfcRemoteLock:         return presentation(fmt, "kfcRemoteLock",         "Remote lock");
+                    case kfcLineSignalFail:     return presentation(fmt, "kfcLineSignalFail",     "Line signal failure");
+                    case kfcAcousticSignalFail: return presentation(fmt, "kfcAcousticSignalFail", "Acoustic signal failure");
+                }
+
+                throw internal_not_found();
+
+#if K3L_AT_LEAST(1,5,1)
+            case ksigOpenCCS:
+            case ksigPRI_EndPoint:
+            case ksigPRI_Network:
+            case ksigPRI_Passive:
+#if K3L_AT_LEAST(2,2,0)
+            case ksigISUP:
+            case ksigISUPPassive:
+#endif
+                return internal_isdnCause((KQ931Cause)code);
+#endif
+        }
+    }
+    catch (internal_not_found & e)
+    {
+        /* this exception is used for breaking the control flow */
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[%s, channelFail='%d']") % signaling(sig, fmt) % (int)code),
+        STG(FMT("Unknown channel fail code for '%s' (%d)") % signaling(sig, fmt) % (int)code));
+}
+
+std::string Verbose::internalFail(KInternalFail inf, Verbose::Presentation fmt)
+{
+    switch (inf)
+    {
+        case kifInterruptCtrl:     return presentation(fmt, "kifInterruptCtrl",     "Interrupt control");
+        case kifCommunicationFail: return presentation(fmt, "kifCommunicationFail", "Communication failure");
+        case kifProtocolFail:      return presentation(fmt, "kifProtocolFail",      "Protocol failure");
+        case kifInternalBuffer:    return presentation(fmt, "kifInternalBuffer",    "Internal buffer");
+        case kifMonitorBuffer:     return presentation(fmt, "kifMonitorBuffer",     "Monitor buffer");
+        case kifInitialization:    return presentation(fmt, "kifInitialization",    "Initialization");
+        case kifInterfaceFail:     return presentation(fmt, "kifInterfaceFail",     "Interface failure");
+        case kifClientCommFail:    return presentation(fmt, "kifClientCommFail",    "Client communication failure");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KInternalFail='%d']") % (int)inf),
+        STG(FMT("Unknown internal failure (%d)") % (int)inf));
+}
+
+std::string Verbose::linkErrorCounter(KLinkErrorCounter ec, Verbose::Presentation fmt)
+{
+    switch (ec)
+    {
+        case klecChangesToLock:     return presentation(fmt, "klecChangesToLock",     "Changes to lock");
+        case klecLostOfSignal:      return presentation(fmt, "klecLostOfSignal",      "Lost of signal");
+        case klecAlarmNotification: return presentation(fmt, "klecAlarmNotification", "Alarm notification");
+        case klecLostOfFrame:       return presentation(fmt, "klecLostOfFrame",       "Lost of frame");
+        case klecLostOfMultiframe:  return presentation(fmt, "klecLostOfMultiframe",  "Lost of multiframe");
+        case klecRemoteAlarm:       return presentation(fmt, "klecRemoteAlarm",       "Remote alarm");
+        case klecUnknowAlarm:       return presentation(fmt, "klecUnknowAlarm",       "Slip alarm");
+        case klecPRBS:              return presentation(fmt, "klecPRBS",              "PRBS");
+        case klecWrogrBits:         return presentation(fmt, "klecWrongBits",         "Wrong bits");
+        case klecJitterVariation:   return presentation(fmt, "klecJitterVariation",   "Jitter variation");
+        case klecFramesWithoutSync: return presentation(fmt, "klecFramesWithoutSync", "Frames without sync");
+        case klecMultiframeSignal:  return presentation(fmt, "klecMultiframeSignal",  "Multiframe Signal");
+        case klecFrameError:        return presentation(fmt, "klecFrameError",        "Frame error");
+        case klecBipolarViolation:  return presentation(fmt, "klecBipolarViolation",  "Bipolar violation");
+        case klecCRC4:              return presentation(fmt, "klecCRC4",              "CRC4 error");
+        case klecCount:             return ""; /* this should never be verbosed */
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KLinkErrorCounter='%d']") % (int)ec),
+        STG(FMT("Unknown link error counter (%d)") % (int)ec));
+}
+
+std::string Verbose::callStatus(KCallStatus code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kcsFree:       return presentation(fmt, "kcsFree",     "Free");
+        case kcsIncoming:   return presentation(fmt, "kcsIncoming", "Incoming");
+        case kcsOutgoing:   return presentation(fmt, "kcsOutgoing", "Outgoing");
+        case kcsFail:       return presentation(fmt, "kcsFail",     "Failure");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KCallStatus='%d']") % (int)code),
+        STG(FMT("Unknown call status (%d)") % (int)code));
+}
+
+std::string Verbose::linkStatus(KSignaling sig, int32 code, Verbose::Presentation fmt)
+{
+    switch (sig)
+    {
+        case ksigInactive:
+            return presentation(fmt, "[ksigInactive]", "Inactive trunk");
+
+        case ksigAnalog:
+            return presentation(fmt, "[ksigAnalog]", "Analog trunk");
+
+#if K3L_AT_LEAST(1,4,1)
+        case ksigSIP:
+            return presentation(fmt, "[ksigSIP]", "SIP trunk");
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case ksigGSM:
+            return presentation(fmt, "[ksigGSM]", "GSM trunk");
+#endif
+
+#if K3L_EXACT(2,1,0)
+        case ksigFax:
+            return presentation(fmt, "[ksigFax]", "FAX");
+#endif
+        case ksigContinuousEM:
+        case ksigPulsedEM:
+
+        case ksigOpenCAS:
+        case ksigOpenR2:
+        case ksigR2Digital:
+        case ksigUserR2Digital:
+
+#if K3L_AT_LEAST(1,5,1)
+        case ksigOpenCCS:
+        case ksigPRI_EndPoint:
+        case ksigPRI_Network:
+        case ksigPRI_Passive:
+#endif
+#if K3L_AT_LEAST(1,5,3)
+        case ksigLineSide:
+#endif
+#if K3L_AT_LEAST(1,6,0)
+        case ksigAnalogTerminal:
+        case ksigCAS_EL7:
+        case ksigE1LC:
+#endif
+#if K3L_AT_LEAST(2,2,0)
+        case ksigISUP:
+        case ksigISUPPassive:
+#endif
+            if (kesOk == code)
+            {
+                return presentation(fmt, "kesOk", "Up");
+            }
+            else
+            {
+                Strings::Merger strs;
+
+                if (kesSignalLost & code)         strs.add(presentation(fmt, "SignalLost",         "Signal lost"));
+                if (kesNetworkAlarm & code)       strs.add(presentation(fmt, "NetworkAlarm",       "Network alarm"));
+                if (kesFrameSyncLost & code)      strs.add(presentation(fmt, "FrameSyncLost",      "Frame sync lost"));
+                if (kesMultiframeSyncLost & code) strs.add(presentation(fmt, "MultiframeSyncLost", "Multiframe sync lost"));
+                if (kesRemoteAlarm & code)        strs.add(presentation(fmt, "RemoteAlarm",        "Remote alarm"));
+                if (kesHighErrorRate & code)      strs.add(presentation(fmt, "HighErrorRate",      "High error rate"));
+                if (kesUnknownAlarm & code)       strs.add(presentation(fmt, "UnknownAlarm",       "Slip alarm"));
+                if (kesE1Error & code)            strs.add(presentation(fmt, "E1Error",            "E1 error"));
+
+                PRESENTATION_CHECK_RETURN(fmt,
+                    STG(FMT("kes{%s}") % strs.merge(",")),
+                    strs.merge(", "));
+            }
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[%s, linkStatus='%d']") % signaling(sig) % (int)code),
+        STG(FMT("Unknown link status for '%s' (%d)") % signaling(sig) % (int)code));
+}
+
+std::string Verbose::channelStatus(KSignaling sig, int32 flags, Verbose::Presentation fmt)
+{
+    try
+    {
+        switch (sig)
+        {
+            case ksigInactive:
+                return presentation(fmt, "[ksigInactive]", "Inactive channel");
+
+#if K3L_AT_LEAST(1,4,1)
+            case ksigSIP:
+                return presentation(fmt, "[ksigSIP]", "SIP channel");
+#endif
+#if K3L_EXACT(2,1,0)
+            case ksigISUP:
+                return presentation(fmt, "[ksigISUP]", "ISUP trunk");
+            case ksigFax:
+                return presentation(fmt, "[ksigFax]", "FAX");
+#endif
+
+            case ksigAnalog:
+#if K3L_AT_LEAST(1,6,0)
+                switch ((KFXOChannelStatus)flags)
+#else
+                switch ((KFXChannelStatus)flags)
+#endif
+                {
+                    case kfcsDisabled:   return presentation(fmt, "kfcsDisabled", "Disabled");
+                    case kfcsEnabled:    return presentation(fmt, "kfcsEnabled",  "Enabled");
+                }
+
+                throw internal_not_found();
+
+#if K3L_AT_LEAST(1,6,0)
+            case ksigAnalogTerminal:
+                switch ((KFXSChannelStatus)flags)
+                {
+                    case kfxsOnHook:   return presentation(fmt, "kfxsOnHook",  "On Hook");
+                    case kfxsOffHook:  return presentation(fmt, "kfxsOffHook", "Off Hook");
+                    case kfxsRinging:  return presentation(fmt, "kfxsRinging", "Ringing");
+                    case kfxsFail:     return presentation(fmt, "kfxsFail",    "Failure");
+                }
+
+                throw internal_not_found();
+
+            case ksigGSM:
+                switch ((KGsmChannelStatus)flags)
+                {
+                    case kgsmIdle:            return presentation(fmt, "kgsmIdle",           "Idle");
+                    case kgsmCallInProgress:  return presentation(fmt, "kgsmCallInProgress", "Call in progress");
+                    case kgsmSMSInProgress:   return presentation(fmt, "kgsmSMSInProgress",  "SMS in progress");
+                    case kgsmModemError:      return presentation(fmt, "kgsmModemError",     "Modem error");
+                    case kgsmSIMCardError:    return presentation(fmt, "kgsmSIMCardError",   "SIM card error");
+                    case kgsmNetworkError:    return presentation(fmt, "kgsmNetworkError",   "Network error");
+                    case kgsmNotReady:        return presentation(fmt, "kgsmNotReady",       "Initializing");
+                }
+
+                throw internal_not_found();
+#endif
+
+            /* deprecated, but still.. */
+            case ksigPulsedEM:
+            case ksigContinuousEM:
+
+            case ksigOpenCAS:
+            case ksigOpenR2:
+            case ksigR2Digital:
+            case ksigUserR2Digital:
+
+#if K3L_AT_LEAST(1,5,1)
+            case ksigOpenCCS:
+            case ksigPRI_EndPoint:
+            case ksigPRI_Network:
+            case ksigPRI_Passive:
+#endif
+#if K3L_AT_LEAST(1,5,3)
+            case ksigLineSide:
+#endif
+#if K3L_AT_LEAST(1,6,0)
+            case ksigCAS_EL7:
+            case ksigE1LC:
+#endif
+#if K3L_AT_LEAST(2,2,0)
+            case ksigISUP:
+            case ksigISUPPassive:
+#endif
+            {
+                if (flags == kecsFree)
+                {
+                    return presentation(fmt, "kecsFree", "Free");
+                }
+                else
+                {
+                    Strings::Merger strs;
+
+                    if (flags & kecsBusy)
+                        strs.add("Busy");
+
+                    switch (flags & 0x06)
+                    {
+                        case kecsOutgoing:
+                            strs.add("Outgoing");
+                             break;
+                        case kecsIncoming:
+                            strs.add("Incoming");
+                            break;
+                        case kecsLocked:
+                            strs.add("Locked");
+                        default:
+                            break;
+                    }
+
+                    int32 value = (flags & 0xf0);
+
+                    if (kecsOutgoingLock & value)
+                        strs.add(presentation(fmt, "OutgoingLock", "Outgoing Lock"));
+
+                    if (kecsLocalFail & value)
+                        strs.add(presentation(fmt, "LocalFail", "Local Failure"));
+
+                    if (kecsIncomingLock & value)
+                        strs.add(presentation(fmt, "IncomingLock", "Incoming Lock"));
+
+                    if (kecsRemoteLock & value)
+                        strs.add(presentation(fmt, "RemoteLock", "Remote Lock"));
+
+                    PRESENTATION_CHECK_RETURN(fmt,
+                        STG(FMT("kecs{%s}") % strs.merge(",")),
+                        strs.merge(", "));
+                }
+
+                throw internal_not_found();
+            }
+        }
+    }
+    catch (internal_not_found & e)
+    {
+        /* we use this exception to break the control flow */
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[%s, channelStatus='%d']") % signaling(sig) % flags),
+        STG(FMT("Unknown channel status for '%s' (%d)") % signaling(sig) % flags));
+}
+
+std::string Verbose::status(KLibraryStatus code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case ksSuccess:        return presentation(fmt, "ksSuccess",        "Success");
+        case ksFail:           return presentation(fmt, "ksFail",           "Failure");
+        case ksTimeOut:        return presentation(fmt, "ksTimeOut",        "Time Out");
+        case ksBusy:           return presentation(fmt, "ksBusy",           "Busy");
+        case ksLocked:         return presentation(fmt, "ksLocked",         "Locked");
+        case ksInvalidParams:  return presentation(fmt, "ksInvalidParams",  "Invalid Parameters");
+        case ksEndOfFile:      return presentation(fmt, "ksEndOfFile",      "End of File");
+        case ksInvalidState:   return presentation(fmt, "ksInvalidState",   "Invalid State");
+        case ksServerCommFail: return presentation(fmt, "ksServerCommFail", "Communication Failure");
+        case ksOverflow:       return presentation(fmt, "ksOverflow",       "Overflow");
+        case ksUnderrun:       return presentation(fmt, "ksUnderrun",       "Underrun");
+
+#if K3L_AT_LEAST(1,4,0)
+        case ksNotFound:       return presentation(fmt, "ksNotFound",       "Not Found");
+        case ksNotAvailable:   return presentation(fmt, "ksNotAvaiable",    "Not Available");
+#endif
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KLibraryStatus='%d']") % (int)code),
+        STG(FMT("Unknown library status (%d)") % (int)code));
+}
+
+std::string Verbose::h100configIndex(KH100ConfigIndex code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case khciDeviceMode:         return presentation(fmt, "khciDeviceMode",      "Device Mode");
+        case khciMasterGenClock:     return presentation(fmt, "khciMasterGenClock",  "Master Generated Clock");
+        case khciCTNetRefEnable:     return presentation(fmt, "khciCTNetRefEnable",  "CTBus Network Reference Enable");
+        case khciSCbusEnable:        return presentation(fmt, "khciSCbusEnable",     "SCBus Enable");
+        case khciHMVipEnable:        return presentation(fmt, "khciHMVipEnable",     "HMVip Enable");
+        case khciMVip90Enable:       return presentation(fmt, "khciMVip90Enable",    "MVip90 Enable");
+        case khciCTbusDataEnable:    return presentation(fmt, "khciCTbusDataEnable", "CTBus Data Enable");
+        case khciCTbusFreq03_00:     return presentation(fmt, "khciCTbusFreq03_00",  "CTBus Frequency 03 00"); // TODO: find better name
+        case khciCTbusFreq07_04:     return presentation(fmt, "khciCTbusFreq07_04",  "CTBus Frequency 07 04"); // TODO: find better name
+        case khciCTbusFreq11_08:     return presentation(fmt, "khciCTbusFreq11_08",  "CTBus Frequency 11 08"); // TODO: find better name
+        case khciCTbusFreq15_12:     return presentation(fmt, "khciCTbusFreq15_12",  "CTBus Frequency 15 12"); // TODO: find better name
+        case khciMax:                return presentation(fmt, "khciMax",             "Max"); // TODO: find better name
+        case khciMasterDevId:        return presentation(fmt, "khciMasterDevId",     "Master Device Number");
+        case khciSecMasterDevId:     return presentation(fmt, "khciSecMasterDevId",  "Secondary Master Device Number");
+        case khciCtNetrefDevId:      return presentation(fmt, "khciCtNetrefDevId",   "CTBus Network Reference Device Number");
+#if K3L_AT_LEAST(1,6,0)
+        case khciMaxH100ConfigIndex: return ""; /* do not verbose this value */
+#endif
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KH100ConfigIndex='%d']") % (int)code),
+        STG(FMT("Unknown H.100 config index (%d)") % (int)code));
+}
+
+#if K3L_AT_LEAST(1,6,0)
+std::string Verbose::callStartInfo(KCallStartInfo code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kcsiHumanAnswer:         return presentation(fmt, "kcsiHumanAnswer",         "Human Answer");
+        case kcsiAnsweringMachine:    return presentation(fmt, "kcsiAnsweringMachine",    "Answering Machine");
+        case kcsiCellPhoneMessageBox: return presentation(fmt, "kcsiCellPhoneMessageBox", "Cell Phone Message Box");
+        case kcsiCarrierMessage:      return presentation(fmt, "kcsiCarrierMessage",      "Carrier Message");
+        case kcsiUnknown:             return presentation(fmt, "kcsiUnknown",             "Unknown");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KCallStartInfo='%d']") % (int)code),
+        STG(FMT("Unknown call answer info (%d)") % (int)code));
+}
+
+std::string Verbose::gsmCallCause(KGsmCallCause code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_gsmCallCause(code, fmt);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KGsmCallCause='%d']") % (int)code),
+            STG(FMT("Unknown GSM call cause (%d)") % (int)code));
+    }
+}
+
+std::string Verbose::internal_gsmCallCause(KGsmCallCause code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kgccNone:                               return presentation(fmt, "kgccNone",                      "None");
+        case kgccUnallocatedNumber:                  return presentation(fmt, "kgccUnallocatedNumber",         "Unallocated number");
+        case kgccNoRouteToDest:                      return presentation(fmt, "kgccNoRouteToDest",             "No route to destination");
+        case kgccChannelUnacceptable:                return presentation(fmt, "kgccChannelUnacceptable",       "Channel unacceptable");
+        case kgccOperatorDeterminedBarring:          return presentation(fmt, "kgccOperatorDeterminedBarring", "Operator determined barring");
+        case kgccNormalCallClear:                    return presentation(fmt, "kgccNormalCallClear",           "Normal call clear");
+        case kgccUserBusy:                           return presentation(fmt, "kgccUserBusy",                  "User busy");
+        case kgccNoUserResponding:                   return presentation(fmt, "kgccNoUserResponding",          "No user responding");
+        case kgccNoAnswerFromUser:                   return presentation(fmt, "kgccNoAnswerFromUser",          "No answer from user");
+        case kgccCallRejected:                       return presentation(fmt, "kgccCallRejected",              "Call rejected");
+        case kgccNumberChanged:                      return presentation(fmt, "kgccNumberChanged",             "Number changed");
+        case kgccNonSelectedUserClear:               return presentation(fmt, "kgccNonSelectedUserClear",      "Non Selected user clear");
+        case kgccDestinationOutOfOrder:              return presentation(fmt, "kgccDestinationOutOfOrder",     "Destination out of order");
+        case kgccInvalidNumberFormat:                return presentation(fmt, "kgccInvalidNumberFormat",       "Invalid number format");
+        case kgccFacilityRejected:                   return presentation(fmt, "kgccFacilityRejected",          "Facility rejected");
+        case kgccRespStatusEnquiry:                  return presentation(fmt, "kgccRespStatusEnquiry",         "Response status enquiry");
+        case kgccNormalUnspecified:                  return presentation(fmt, "kgccNormalUnspecified",         "Normal, unspecified");
+        case kgccNoCircuitChannelAvail:              return presentation(fmt, "kgccNoCircuitChannelAvail",     "No circuit channel available");
+        case kgccNetworkOutOfOrder:                  return presentation(fmt, "kgccNetworkOutOfOrder",         "Network out of order");
+        case kgccTemporaryFailure:                   return presentation(fmt, "kgccTemporaryFailure",          "Temporary failure");
+        case kgccSwitchCongestion:                   return presentation(fmt, "kgccSwitchCongestion",          "Switch congestion");
+        case kgccAccessInfoDiscarded:                return presentation(fmt, "kgccAccessInfoDiscarded",       "Access information discarded");
+        case kgccRequestedChannelUnav:               return presentation(fmt, "kgccRequestedChannelUnav",      "Requested channel unavailable");
+        case kgccResourceUnavailable:                return presentation(fmt, "kgccResourceUnavailable",       "Resource unavailable");
+        case kgccQosUnavailable:                     return presentation(fmt, "kgccQosUnavailable",            "QoS unavailable");
+        case kgccReqFacilityNotSubsc:                return presentation(fmt, "kgccReqFacilityNotSubsc",       "Request facility not subscribed");
+        case kgccCallBarredWitchCUG:                 return presentation(fmt, "kgccCallBarredWitchCUG",        "Call barred with UG");
+        case kgccBearerCapabNotAuthor:               return presentation(fmt, "kgccBearerCapabNotAuthor",      "Bearer capability not authorized");
+        case kgccBearerCapabNotAvail:                return presentation(fmt, "kgccBearerCapabNotAvail",       "Bearer capability not available");
+        case kgccServiceNotAvailable:                return presentation(fmt, "kgccServiceNotAvailable",       "Service not available");
+        case kgccBcNotImplemented:                   return presentation(fmt, "kgccBcNotImplemented",          "Bearer capability not implemented");
+        case kgccReqFacilityNotImplem:               return presentation(fmt, "kgccReqFacilityNotImplem",      "Request facility not implemented");
+        case kgccOnlyRestrictedBcAvail:              return presentation(fmt, "kgccOnlyRestrictedBcAvail",     "Only restricted bearer capability available");
+        case kgccServiceNotImplemented:              return presentation(fmt, "kgccServiceNotImplemented",     "Service not implemented");
+        case kgccInvalidCrv:                         return presentation(fmt, "kgccInvalidCrv",                "Invalid call reference value");
+        case kgccUserNotMemberOfCUG:                 return presentation(fmt, "kgccUserNotMemberOfCUG",        "User not member of UG");
+        case kgccIncompatibleDestination:            return presentation(fmt, "kgccIncompatibleDestination",   "Incompatible destination");
+        case kgccInvalidTransitNetSel:               return presentation(fmt, "kgccInvalidTransitNetSel",      "Invalid transit network selected");
+        case kgccInvalidMessage:                     return presentation(fmt, "kgccInvalidMessage",            "Invalid message");
+        case kgccMissingMandatoryIe:                 return presentation(fmt, "kgccMissingMandatoryIe",        "Missing mandatory information element");
+        case kgccMsgTypeNotImplemented:              return presentation(fmt, "kgccMsgTypeNotImplemented",     "Message type not implemented");
+        case kgccMsgIncompatWithState:               return presentation(fmt, "kgccMsgIncompatWithState",      "Message incompatible with state");
+        case kgccIeNotImplemented:                   return presentation(fmt, "kgccIeNotImplemented",          "Information element not implemented");
+        case kgccInvalidIe:                          return presentation(fmt, "kgccInvalidIe",                 "Invalid information element");
+        case kgccMsgIncompatWithState2:              return presentation(fmt, "kgccMsgIncompatWithState2",     "Message incompatible with state (2)");
+        case kgccRecoveryOnTimerExpiry:              return presentation(fmt, "kgccRecoveryOnTimerExpiry",     "Recovery on timer expiry");
+        case kgccProtocolError:                      return presentation(fmt, "kgccProtocolError",             "Protocol error");
+        case kgccInterworking:                       return presentation(fmt, "kgccInterworking",              "Interworking");
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::gsmMobileCause(KGsmMobileCause code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_gsmMobileCause(code, fmt);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KGsmMobileCause='%d']") % (int)code),
+            STG(FMT("Unknown GSM mobile cause (%d)") % (int)code));
+    }
+}
+
+std::string Verbose::internal_gsmMobileCause(KGsmMobileCause code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kgmcPhoneFailure:                    return presentation(fmt, "kgmcPhoneFailure",               "Phone failure");
+        case kgmcNoConnectionToPhone:             return presentation(fmt, "kgmcNoConnectionToPhone",        "No connection to phone");
+        case kgmcPhoneAdaptorLinkReserved:        return presentation(fmt, "kgmcPhoneAdaptorLinkReserved",   "Phone adaptor link reserved");
+#if 0 /* this changed during K3L 1.6.0 development cycle... */
+        case kgmcCoperationNotAllowed:            return presentation(fmt, "kgmcCoperationNotAllowed",       "");
+        case kgmcCoperationNotSupported:          return presentation(fmt, "kgmcCoperationNotSupported",     "");
+#else
+        case kgmcOperationNotAllowed:             return presentation(fmt, "kgmcOperationNotAllowed",        "Operation not allowed");
+        case kgmcOperationNotSupported:           return presentation(fmt, "kgmcOperationNotSupported",      "Operation not supported");
+#endif
+        case kgmcPH_SIMPINRequired:               return presentation(fmt, "kgmcPH_SIMPINRequired",          "Phone SIM PIN required");
+        case kgmcPH_FSIMPINRequired:              return presentation(fmt, "kgmcPH_FSIMPINRequired",         "Phone FSIM PIN required");
+        case kgmcPH_FSIMPUKRequired:              return presentation(fmt, "kgmcPH_FSIMPUKRequired",         "Phone FSIM PUK required");
+        case kgmcSIMNotInserted:                  return presentation(fmt, "kgmcSIMNotInserted",             "SIM not inserted");
+        case kgmcSIMPINRequired:                  return presentation(fmt, "kgmcSIMPINRequired",             "SIM PIN required");
+        case kgmcSIMPUKRequired:                  return presentation(fmt, "kgmcSIMPUKRequired",             "SIM PUK required");
+        case kgmcSIMFailure:                      return presentation(fmt, "kgmcSIMFailure",                 "SIM failure");
+        case kgmcSIMBusy:                         return presentation(fmt, "kgmcSIMBusy",                    "SIM busy");
+        case kgmcSIMWrong:                        return presentation(fmt, "kgmcSIMWrong",                   "SIM wrong");
+        case kgmcIncorrectPassword:               return presentation(fmt, "kgmcIncorrectPassword",          "Incorrect password");
+        case kgmcSIMPIN2Required:                 return presentation(fmt, "kgmcSIMPIN2Required",            "SIM PIN2 required");
+        case kgmcSIMPUK2Required:                 return presentation(fmt, "kgmcSIMPUK2Required",            "SIM PUK2 required");
+        case kgmcMemoryFull:                      return presentation(fmt, "kgmcMemoryFull",                 "Memory full");
+        case kgmcInvalidIndex:                    return presentation(fmt, "kgmcInvalidIndex",               "Invalid index");
+        case kgmcNotFound:                        return presentation(fmt, "kgmcNotFound",                   "Not found");
+        case kgmcMemoryFailure:                   return presentation(fmt, "kgmcMemoryFailure",              "Memory failure");
+        case kgmcTextStringTooLong:               return presentation(fmt, "kgmcTextStringTooLong",          "Text string too long");
+        case kgmcInvalidCharInTextString:         return presentation(fmt, "kgmcInvalidCharInTextString",    "Invalid character in text string");
+        case kgmcDialStringTooLong:               return presentation(fmt, "kgmcDialStringTooLong",          "Dial string too long");
+        case kgmcInvalidCharInDialString:         return presentation(fmt, "kgmcInvalidCharInDialString",    "Invalid character in dial string");
+        case kgmcNoNetworkService:                return presentation(fmt, "kgmcNoNetworkService",           "No network service");
+        case kgmcNetworkTimeout:                  return presentation(fmt, "kgmcNetworkTimeout",             "Network timeout");
+        case kgmcNetworkNotAllowed:               return presentation(fmt, "kgmcNetworkNotAllowed",          "Network not allowed");
+        case kgmcCommandAborted:                  return presentation(fmt, "kgmcCommandAborted",             "Command aborted");
+        case kgmcNumParamInsteadTextParam:        return presentation(fmt, "kgmcNumParamInsteadTextParam",   "Number parameter instead of text parameter");
+        case kgmcTextParamInsteadNumParam:        return presentation(fmt, "kgmcTextParamInsteadNumParam",   "Text parameter instead of number parameter");
+        case kgmcNumericParamOutOfBounds:         return presentation(fmt, "kgmcNumericParamOutOfBounds",    "Numeric parameter out of bounds");
+        case kgmcTextStringTooShort:              return presentation(fmt, "kgmcTextStringTooShort",         "Text string too short");
+        case kgmcNetworkPINRequired:              return presentation(fmt, "kgmcNetworkPINRequired",         "Network PIN required");
+        case kgmcNetworkPUKRequired:              return presentation(fmt, "kgmcNetworkPUKRequired",         "Network PUK required");
+        case kgmcNetworkSubsetPINRequired:        return presentation(fmt, "kgmcNetworkSubsetPINRequired",   "Network subset PIN required");
+        case kgmcNetworkSubnetPUKRequired:        return presentation(fmt, "kgmcNetworkSubnetPUKRequired",   "Network subset PUK required");
+        case kgmcServiceProviderPINRequired:      return presentation(fmt, "kgmcServiceProviderPINRequired", "Network service provider PIN required");
+        case kgmcServiceProviderPUKRequired:      return presentation(fmt, "kgmcServiceProviderPUKRequired", "Network service provider PUK required");
+        case kgmcCorporatePINRequired:            return presentation(fmt, "kgmcCorporatePINRequired",       "Corporate PIN required");
+        case kgmcCorporatePUKRequired:            return presentation(fmt, "kgmcCorporatePUKRequired",       "Corporate PUK required");
+        case kgmcSIMServiceOptNotSupported:       return presentation(fmt, "kgmcSIMServiceOptNotSupported",  "SIM Service option not supported");
+        case kgmcUnknown:                         return presentation(fmt, "kgmcUnknown",                    "Unknown");
+        case kgmcIllegalMS_N3:                    return presentation(fmt, "kgmcIllegalMS_N3",               "Illegal MS #3");
+        case kgmcIllegalME_N6:                    return presentation(fmt, "kgmcIllegalME_N6",               "Illegal MS #6");
+        case kgmcGPRSServicesNotAllowed_N7:       return presentation(fmt, "kgmcGPRSServicesNotAllowed_N7",  "GPRS service not allowed #7");
+        case kgmcPLMNNotAllowed_No11:             return presentation(fmt, "kgmcPLMNNotAllowed_No11",        "PLMN not allowed #11");
+        case kgmcLocationAreaNotAllowed_N12:      return presentation(fmt, "kgmcLocationAreaNotAllowed_N12", "Location area not allowed #12");
+        case kgmcRoamingNotAllowed_N13:           return presentation(fmt, "kgmcRoamingNotAllowed_N13",      "Roaming not allowed #13");
+        case kgmcServiceOptNotSupported_N32:      return presentation(fmt, "kgmcServiceOptNotSupported_N32", "Service option not supported #32");
+        case kgmcReqServOptNotSubscribed_N33:     return presentation(fmt, "kgmcReqServOptNotSubscribed_N33", "Registration service option not subscribed #33");
+        case kgmcServOptTempOutOfOrder_N34:       return presentation(fmt, "kgmcServOptTempOutOfOrder_N34",   "Service option temporary out of order #34");
+        case kgmcLongContextActivation:           return presentation(fmt, "kgmcLongContextActivation",       "Long context activation");
+        case kgmcUnspecifiedGPRSError:            return presentation(fmt, "kgmcUnspecifiedGPRSError",        "Unspecified GPRS error");
+        case kgmcPDPAuthenticationFailure:        return presentation(fmt, "kgmcPDPAuthenticationFailure",    "PDP authentication failure");
+        case kgmcInvalidMobileClass:              return presentation(fmt, "kgmcInvalidMobileClass",          "Invalid mobile class");
+        case kgmcGPRSDisconnectionTmrActive:      return presentation(fmt, "kgmcGPRSDisconnectionTmrActive",  "GPRS disconnection TMR active");
+        case kgmcTooManyActiveCalls:              return presentation(fmt, "kgmcTooManyActiveCalls",          "Too many active calls");
+        case kgmcCallRejected:                    return presentation(fmt, "kgmcCallRejected",                "Call rejected");
+        case kgmcUnansweredCallPending:           return presentation(fmt, "kgmcUnansweredCallPending",       "Unanswered call pending");
+        case kgmcUnknownCallingError:             return presentation(fmt, "kgmcUnknownCallingError",         "Unknown calling error");
+        case kgmcNoPhoneNumRecognized:            return presentation(fmt, "kgmcNoPhoneNumRecognized",        "No phone number recognized");
+        case kgmcCallStateNotIdle:                return presentation(fmt, "kgmcCallStateNotIdle",            "Call state not idle");
+        case kgmcCallInProgress:                  return presentation(fmt, "kgmcCallInProgress",              "Call in progress");
+        case kgmcDialStateError:                  return presentation(fmt, "kgmcDialStateError",              "Dial state error");
+        case kgmcUnlockCodeRequired:              return presentation(fmt, "kgmcUnlockCodeRequired",          "Unlock code required");
+        case kgmcNetworkBusy:                     return presentation(fmt, "kgmcNetworkBusy",                 "Network busy");
+        case kgmcInvalidPhoneNumber:              return presentation(fmt, "kgmcInvalidPhoneNumber",          "Invalid phone number");
+        case kgmcNumberEntryAlreadyStarted:       return presentation(fmt, "kgmcNumberEntryAlreadyStarted",   "Number entry already started");
+        case kgmcCancelledByUser:                 return presentation(fmt, "kgmcCancelledByUser",             "Cancelled by user");
+        case kgmcNumEntryCouldNotBeStarted:       return presentation(fmt, "kgmcNumEntryCouldNotBeStarted",   "Number entry could not be started");
+        case kgmcDataLost:                        return presentation(fmt, "kgmcDataLost",                    "Data lost");
+        case kgmcInvalidBessageBodyLength:        return presentation(fmt, "kgmcInvalidBessageBodyLength",    "Invalid message body length");
+        case kgmcInactiveSocket:                  return presentation(fmt, "kgmcInactiveSocket",              "Inactive socket");
+        case kgmcSocketAlreadyOpen:               return presentation(fmt, "kgmcSocketAlreadyOpen",           "Socket already open");
+#if K3L_AT_LEAST(2,1,0)
+        case kgmcSuccess:                         return presentation(fmt, "kgmcSuccess",                     "Success");
+#endif
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::gsmSmsCause(KGsmSmsCause code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_gsmSmsCause(code, fmt);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KGsmSmsCause='%d']") % (int)code),
+            STG(FMT("Unknown GSM SMS cause (%d)") % (int)code));
+    }
+}
+
+std::string Verbose::internal_gsmSmsCause(KGsmSmsCause code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+#if K3L_AT_LEAST(2,1,0)
+        case kgscNone:                           return presentation(fmt, "kgscNone",                         "None");
+#endif
+        case kgscUnassigned:                     return presentation(fmt, "kgscUnassigned",                   "Unassigned number");
+        case kgscOperatorDeterminedBarring:      return presentation(fmt, "kgscOperatorDeterminedBarring",    "Operator determined barring");
+        case kgscCallBarred:                     return presentation(fmt, "kgscCallBarred",                   "Call barred");
+        case kgscSMSTransferRejected:            return presentation(fmt, "kgscSMSTransferRejected",          "SMS transfer rejected");
+        case kgscDestinationOutOfService:        return presentation(fmt, "kgscDestinationOutOfService",      "Destination out of service");
+        case kgscUnidentifiedSubscriber:         return presentation(fmt, "kgscUnidentifiedSubscriber",       "Unidentified subscriber");
+        case kgscFacilityRejected:               return presentation(fmt, "kgscFacilityRejected",             "Facility rejected");
+        case kgscUnknownSubscriber:              return presentation(fmt, "kgscUnknownSubscriber",            "Unknown subscriber");
+        case kgscNetworkOutOfOrder:              return presentation(fmt, "kgscNetworkOutOfOrder",            "Network out of order");
+        case kgscTemporaryFailure:               return presentation(fmt, "kgscTemporaryFailure",             "Temporary failure");
+        case kgscCongestion:                     return presentation(fmt, "kgscCongestion",                   "Congestion");
+        case kgscResourcesUnavailable:           return presentation(fmt, "kgscResourcesUnavailable",         "Resources unavailable");
+        case kgscFacilityNotSubscribed:          return presentation(fmt, "kgscFacilityNotSubscribed",        "Facility not subscribed");
+        case kgscFacilityNotImplemented:         return presentation(fmt, "kgscFacilityNotImplemented",       "Facility not implemented");
+        case kgscInvalidSMSTransferRefValue:     return presentation(fmt, "kgscInvalidSMSTransferRefValue",   "Invalid SMS transfer reference value");
+        case kgscInvalidMessage:                 return presentation(fmt, "kgscInvalidMessage",               "Invalid message");
+        case kgscInvalidMandatoryInformation:    return presentation(fmt, "kgscInvalidMandatoryInformation",  "Invalid mandatory information");
+        case kgscMessageTypeNonExistent:         return presentation(fmt, "kgscMessageTypeNonExistent",       "Message type non existent");
+        case kgscMsgNotCompatWithSMProtState:    return presentation(fmt, "kgscMsgNotCompatWithSMProtState",  "Message not compatible with SMS protection state");
+        case kgscInformationElementNonExiste:    return presentation(fmt, "kgscInformationElementNonExiste",  "Information element non existent");
+        case kgscProtocolError:                  return presentation(fmt, "kgscProtocolError",                "Protocol error");
+        case kgscInterworking:                   return presentation(fmt, "kgscInterworking",                 "Interworking");
+        case kgscTelematicInterworkingNotSup:    return presentation(fmt, "kgscTelematicInterworkingNotSup",  "Telematic interworking not supported");
+        case kgscSMSTypeZeroNotSupported:        return presentation(fmt, "kgscSMSTypeZeroNotSupported",      "SMS type zero not supported");
+        case kgscCannotReplaceSMS:               return presentation(fmt, "kgscCannotReplaceSMS",             "Cannot replace SMS");
+        case kgscUnspecifiedTPPIDError:          return presentation(fmt, "kgscUnspecifiedTPPIDError",        "Unspecified TPPID error");
+        case kgscAlphabetNotSupported:           return presentation(fmt, "kgscAlphabetNotSupported",         "Alphabet not supported");
+        case kgscMessageClassNotSupported:       return presentation(fmt, "kgscMessageClassNotSupported",     "Message class not supported");
+        case kgscUnspecifiedTPDCSError:          return presentation(fmt, "kgscUnspecifiedTPDCSError",        "Unspecified TPDCS error");
+        case kgscCommandCannotBeActioned:        return presentation(fmt, "kgscCommandCannotBeActioned",      "Command cannot be actioned");
+        case kgscCommandUnsupported:             return presentation(fmt, "kgscCommandUnsupported",           "Command unsupported");
+        case kgscUnspecifiedTPCommandError:      return presentation(fmt, "kgscUnspecifiedTPCommandError",    "Unspecified TP command error");
+        case kgscTPDUNotSupported:               return presentation(fmt, "kgscTPDUNotSupported",             "TPDU not supported");
+        case kgscSCBusy:                         return presentation(fmt, "kgscSCBusy",                       "SC busy");
+        case kgscNoSCSubscription:               return presentation(fmt, "kgscNoSCSubscription",             "No SC subscription");
+        case kgscSCSystemFailure:                return presentation(fmt, "kgscSCSystemFailure",              "SC system failure");
+        case kgscInvalidSMEAddress:              return presentation(fmt, "kgscInvalidSMEAddress",            "Invalid SME address");
+        case kgscDestinationSMEBarred:           return presentation(fmt, "kgscDestinationSMEBarred",         "Destination SME barred");
+        case kgscSMRejectedDuplicateSM:          return presentation(fmt, "kgscSMRejectedDuplicateSM",        "SM rejected duplicate SM");
+        case kgscTPVPFNotSupported:              return presentation(fmt, "kgscTPVPFNotSupported",            "TPVPF not supported");
+        case kgscTPVPNotSupported:               return presentation(fmt, "kgscTPVPNotSupported",             "TPVP not supported");
+        case kgscSIMSMSStorageFull:              return presentation(fmt, "kgscSIMSMSStorageFull",            "SIM SMS storage full");
+        case kgscNoSMSStorageCapabilityInSIM:    return presentation(fmt, "kgscNoSMSStorageCapabilityInSIM",  "No SMS storage capability in SIM");
+        case kgscErrorInMS:                      return presentation(fmt, "kgscErrorInMS",                    "Error in SMS");
+        case kgscMemoryCapacityExceeded:         return presentation(fmt, "kgscMemoryCapacityExceeded",       "Memory capatity exceeded");
+        case kgscSIMDataDownloadError:           return presentation(fmt, "kgscSIMDataDownloadError",         "SIM data download error");
+        case kgscUnspecifiedError:               return presentation(fmt, "kgscUnspecifiedError",             "Unspecified error");
+        case kgscPhoneFailure:                   return presentation(fmt, "kgscPhoneFailure",                 "Phone failure");
+        case kgscSmsServiceReserved:             return presentation(fmt, "kgscSmsServiceReserved",           "SMS service reserved");
+        case kgscOperationNotAllowed:            return presentation(fmt, "kgscOperationNotAllowed",          "Operation not allowed");
+        case kgscOperationNotSupported:          return presentation(fmt, "kgscOperationNotSupported",        "Operation not supported");
+        case kgscInvalidPDUModeParameter:        return presentation(fmt, "kgscInvalidPDUModeParameter",      "Invalid PDU mode parameter");
+        case kgscInvalidTextModeParameter:       return presentation(fmt, "kgscInvalidTextModeParameter",     "Invalid text mode parameter");
+        case kgscSIMNotInserted:                 return presentation(fmt, "kgscSIMNotInserted",               "SIM not inserted");
+        case kgscSIMPINNecessary:                return presentation(fmt, "kgscSIMPINNecessary",              "SIM PIN necessary");
+        case kgscPH_SIMPINNecessary:             return presentation(fmt, "kgscPH_SIMPINNecessary",           "Phone SIM PIN necessary");
+        case kgscSIMFailure:                     return presentation(fmt, "kgscSIMFailure",                   "SIM failure");
+        case kgscSIMBusy:                        return presentation(fmt, "kgscSIMBusy",                      "SIM busy");
+        case kgscSIMWrong:                       return presentation(fmt, "kgscSIMWrong",                     "SIM wrong");
+        case kgscMemoryFailure:                  return presentation(fmt, "kgscMemoryFailure",                "Memory failure");
+        case kgscInvalidMemoryIndex:             return presentation(fmt, "kgscInvalidMemoryIndex",           "Invalid memory index");
+        case kgscMemoryFull:                     return presentation(fmt, "kgscMemoryFull",                   "Memory full");
+        case kgscSMSCAddressUnknown:             return presentation(fmt, "kgscSMSCAddressUnknown",           "SMSC address unknown");
+        case kgscNoNetworkService:               return presentation(fmt, "kgscNoNetworkService",             "No network service");
+        case kgscNetworkTimeout:                 return presentation(fmt, "kgscNetworkTimeout",               "Network timeout");
+        case kgscUnknownError:                   return presentation(fmt, "kgscUnknownError",                 "Unknown error");
+        case kgscNetworkBusy:                    return presentation(fmt, "kgscNetworkBusy",                  "Network busy");
+        case kgscInvalidDestinationAddress:      return presentation(fmt, "kgscInvalidDestinationAddress",    "Invalid destination address");
+        case kgscInvalidMessageBodyLength:       return presentation(fmt, "kgscInvalidMessageBodyLength",     "Invalid message body length");
+        case kgscPhoneIsNotInService:            return presentation(fmt, "kgscPhoneIsNotInService",          "Phone is not in service");
+        case kgscInvalidPreferredMemStorage:     return presentation(fmt, "kgscInvalidPreferredMemStorage",   "Invalid preferred memory storage");
+        case kgscUserTerminated:                 return presentation(fmt, "kgscUserTerminated",               "User terminated");
+    }
+
+    throw internal_not_found();
+}
+
+std::string Verbose::q931ProgressIndication(KQ931ProgressIndication code, Verbose::Presentation fmt)
+{
+    try
+    {
+        return internal_q931ProgressIndication(code);
+    }
+    catch (internal_not_found & e)
+    {
+        PRESENTATION_CHECK_RETURN(fmt,
+            STG(FMT("[KQ931ProgressIndication='%d']") % (int)code),
+            STG(FMT("Unknown Q931 progress indication (%d)") % (int)code));
+    }
+}
+
+std::string Verbose::internal_q931ProgressIndication(KQ931ProgressIndication code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kq931pTonesMaybeAvailable:     return presentation(fmt, "kq931pTonesMaybeAvailable",  "Tones may be available");
+        case kq931pDestinationIsNonIsdn:    return presentation(fmt, "kq931pDestinationIsNonIsdn", "Destination is not ISDN");
+        case kq931pOriginationIsNonIsdn:    return presentation(fmt, "kq931pOriginationIsNonIsdn", "Origination is not ISDN");
+        case kq931pCallReturnedToIsdn:      return presentation(fmt, "kq931pCallReturnedToIsdn",   "Call returned to ISDN");
+        case kq931pTonesAvailable:          return presentation(fmt, "kq931pTonesAvailable",       "Tones available");
+    }
+
+    throw internal_not_found();
+}
+
+#endif /* K3L_AT_LEAST(1,6,0) */
+
+
+
+
+#if K3L_AT_LEAST(2,1,0)
+std::string Verbose::faxResult(KFaxResult code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kfaxrEndOfTransmission:    return presentation(fmt, "kfaxrEndOfTransmission", "EndOfTransmission");
+        case kfaxrStoppedByCommand:     return presentation(fmt, "kfaxrStoppedByCommand", "StoppedByCommand");
+        case kfaxrProtocolTimeout:      return presentation(fmt, "kfaxrProtocolTimeout", "ProtocolTimeout");
+        case kfaxrProtocolError:        return presentation(fmt, "kfaxrProtocolError", "ProtocolError");
+        case kfaxrRemoteDisconnection:  return presentation(fmt, "kfaxrRemoteDisconnection", "RemoteDisconnection");
+        case kfaxrFileError:            return presentation(fmt, "kfaxrFileError", "FileError");
+        case kfaxrUnknown:              return presentation(fmt, "kfaxrUnknown", "Unknown");
+        case kfaxrEndOfReception:       return presentation(fmt, "kfaxrEndOfReception", "EndOfReception");
+        case kfaxrCompatibilityError:   return presentation(fmt, "kfaxrCompatibilityError", "CompatibilityError");
+        case kfaxrQualityError:         return presentation(fmt, "kfaxrQualityError", "QualityError");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KFaxResult='%d']") % (int)code),
+        STG(FMT("Unknown fax result (%d)") % (int)code));
+}
+
+std::string Verbose::faxFileErrorCause(KFaxFileErrorCause code, Verbose::Presentation fmt)
+{
+    switch (code)
+    {
+        case kfaxfecTransmissionStopped:       return presentation(fmt, "kfaxfecTransmissionStopped", "TransmissionStopped");
+        case kfaxfecTransmissionError:          return presentation(fmt, "kfaxfecTransmissionError", "TransmissionError");
+        case kfaxfecListCleared:                return presentation(fmt, "kfaxfecListCleared", "ListCleared");
+        case kfaxfecCouldNotOpen:               return presentation(fmt, "kfaxfecCouldNotOpen", "CouldNotOpen");
+        case kfaxfecInvalidHeader:              return presentation(fmt, "kfaxfecInvalidHeader", "InvalidHeader");
+        case kfaxfecDataNotFound:               return presentation(fmt, "kfaxfecDataNotFound", "DataNotFound");
+        case kfaxfecInvalidHeight:              return presentation(fmt, "kfaxfecInvalidHeight", "InvalidHeight");
+        case kfaxfecUnsupportedWidth:           return presentation(fmt, "kfaxfecUnsupportedWidth", "UnsupportedWidth");
+        case kfaxfecUnsupportedCompression:     return presentation(fmt, "kfaxfecUnsupportedCompression", "UnsupportedCompression");
+        case kfaxfecUnsupportedRowsPerStrip:    return presentation(fmt, "kfaxfecUnsupportedRowsPerStrip", "UnsupportedRowsPerStrip");
+        case kfaxfecUnknown:                    return presentation(fmt, "kfaxfecUnknown", "Unknown");
+    }
+
+    PRESENTATION_CHECK_RETURN(fmt,
+        STG(FMT("[KFaxFileErrorCause='%d']") % (int)code),
+        STG(FMT("Unknown fax file error cause (%d)") % (int)code));
+}
+
+#endif
+
+
+/********/
+
+std::string Verbose::commandName(int32 code)
+{
+    switch ((kcommand)code)
+    {
+        case K_CM_SEIZE:                    return "CM_SEIZE";
+        case K_CM_SYNC_SEIZE:               return "CM_SYNC_SEIZE";
+        case K_CM_DIAL_DTMF:                return "CM_DIAL_DTMF";
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_SIP_REGISTER:             return "CM_SIP_REGISTER";
+#endif
+        case K_CM_DISCONNECT:               return "CM_DISCONNECT";
+        case K_CM_CONNECT:                  return "CM_CONNECT";
+        case K_CM_PRE_CONNECT:              return "CM_PRE_CONNECT";
+        case K_CM_CAS_CHANGE_LINE_STT:      return "CM_CAS_CHANGE_LINE_STT";
+        case K_CM_CAS_SEND_MFC:             return "CM_CAS_SEND_MFC";
+        case K_CM_SET_FORWARD_CHANNEL:      return "CM_SET_FORWARD_CHANNEL";
+        case K_CM_CAS_SET_MFC_DETECT_MODE:  return "CM_CAS_SET_MFC_DETECT_MODE";
+        case K_CM_DROP_COLLECT_CALL:        return "CM_DROP_COLLECT_CALL";
+
+#if K3L_AT_LEAST(1,5,0)
+        case K_CM_MAKE_CALL:                return "CM_MAKE_CALL";
+#endif
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_CM_RINGBACK:                 return "CM_RINGBACK";
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+        case K_CM_USER_INFORMATION:         return "CM_USER_INFORMATION";
+#endif
+
+#if K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(2,2,0)
+        case K_CM_VOIP_SEIZE:               return "CM_VOIP_SEIZE";
+
+#if !K3L_AT_LEAST(2,0,0)
+        /* internal commands */
+        case K_CM_VOIP_START_DEBUG:         return "CM_VOIP_START_DEBUG";
+        case K_CM_VOIP_STOP_DEBUG:          return "CM_VOIP_STOP_DEBUG";
+        case K_CM_VOIP_DUMP_STAT:           return "CM_VOIP_DUMP_STAT";
+#endif
+#endif
+
+#if K3L_AT_LEAST(1,5,2) && !K3L_AT_LEAST(2,0,0)
+        /* internal command */
+        case K_CM_ISDN_DEBUG:               return "CM_ISDN_DEBUG";
+#endif
+
+        case K_CM_LOCK_INCOMING:            return "CM_LOCK_INCOMING";
+        case K_CM_UNLOCK_INCOMING:          return "CM_UNLOCK_INCOMING";
+        case K_CM_LOCK_OUTGOING:            return "CM_LOCK_OUTGOING";
+        case K_CM_UNLOCK_OUTGOING:          return "CM_UNLOCK_OUTGOING";
+
+        case K_CM_START_SEND_FAIL:          return "CM_START_SEND_FAIL";
+        case K_CM_STOP_SEND_FAIL:           return "CM_STOP_SEND_FAIL";
+
+#if K3L_AT_LEAST(1,5,3)
+        case K_CM_END_OF_NUMBER:            return "CM_END_OF_NUMBER";
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_SS_TRANSFER:              return "CM_SS_TRANSFER";
+        case K_CM_GET_SMS:                  return "CM_GET_SMS";
+        case K_CM_PREPARE_SMS:              return "CM_PREPARE_SMS";
+        case K_CM_SEND_SMS:                 return "CM_SEND_SMS";
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        case K_CM_HOLD_SWITCH:              return "CM_HOLD_SWITCH";
+        case K_CM_MPTY_CONF:                return "CM_MPTY_CONF";
+        case K_CM_MPTY_SPLIT:               return "CM_MPTY_SPLIT";
+#endif
+
+        case K_CM_ENABLE_DTMF_SUPPRESSION:  return "CM_ENABLE_DTMF_SUPPRESSION";
+        case K_CM_DISABLE_DTMF_SUPPRESSION: return "CM_DISABLE_DTMF_SUPPRESSION";
+        case K_CM_ENABLE_AUDIO_EVENTS:      return "CM_ENABLE_AUDIO_EVENTS";
+        case K_CM_DISABLE_AUDIO_EVENTS:     return "CM_DISABLE_AUDIO_EVENTS";
+        case K_CM_ENABLE_CALL_PROGRESS:     return "CM_ENABLE_CALL_PROGRESS";
+        case K_CM_DISABLE_CALL_PROGRESS:    return "CM_DISABLE_CALL_PROGRESS";
+        case K_CM_FLASH:                    return "CM_FLASH";
+        case K_CM_ENABLE_PULSE_DETECTION:   return "CM_ENABLE_PULSE_DETECTION";
+        case K_CM_DISABLE_PULSE_DETECTION:  return "CM_DISABLE_PULSE_DETECTION";
+        case K_CM_ENABLE_ECHO_CANCELLER:    return "CM_ENABLE_ECHO_CANCELLER";
+        case K_CM_DISABLE_ECHO_CANCELLER:   return "CM_DISABLE_ECHO_CANCELLER";
+        case K_CM_ENABLE_AGC:               return "CM_ENABLE_AGC";
+        case K_CM_DISABLE_AGC:              return "CM_DISABLE_AGC";
+        case K_CM_ENABLE_HIGH_IMP_EVENTS:   return "CM_ENABLE_HIGH_IMP_EVENTS";
+        case K_CM_DISABLE_HIGH_IMP_EVENTS:  return "CM_DISABLE_HIGH_IMP_EVENTS";
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_ENABLE_CALL_ANSWER_INFO:  return "CM_ENABLE_CALL_ANSWER_INFO";
+        case K_CM_DISABLE_CALL_ANSWER_INFO: return "CM_DISABLE_CALL_ANSWER_INFO";
+#endif
+
+        case K_CM_RESET_LINK:               return "CM_RESET_LINK";
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_CLEAR_LINK_ERROR_COUNTER: return "CM_CLEAR_LINK_ERROR_COUNTER";
+#endif
+
+        case K_CM_SEND_DTMF:                return "CM_SEND_DTMF";
+        case K_CM_STOP_AUDIO:               return "CM_STOP_AUDIO";
+        case K_CM_HARD_RESET:               return "CM_HARD_RESET";
+
+        case K_CM_SEND_TO_CTBUS:            return "CM_SEND_TO_CTBUS";
+        case K_CM_RECV_FROM_CTBUS:          return "CM_RECV_FROM_CTBUS";
+        case K_CM_SETUP_H100:               return "CM_SETUP_H100";
+
+        case K_CM_MIXER:                    return "CM_MIXER";
+        case K_CM_CLEAR_MIXER:              return "CM_CLEAR_MIXER";
+        case K_CM_PLAY_FROM_FILE:           return "CM_PLAY_FROM_FILE";
+        case K_CM_RECORD_TO_FILE:           return "CM_RECORD_TO_FILE";
+        case K_CM_PLAY_FROM_STREAM:         return "CM_PLAY_FROM_STREAM";
+        case K_CM_STOP_PLAY:                return "CM_STOP_PLAY";
+        case K_CM_STOP_RECORD:              return "CM_STOP_RECORD";
+        case K_CM_PAUSE_PLAY:               return "CM_PAUSE_PLAY";
+        case K_CM_PAUSE_RECORD:             return "CM_PAUSE_RECORD";
+        case K_CM_INCREASE_VOLUME:          return "CM_INCREASE_VOLUME";
+        case K_CM_DECREASE_VOLUME:          return "CM_DECREASE_VOLUME";
+        case K_CM_LISTEN:                   return "CM_LISTEN";
+        case K_CM_STOP_LISTEN:              return "CM_STOP_LISTEN";
+        case K_CM_PREPARE_FOR_LISTEN:       return "CM_PREPARE_FOR_LISTEN";
+
+        case K_CM_PLAY_SOUND_CARD:          return "CM_PLAY_SOUND_CARD";
+        case K_CM_STOP_SOUND_CARD:          return "CM_STOP_SOUND_CARD";
+
+        case K_CM_MIXER_CTBUS:              return "CM_MIXER_CTBUS";
+        case K_CM_PLAY_FROM_STREAM_EX:      return "CM_PLAY_FROM_STREAM_EX";
+        case K_CM_ENABLE_PLAYER_AGC:        return "CM_ENABLE_PLAYER_AGC";
+        case K_CM_DISABLE_PLAYER_AGC:       return "CM_DISABLE_PLAYER_AGC";
+        case K_CM_START_STREAM_BUFFER:      return "CM_START_STREAM_BUFFER";
+        case K_CM_ADD_STREAM_BUFFER:        return "CM_ADD_STREAM_BUFFER";
+        case K_CM_STOP_STREAM_BUFFER:       return "CM_STOP_STREAM_BUFFER";
+        case K_CM_SEND_BEEP:                return "CM_SEND_BEEP";
+        case K_CM_SEND_BEEP_CONF:           return "CM_SEND_BEEP_CONF";
+        case K_CM_ADD_TO_CONF:              return "CM_ADD_TO_CONF";
+        case K_CM_REMOVE_FROM_CONF:         return "CM_REMOVE_FROM_CONF";
+        case K_CM_RECORD_TO_FILE_EX:        return "CM_RECORD_TO_FILE_EX";
+
+#if K3L_AT_LEAST(1,5,4)
+        case K_CM_SET_VOLUME:               return "CM_SET_VOLUME";
+#endif
+        case K_CM_SET_LINE_CONDITION:       return "CM_SET_LINE_CONDITION";
+        case K_CM_SEND_LINE_CONDITION:      return "CM_SEND_LINE_CONDITION";
+        case K_CM_SET_CALLER_CATEGORY:      return "CM_SET_CALLER_CATEGORY";
+        case K_CM_DIAL_MFC:                 return "CM_DIAL_MFC";
+
+        case K_CM_INTERNAL_PLAY:            return "CM_INTERNAL_PLAY";
+        case K_CM_RESUME_PLAY:              return "CM_RESUME_PLAY";
+        case K_CM_RESUME_RECORD:            return "CM_RESUME_RECORD";
+        case K_CM_INTERNAL_PLAY_EX:         return "CM_INTERNAL_PLAY_EX";
+#if !K3L_AT_LEAST(2,0,0)
+        case K_CM_PING:                     return "CM_PING";
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_LOG_REQUEST:              return "CM_LOG_REQUEST";
+        case K_CM_LOG_CREATE_DISPATCHER:    return "CM_LOG_CREATE_DISPATCHER";
+        case K_CM_LOG_DESTROY_DISPATCHER:   return "CM_LOG_DESTROY_DISPATCHER";
+#endif
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_START_CADENCE:            return "CM_START_CADENCE";
+        case K_CM_STOP_CADENCE:             return "CM_STOP_CADENCE";
+        case K_CM_CHECK_NEW_SMS:            return "CM_CHECK_NEW_SMS";
+        case K_CM_SEND_TO_MODEM:            return "CM_SEND_TO_MODEM";
+#endif
+#if K3L_AT_LEAST(2,1,0)
+        case K_CM_START_FAX_TX:             return "CM_START_FAX_TX";
+        case K_CM_STOP_FAX_TX:              return "CM_STOP_FAX_TX";
+        case K_CM_ADD_FAX_FILE:             return "CM_ADD_FAX_FILE";
+        case K_CM_ADD_FAX_PAGE_BREAK:       return "CM_ADD_FAX_PAGE_BREAK";
+        case K_CM_START_FAX_RX:             return "CM_START_FAX_RX";
+        case K_CM_STOP_FAX_RX:              return "CM_STOP_FAX_RX";
+        case K_CM_SIM_CARD_SELECT:          return "CM_SIM_CARD_SELECT";
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+       case K_CM_NOTIFY_WATCHDOG:           return "CM_NOTIFY_WATCHDOG";
+       case K_CM_STOP_WATCHDOG:             return "CM_STOP_WATCHDOG";
+       case K_CM_WATCHDOG_COUNT:            return "CM_WATCHDOG_COUNT";
+       case K_CM_START_WATCHDOG:            return "CM_START_WATCHDOG";
+#endif
+
+    }
+
+    return STG(FMT("[command='%d']") % code);
+}
+
+std::string Verbose::eventName(int32 code)
+{
+    switch ((kevent)code)
+    {
+        case K_EV_CHANNEL_FREE:         return "EV_CHANNEL_FREE";
+        case K_EV_CONNECT:              return "EV_CONNECT";
+        case K_EV_DISCONNECT:           return "EV_DISCONNECT";
+        case K_EV_CALL_SUCCESS:         return "EV_CALL_SUCCESS";
+        case K_EV_CALL_FAIL:            return "EV_CALL_FAIL";
+        case K_EV_NO_ANSWER:            return "EV_NO_ANSWER";
+        case K_EV_BILLING_PULSE:        return "EV_BILLING_PULSE";
+        case K_EV_SEIZE_SUCCESS:        return "EV_SEIZE_SUCCESS";
+        case K_EV_SEIZE_FAIL:           return "EV_SEIZE_FAIL";
+        case K_EV_SEIZURE_START:        return "EV_SEIZURE_START";
+        case K_EV_CAS_LINE_STT_CHANGED: return "EV_CAS_LINE_STT_CHANGED";
+        case K_EV_CAS_MFC_RECV:         return "EV_CAS_MFC_RECV";
+
+#if K3L_AT_LEAST(1,5,0)
+        case K_EV_NEW_CALL:             return "EV_NEW_CALL";
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+        case K_EV_USER_INFORMATION:     return "EV_USER_INFORMATION";
+#endif
+
+#if K3L_AT_LEAST(1,5,3)
+        case K_EV_DIALED_DIGIT:         return "EV_DIALED_DIGIT";
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_SIP_REGISTER_INFO:    return "EV_SIP_REGISTER_INFO";
+#endif
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_EV_CALL_HOLD_START:      return "EV_CALL_HOLD_START";
+        case K_EV_CALL_HOLD_STOP:       return "EV_CALL_HOLD_STOP";
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_SS_TRANSFER_FAIL:     return "EV_SS_TRANSFER_FAIL";
+        case K_EV_FLASH:                return "EV_FLASH";
+#endif
+
+        case K_EV_DTMF_DETECTED:        return "EV_DTMF_DETECTED";
+        case K_EV_DTMF_SEND_FINISH:     return "EV_DTMF_SEND_FINISH";
+        case K_EV_AUDIO_STATUS:         return "EV_AUDIO_STATUS";
+        case K_EV_CADENCE_RECOGNIZED:   return "EV_CADENCE_RECOGNIZED";
+
+        case K_EV_END_OF_STREAM:        return "EV_END_OF_STREAM";
+        case K_EV_PULSE_DETECTED:       return "EV_PULSE_DETECTED";
+
+#if K3L_AT_LEAST(1,5,1)
+        case K_EV_POLARITY_REVERSAL:    return "EV_POLARITY_REVERSAL";
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_ISDN_PROGRESS_INDICATOR: return "EV_ISDN_PROGRESS_INDICATOR";
+        case K_EV_CALL_ANSWER_INFO:        return "EV_CALL_ANSWER_INFO";
+        case K_EV_COLLECT_CALL:            return "EV_COLLECT_CALL";
+        case K_EV_SIP_DTMF_DETECTED:       return "EV_SIP_DTMF_DETECTED";
+
+        case K_EV_RECV_FROM_MODEM:      return "EV_RECV_FROM_MODEM";
+        case K_EV_NEW_SMS:              return "EV_NEW_SMS";
+        case K_EV_SMS_INFO:             return "EV_SMS_INFO";
+        case K_EV_SMS_DATA:             return "EV_SMS_DATA";
+        case K_EV_SMS_SEND_RESULT:      return "EV_SMS_SEND_RESULT";
+        case K_EV_RING_DETECTED:        return "EV_RING_DETECTED";
+        case K_EV_PHYSICAL_LINK_DOWN:   return "EV_PHYSICAL_LINK_DOWN";
+        case K_EV_PHYSICAL_LINK_UP:     return "EV_PHYSICAL_LINK_UP";
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        case K_EV_CALL_MPTY_START:      return "EV_CALL_MPTY_START";
+        case K_EV_CALL_MPTY_STOP:       return "EV_CALL_MPTY_STOP";
+        case K_EV_GSM_COMMAND_STATUS:   return "EV_GSM_COMMAND_STATUS";
+#endif
+#if !K3L_AT_LEAST(2,0,0)
+        case K_EV_PONG:                 return "EV_PONG";
+#endif
+        case K_EV_CHANNEL_FAIL:         return "EV_CHANNEL_FAIL";
+        case K_EV_REFERENCE_FAIL:       return "EV_REFERENCE_FAIL";
+        case K_EV_INTERNAL_FAIL:        return "EV_INTERNAL_FAIL";
+        case K_EV_HARDWARE_FAIL:        return "EV_HARDWARE_FAIL";
+        case K_EV_LINK_STATUS:          return "EV_LINK_STATUS";
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_EV_CLIENT_RECONNECT:     return "EV_CLIENT_RECONNECT";
+        case K_EV_VOIP_SEIZURE:         return "EV_VOIP_SEIZURE";
+#endif
+        case K_EV_SEIZURE:              return "EV_SEIZURE";
+#if K3L_AT_LEAST(2,1,0)
+        case K_EV_FAX_CHANNEL_FREE:     return "EV_FAX_CHANNEL_FREE";
+        case K_EV_FAX_FILE_SENT:        return "EV_FAX_FILE_SENT";
+        case K_EV_FAX_FILE_FAIL:        return "EV_FAX_FILE_FAIL";
+    /*case K_EV_FAX_MESSAGE_CONFIRMATION:return "EV_FAX_MESSAGE_CONFIRMATION";*/
+        case K_EV_FAX_TX_TIMEOUT:       return "EV_FAX_TX_TIMEOUT";
+        case K_EV_FAX_PAGE_CONFIRMATION:return "EV_FAX_PAGE_CONFIRMATION";
+        case K_EV_FAX_REMOTE_INFO:      return "EV_FAX_REMOTE_INFO";
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        case K_EV_WATCHDOG_COUNT:       return "EV_WATCHDOG_COUNT";
+#endif
+    }
+
+    return STG(FMT("[event='%d']") % code);
+}
+
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::command(int32 dev, K3L_COMMAND *k3lcmd, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::command(int32 dev, K3L_COMMAND *k3lcmd, Verbose::Presentation fmt)
+#endif
+{
+#if K3L_AT_LEAST(2,0,0)
+    return command(k3lcmd->Cmd, dev, k3lcmd->Object, (const char *) k3lcmd->Params, r2_country, fmt);
+#else
+    return command(k3lcmd->Cmd, dev, k3lcmd->Object, (const char *) k3lcmd->Params, fmt);
+#endif
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const char * params, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::command(int32 cmd_code, int32 dev_idx, int32 obj_idx, const char * params, Verbose::Presentation fmt)
+#endif
+{
+    unsigned short int dev = (unsigned short int) dev_idx;
+    unsigned short int obj = (unsigned short int) obj_idx;
+
+    kcommand code = (kcommand) cmd_code;
+
+    std::string buf, extra;
+
+    switch (code)
+    {
+        case K_CM_SEIZE:
+        case K_CM_SYNC_SEIZE:
+        //case K_CM_VOIP_SEIZE://deprecated
+        case K_CM_DIAL_MFC:
+        case K_CM_DIAL_DTMF:
+
+        case K_CM_CONNECT:
+        case K_CM_PRE_CONNECT:
+        case K_CM_DISCONNECT:
+        case K_CM_DROP_COLLECT_CALL:
+
+        case K_CM_START_SEND_FAIL:
+        case K_CM_STOP_SEND_FAIL:
+
+        case K_CM_ENABLE_DTMF_SUPPRESSION:
+        case K_CM_DISABLE_DTMF_SUPPRESSION:
+        case K_CM_ENABLE_AUDIO_EVENTS:
+        case K_CM_DISABLE_AUDIO_EVENTS:
+        case K_CM_ENABLE_CALL_PROGRESS:
+        case K_CM_DISABLE_CALL_PROGRESS:
+        case K_CM_ENABLE_PULSE_DETECTION:
+        case K_CM_DISABLE_PULSE_DETECTION:
+        case K_CM_ENABLE_ECHO_CANCELLER:
+        case K_CM_DISABLE_ECHO_CANCELLER:
+        case K_CM_ENABLE_AGC:
+        case K_CM_DISABLE_AGC:
+        case K_CM_ENABLE_HIGH_IMP_EVENTS:
+        case K_CM_DISABLE_HIGH_IMP_EVENTS:
+
+        case K_CM_FLASH:
+        case K_CM_RESET_LINK:
+        case K_CM_CLEAR_MIXER:
+
+        case K_CM_LOCK_INCOMING:
+        case K_CM_UNLOCK_INCOMING:
+        case K_CM_LOCK_OUTGOING:
+        case K_CM_UNLOCK_OUTGOING:
+
+        case K_CM_INCREASE_VOLUME:
+        case K_CM_DECREASE_VOLUME:
+
+        case K_CM_STOP_RECORD:
+        case K_CM_PAUSE_RECORD:
+        case K_CM_RESUME_RECORD:
+
+        case K_CM_STOP_LISTEN:
+
+        case K_CM_PLAY_SOUND_CARD:
+        case K_CM_STOP_SOUND_CARD:
+        case K_CM_RINGBACK:
+#if K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(2,0,0)
+        case K_CM_VOIP_START_DEBUG:
+        case K_CM_VOIP_STOP_DEBUG:
+        case K_CM_VOIP_DUMP_STAT:
+#endif
+
+#if K3L_AT_LEAST(1,5,3)
+        case K_CM_END_OF_NUMBER:
+#endif
+
+#if K3L_AT_LEAST(1,5,4)
+        case K_CM_SET_VOLUME:
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_ENABLE_CALL_ANSWER_INFO:
+        case K_CM_DISABLE_CALL_ANSWER_INFO:
+
+        case K_CM_SS_TRANSFER:
+
+        case K_CM_CHECK_NEW_SMS:
+        case K_CM_GET_SMS:
+        case K_CM_PREPARE_SMS:
+        case K_CM_SEND_SMS:
+
+        case K_CM_START_CADENCE:
+        case K_CM_STOP_CADENCE:
+        case K_CM_SEND_TO_MODEM:
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        case K_CM_HOLD_SWITCH:
+        case K_CM_MPTY_CONF:
+        case K_CM_MPTY_SPLIT:
+#endif
+#if K3L_AT_LEAST(2,1,0)
+        case K_CM_SIM_CARD_SELECT:
+#endif
+            if (params != NULL)
+            {
+                extra += "param='";
+                extra += (params ? params : "<empty>");
+                extra += "'";
+
+                return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+            }
+            else
+            {
+                return show(buf, commandName(code), Target(CHANNEL, dev, obj));
+            }
+
+        case K_CM_SEND_DTMF: /* ?? */
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj));
+
+        /****/
+
+        case K_CM_STOP_AUDIO:
+            extra  = "stop='";
+            switch ((params ? (int)(*params) : -1))
+            {
+                case 1:   extra += "tx";
+                case 2:   extra += "rx";
+                case 3:   extra += "tx+rx";
+                default:  extra += "<unknown>";
+            }
+            extra  = "'";
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+
+        /****/
+
+#if K3L_AT_LEAST(1,5,2) && !K3L_AT_LEAST(2,0,0)
+        case K_CM_ISDN_DEBUG:
+            extra  = "flags='";
+            extra += isdnDebug((unsigned long)params);
+            extra += "'";
+
+            return show(buf, commandName(code), Target(NONE), extra);
+#endif
+
+        /****/
+
+#if K3L_AT_LEAST(1,5,1)
+        case K_CM_USER_INFORMATION:
+#endif
+            if (params != NULL)
+            {
+                KUserInformation * userinfo = (KUserInformation *)params;
+
+                std::string tmp((const char*) userinfo->UserInfo, userinfo->UserInfoLength);
+
+                extra = STG(FMT("proto='%d',length='%d',data='%s'")
+                        % userinfo->ProtocolDescriptor % userinfo->UserInfoLength % tmp);
+
+                return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+            }
+            else
+            {
+                return show(buf, commandName(code), Target(CHANNEL, dev, obj));
+            }
+
+        /****/
+
+
+
+        case K_CM_CAS_CHANGE_LINE_STT:
+        {
+            const char status = (params ? *params : 0x00);
+
+            extra += "status='";
+            extra += (status & 0x01 ? "1" : "0");
+            extra += (status & 0x02 ? "1" : "0");
+            extra += (status & 0x04 ? "1" : "0");
+            extra += (status & 0x08 ? "1" : "0");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+        case K_CM_CAS_SEND_MFC:
+        {
+            char mfc = (params ? *params : 0xff);
+
+            extra = STG(FMT("mfc='%d'") % (int) mfc);
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+        case K_CM_CAS_SET_MFC_DETECT_MODE:
+        {
+            int mode = (params ? *((int *)params) : -1);
+
+            extra = STG(FMT("mode='%d'") % mode);
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+        case K_CM_SET_FORWARD_CHANNEL:
+        {
+            int channel = (params ? *((int*) params) : -1);
+
+            extra = STG(FMT("forward='%03d'") % channel);
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+#if K3L_AT_LEAST(1,5,0)
+        case K_CM_MAKE_CALL:
+            extra  = "options='";
+            extra += (params ? params : "<empty>");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+#endif
+
+        case K_CM_MIXER:
+        case K_CM_MIXER_CTBUS:
+        {
+            if (params)
+            {
+                KMixerCommand *m = (KMixerCommand*)params;
+
+                std::string src = mixerSource((KMixerSource)m->Source);
+                std::string idx("<unknown>");
+
+                switch (m->Source)
+                {
+                    case kmsChannel:
+                    case kmsPlay:
+                    case kmsCTbus:
+#if (K3L_AT_LEAST(1,4,0) && !K3L_AT_LEAST(1,6,0))
+                    case kmsVoIP:
+#endif
+#if K3L_AT_LEAST(1,6,0)
+                    case kmsNoDelayChannel:
+#endif
+                        idx = STG(FMT("%02d") % (int)m->SourceIndex);
+                        break;
+
+                    case kmsGenerator:
+                        idx = mixerTone((KMixerTone)m->SourceIndex);
+                        break;
+                };
+
+                extra = STG(FMT("track='%d',src='%s',index='%s'") % (int)m->Track % src % idx);
+            }
+            else
+            {
+                extra = "<unknown>";
+            }
+
+            return show(buf, commandName(code), Target(MIXER, dev, obj), extra);
+        };
+
+        case K_CM_PLAY_FROM_FILE:
+            extra  = "file='";
+            extra += (params ? params : "<empty>");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+
+        case K_CM_RECORD_TO_FILE:
+            extra  = "file='";
+            extra += (params ? params : "<empty>");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+
+        case K_CM_RECORD_TO_FILE_EX:
+            extra  = "params='";
+            extra += (params ? params : "<empty>");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+
+        case K_CM_PLAY_FROM_STREAM:
+        case K_CM_ADD_STREAM_BUFFER:
+        {
+            struct buffer_param
+            {
+                const void * ptr;
+                const int   size;
+            }
+            *p = (buffer_param *) params;
+
+            std::stringstream stream;
+
+            extra = STG(FMT("buffer='%p',size='%d'")
+                % (const void *) p->ptr % (const int) p->size);
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+        }
+
+        case K_CM_PLAY_FROM_STREAM_EX:
+        {
+            struct buffer_param
+            {
+                const void  *  ptr;
+                const int     size;
+                const char   codec;
+            }
+            *p = (buffer_param *) params;
+
+            std::string codec;
+
+            switch (p->codec)
+            {
+                case 0:  codec = "A-Law";
+                case 1:  codec = "PCM-08khz";
+                case 2:  codec = "PCM-11khz";
+                default: codec = "<unknown>";
+            }
+
+            std::stringstream stream;
+
+            extra = STG(FMT("buffer='%p',size='%d',codec='%s'")
+                % (const void *) p->ptr % (const int) p->size % codec);
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+        }
+
+        case K_CM_STOP_PLAY:
+        case K_CM_PAUSE_PLAY:
+        case K_CM_RESUME_PLAY:
+
+        case K_CM_START_STREAM_BUFFER:
+        case K_CM_STOP_STREAM_BUFFER:
+
+        case K_CM_ENABLE_PLAYER_AGC:
+        case K_CM_DISABLE_PLAYER_AGC:
+
+        case K_CM_SEND_BEEP:
+        case K_CM_SEND_BEEP_CONF:
+
+        case K_CM_INTERNAL_PLAY:
+        case K_CM_INTERNAL_PLAY_EX:
+            return show(buf, commandName(code), Target(PLAYER, dev, obj));
+
+        case K_CM_ADD_TO_CONF:
+            extra += "conference='";
+            extra += (params ? (int) (*params) : -1);
+            extra += "'";
+
+            return show(buf, commandName(code), Target(MIXER, dev, obj), extra);
+
+        case CM_REMOVE_FROM_CONF:
+            return show(buf, commandName(code), Target(MIXER, dev, obj));
+
+        case K_CM_LISTEN:
+        case K_CM_PREPARE_FOR_LISTEN:
+        {
+            int msecs = (params ? *((int*)params) : -1);
+
+            extra = STG(FMT("msecs='%d'") % msecs);
+
+            return show(buf, commandName(code), Target(PLAYER, dev, obj), extra);
+        }
+
+        case K_CM_SEND_TO_CTBUS:
+        case K_CM_RECV_FROM_CTBUS:
+        {
+            KCtbusCommand *p = (KCtbusCommand*)(params);
+
+            extra = STG(FMT("stream='%02d',timeslot='%02d',enable='%d'")
+                % (int)p->Stream % (int)p->TimeSlot % (int)p->Enable);
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+        case K_CM_SET_LINE_CONDITION:
+        case K_CM_SEND_LINE_CONDITION:
+            extra  = "condition='";
+#if K3L_AT_LEAST(2,0,0)
+            extra += signGroupB((KSignGroupB) *((int *) params), r2_country);
+#else
+            extra += signGroupB((KSignGroupB) *((int *) params));
+#endif
+            extra += "'";
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_CM_SET_CALLER_CATEGORY:
+            extra  = "category='";
+#if K3L_AT_LEAST(2,0,0)
+            extra += signGroupII((KSignGroupII) *((int *) params), r2_country);
+#else
+            extra += signGroupII((KSignGroupII) *((int *) params));
+#endif
+            extra += "'";
+
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_CM_CLEAR_LINK_ERROR_COUNTER:
+            return show(buf, commandName(code), Target(LINK, dev, obj));
+
+        case K_CM_SIP_REGISTER:
+            if (params != NULL)
+            {
+                extra += "param='";
+                extra += (params ? params : "<empty>");
+                extra += "'";
+
+                return show(buf, commandName(code), Target(DEVICE, dev), extra);
+            }
+            else
+            {
+                return show(buf, commandName(code), Target(DEVICE, dev));
+            }
+#endif
+
+        case K_CM_SETUP_H100:
+            extra += "option='";
+            extra += h100configIndex((KH100ConfigIndex)obj_idx);
+            extra += "'value='";
+            extra += (params ? STG(FMT("%02d") % (int)(*params)) : "<empty>");
+            extra += "'";
+
+            return show(buf, commandName(code), Target(DEVICE, dev), extra);
+
+        case K_CM_HARD_RESET:
+            return show(buf, commandName(code), Target(LINK, dev, obj));
+
+#if !K3L_AT_LEAST(2,0,0)
+        /* como funciona? */
+        case K_CM_LOG_REQUEST:
+        case K_CM_LOG_CREATE_DISPATCHER:
+        case K_CM_LOG_DESTROY_DISPATCHER:
+
+        case K_CM_PING:
+#endif
+            return show(buf, commandName(code), Target(NONE));
+#if K3L_AT_LEAST(2,1,0)
+        case K_CM_START_FAX_TX:
+        case K_CM_START_FAX_RX:
+        case K_CM_ADD_FAX_FILE:
+            extra  = "params='";
+            extra += (params ? params : "<empty>");
+            extra += "'";
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj), extra);
+        case K_CM_STOP_FAX_TX:
+        case K_CM_STOP_FAX_RX:
+        case K_CM_ADD_FAX_PAGE_BREAK:
+            return show(buf, commandName(code), Target(CHANNEL, dev, obj));
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        case K_CM_NOTIFY_WATCHDOG:
+        case K_CM_STOP_WATCHDOG:
+        case K_CM_START_WATCHDOG:
+            return show(buf, commandName(code) , Target(DEVICE, obj));
+        case K_CM_WATCHDOG_COUNT:
+            return show(buf, commandName(code) , Target(NONE));
+#endif
+
+    }
+
+    /* default command handler */
+    return show(buf, commandName(code), Target(CHANNEL, dev, obj));
+}
+
+#if K3L_AT_LEAST(2,0,0)
+std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, R2CountryType r2_country, Verbose::Presentation fmt)
+#else
+std::string Verbose::event(KSignaling sig, int32 obj_idx, K3L_EVENT *ev, Verbose::Presentation fmt)
+#endif
+{
+    unsigned short int dev = (unsigned short int) ev->DeviceId;
+    unsigned short int obj = (unsigned short int) obj_idx;
+
+    kevent code = (kevent) ev->Code;
+
+    std::string buf, extra;
+
+    switch (code)
+    {
+        case K_EV_CHANNEL_FREE:
+        case K_EV_SEIZE_SUCCESS:
+        case K_EV_CALL_SUCCESS:
+        case K_EV_NO_ANSWER:
+        case K_EV_CONNECT:
+        case K_EV_DTMF_SEND_FINISH:
+        case K_EV_SEIZURE_START:
+        case K_EV_BILLING_PULSE:
+        case K_EV_REFERENCE_FAIL:
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_EV_CALL_HOLD_START:
+        case K_EV_CALL_HOLD_STOP:
+#endif
+
+#if K3L_AT_LEAST(1,5,0)
+        case K_EV_NEW_CALL:
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_FLASH:
+        case K_EV_POLARITY_REVERSAL:
+        case K_EV_COLLECT_CALL:
+        case K_EV_SS_TRANSFER_FAIL:
+        case K_EV_RING_DETECTED:
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        case K_EV_CALL_MPTY_START:
+        case K_EV_CALL_MPTY_STOP:
+#endif
+            break;
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_RECV_FROM_MODEM:
+        case K_EV_SMS_INFO:
+        case K_EV_SMS_DATA:
+            extra  = "data='";
+            extra += (ev->Params ? (const char *)(ev->Params) : "<empty>");
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_SMS_SEND_RESULT:
+            extra  = "result='";
+#if K3L_AT_LEAST(2,0,0)
+            extra += gsmSmsCause((KGsmSmsCause)ev->AddInfo);
+#else
+            extra += gsmCallCause((KGsmCallCause)ev->AddInfo);
+#endif
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+#if K3L_HAS_MPTY_SUPPORT
+        case K_EV_GSM_COMMAND_STATUS:
+            extra  = "result='";
+            extra += gsmMobileCause((KGsmMobileCause)ev->AddInfo);
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+#endif
+
+        case K_EV_CALL_ANSWER_INFO:
+            extra  = "info='";
+            extra += callStartInfo((KCallStartInfo)ev->AddInfo);
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_NEW_SMS:
+            if (ev->AddInfo != 0)
+            {
+                extra  = "messages='";
+                extra += STG(FMT("%d") % ev->AddInfo);
+                extra += "'";
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+            }
+            else
+            {
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj));
+            }
+
+        case K_EV_ISDN_PROGRESS_INDICATOR:
+            if (ev->AddInfo != 0)
+            {
+                extra  = "indication='";
+                extra += q931ProgressIndication((KQ931ProgressIndication)ev->AddInfo);
+                extra += "'";
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+            }
+            else
+            {
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj));
+            }
+#endif
+
+        case K_EV_CAS_LINE_STT_CHANGED:
+            extra = STG(FMT("[a=%d,b=%d,c=%d,d=%d]")
+                % ((ev->AddInfo & 0x8) >> 3) % ((ev->AddInfo & 0x4) >> 2)
+                % ((ev->AddInfo & 0x2) >> 1) %  (ev->AddInfo & 0x1));
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_CAS_MFC_RECV:
+            extra = STG(FMT("digit='%d'") % ev->AddInfo);
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_CALL_FAIL:
+            extra  = "cause='";
+#if K3L_AT_LEAST(2,0,0)
+            extra += callFail(sig, r2_country, ev->AddInfo);
+#else
+            extra += callFail(sig, ev->AddInfo);
+#endif
+            extra += "'";
+
+            if (ev->Params != NULL && ev->ParamSize != 0)
+            {
+                if (!extra.empty())
+                    extra += ",";
+
+                extra += "params='";
+                extra += (const char *) ev->Params;
+                extra += "'";
+            }
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_DISCONNECT:
+            switch (sig)
+            {
+#if K3L_AT_LEAST(1,5,1)
+                case ksigOpenCCS:
+                case ksigPRI_EndPoint:
+                case ksigPRI_Network:
+                case ksigPRI_Passive:
+                    extra  = "cause='";
+                    extra += isdnCause((KQ931Cause) ev->AddInfo);
+                    extra += "'";
+#endif
+                default:
+                    break;
+            }
+
+            if (ev->Params != NULL && ev->ParamSize != 0)
+            {
+                if (!extra.empty())
+                    extra += ",";
+
+                extra += "params='";
+                extra += (const char *) ev->Params;
+                extra += "'";
+            }
+
+            if (!extra.empty())
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+            else
+                return show(buf, eventName(code), Target(CHANNEL, dev, obj));
+
+            break;
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_SIP_DTMF_DETECTED:
+#endif
+        case K_EV_DTMF_DETECTED:
+        case K_EV_PULSE_DETECTED:
+        case K_EV_DIALED_DIGIT:
+            extra = STG(FMT("digit='%c'") % (char)ev->AddInfo);
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_SEIZURE:
+        {
+            KIncomingSeizeParams *n = (KIncomingSeizeParams *)
+                ( ((char*)ev) + sizeof(K3L_EVENT) );
+
+            extra += "orig_addr='";
+            extra += n->NumberA;
+            extra += "',dest_addr='";
+            extra += n->NumberB;
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+        }
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_EV_VOIP_SEIZURE:
+        {
+            char *numB = ((char*)ev) + sizeof(K3L_EVENT);
+            char *numA = numB + 61;
+
+            extra  = "numberA='";
+            extra += numA;
+            extra += "',numberB='";
+            extra += numB;
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+        }
+#endif
+
+
+        case K_EV_END_OF_STREAM:
+            return show(buf, eventName(code), Target(PLAYER, dev, obj));
+
+        case K_EV_AUDIO_STATUS:
+            extra  = "tone='";
+            extra += mixerTone((KMixerTone)ev->AddInfo);
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_CADENCE_RECOGNIZED:
+            extra = STG(FMT("cadence='%c'") % (char)(ev->AddInfo));
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_CHANNEL_FAIL:
+            extra  = "reason='";
+            extra += channelFail(sig, ev->AddInfo);
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_SEIZE_FAIL:
+            extra  = "reason='";
+            extra += seizeFail((KSeizeFail) ev->AddInfo);
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_INTERNAL_FAIL:
+            extra  = "reason='";
+            extra += internalFail((KInternalFail) ev->AddInfo);
+            extra += "'";
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_HARDWARE_FAIL:
+            extra  = "component='";
+            extra += systemObject((KSystemObject) ev->AddInfo);
+            extra += "'";
+
+            switch (ev->AddInfo)
+            {
+                case ksoChannel:
+                    return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+                case ksoLink:
+                    return show(buf, eventName(code), Target(LINK, dev, obj), extra);
+                case ksoLinkMon:
+                case ksoH100:
+                case ksoFirmware:
+                case ksoDevice:
+                    return show(buf, eventName(code), Target(DEVICE, dev), extra);
+                case ksoAPI:
+                    return show(buf, eventName(code), Target(NONE), extra);
+            }
+
+
+        case K_EV_LINK_STATUS:
+            // EV_LINK_STATUS has always zero in ObjectInfo (and AddInfo!)
+            /* fall throught... */
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_PHYSICAL_LINK_UP:
+        case K_EV_PHYSICAL_LINK_DOWN:
+            return show(buf, eventName(code), Target(LINK, dev, obj));
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+        case K_EV_USER_INFORMATION:
+        {
+            KUserInformation *info = (KUserInformation *)(ev->Params);
+
+            std::string data((const char *)info->UserInfo,
+                std::min<size_t>(info->UserInfoLength, KMAX_USER_USER_LEN));
+
+            extra = STG(FMT("proto='%d',length='%d',data='%s'")
+                % info->ProtocolDescriptor % info->UserInfoLength % data);
+
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+        }
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+        case K_EV_SIP_REGISTER_INFO:
+            extra  = "params='";
+            extra += (ev->Params ? (const char *) (ev->Params) : "<unknown>");
+            extra += "',status='";
+            extra += sipFailures((KSIP_Failures)(ev->AddInfo));
+            extra += "'";
+
+            return show(buf, eventName(code), Target(DEVICE, dev), extra);
+#endif
+
+#if !K3L_AT_LEAST(2,0,0)
+        case K_EV_PONG:
+#endif
+
+#if K3L_AT_LEAST(1,4,0)
+        case K_EV_CLIENT_RECONNECT:
+#endif
+            return show(buf, eventName(code), Target(NONE));
+
+#if K3L_AT_LEAST(2,1,0)
+        case K_EV_FAX_CHANNEL_FREE:
+            extra  = "status='";
+            extra += faxResult((KFaxResult)ev->AddInfo);
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_FAX_FILE_SENT:
+            extra  = "filename='";
+            extra += (ev->Params ? (const char *) (ev->Params) : "<unknown>");
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_FAX_FILE_FAIL:
+            extra  = "cause='";
+            extra += faxFileErrorCause((KFaxFileErrorCause)ev->AddInfo);
+            extra += "',filename='";
+            extra += (ev->Params ? (const char *) (ev->Params) : "<unknown>");
+            extra += "'";
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        case K_EV_FAX_REMOTE_INFO:
+            extra = ((ev->Params && ev->ParamSize != 0) ? (const char *) ev->Params : "");
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+
+        /*case K_EV_FAX_MESSAGE_CONFIRMATION:*/
+        case K_EV_FAX_PAGE_CONFIRMATION:
+        case K_EV_FAX_TX_TIMEOUT:
+            return show(buf, eventName(code), Target(CHANNEL, dev, obj));
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        case K_EV_WATCHDOG_COUNT:
+            extra = STG(FMT("count='%d'") % (char)ev->AddInfo);
+            return show(buf , eventName(code), Target(NONE), extra);
+#endif
+
+    }
+
+    // default handler...
+    if (ev->Params != NULL && ev->ParamSize != 0)
+    {
+        extra += "params='";
+        extra.append((const char *) ev->Params, (unsigned int) std::max<int>(ev->ParamSize - 1, 0));
+        extra += "'";
+
+        return show(buf, eventName(code), Target(CHANNEL, dev, obj), extra);
+    }
+    else
+        return show(buf, eventName(code), Target(CHANNEL, dev, obj));
+}
+
+/********************************************/
+
+std::string Verbose::show(std::string & buf, std::string name, Target tgt, std::string & extra)
+{
+    if (tgt.type == NONE)
+    {
+        generate(buf, name, tgt, extra);
+    }
+    else
+    {
+        std::string tmp(",");
+        tmp += extra;
+
+        generate(buf, name, tgt, tmp);
+    }
+
+    return buf;
+}
+
+std::string Verbose::show(std::string & buf, std::string name, Target tgt)
+{
+    std::string tmp("");
+
+    generate(buf, name, tgt, tmp);
+    return buf;
+}
+
+void Verbose::generate(std::string &buf, std::string &name, Target tgt, std::string &extra)
+{
+    switch (tgt.type)
+    {
+        case NONE:
+            if (extra.empty())
+                buf += STG(FMT("<%s>") % name);
+            else
+                buf += STG(FMT("<%s> (%s)") % name % extra);
+            break;
+
+        case DEVICE:
+            buf += STG(FMT("<%s> (d=%02d%s)")
+                % name % tgt.device % extra);
+            break;
+
+        default:
+        {
+            const char *kind = "o";
+
+            switch (tgt.type)
+            {
+                case CHANNEL:
+                    kind = "c";
+                    break;
+                case PLAYER:
+                    kind = "p";
+                    break;
+                case MIXER:
+                    kind = "m";
+                    break;
+                case LINK:
+                    kind = "l";
+                default:
+                    break;
+            }
+
+            buf += STG(FMT("<%s> (d=%02d,%s=%03d%s)")
+                % name % tgt.device % kind % tgt.object % extra);
+            break;
+        }
+    }
+}
+
diff --git a/src/mod/endpoints/mod_khomp/commons/verbose.hpp b/src/mod/endpoints/mod_khomp/commons/verbose.hpp
new file mode 100644 (file)
index 0000000..4668ea6
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <string>
+#include <sstream>
+#include <map>
+
+#include <k3l.h>
+
+// k3lApiMajorVersion
+#ifndef CM_PING
+# include <k3lVersion.h>
+# include <KTools.h>
+#endif
+
+#include <types.hpp>
+#include <k3lapi.hpp>
+#include <format.hpp>
+
+#ifndef _VERBOSE_HPP_
+#define _VERBOSE_HPP_
+
+struct Verbose
+{
+    typedef enum
+    {
+        K_CM_SEIZE                           = CM_SEIZE,
+        K_CM_SYNC_SEIZE                      = CM_SYNC_SEIZE,
+#if K3L_AT_LEAST(1,6,0)
+        K_CM_SIP_REGISTER                    = CM_SIP_REGISTER,
+#endif
+        K_CM_DIAL_DTMF                       = CM_DIAL_DTMF,
+        K_CM_DISCONNECT                      = CM_DISCONNECT,
+        K_CM_CONNECT                         = CM_CONNECT,
+        K_CM_PRE_CONNECT                     = CM_PRE_CONNECT,
+        K_CM_CAS_CHANGE_LINE_STT             = CM_CAS_CHANGE_LINE_STT,
+        K_CM_CAS_SEND_MFC                    = CM_CAS_SEND_MFC,
+        K_CM_SET_FORWARD_CHANNEL             = CM_SET_FORWARD_CHANNEL,
+        K_CM_CAS_SET_MFC_DETECT_MODE         = CM_CAS_SET_MFC_DETECT_MODE,
+        K_CM_DROP_COLLECT_CALL               = CM_DROP_COLLECT_CALL,
+        K_CM_MAKE_CALL                       = CM_MAKE_CALL,
+        K_CM_RINGBACK                        = CM_RINGBACK,
+        K_CM_USER_INFORMATION                = CM_USER_INFORMATION,
+#if !K3L_AT_LEAST(2,2,0)
+        K_CM_VOIP_SEIZE                      = CM_VOIP_SEIZE, //deprecated
+#endif
+        K_CM_LOCK_INCOMING                   = CM_LOCK_INCOMING,
+        K_CM_UNLOCK_INCOMING                 = CM_UNLOCK_INCOMING,
+        K_CM_LOCK_OUTGOING                   = CM_LOCK_OUTGOING,
+        K_CM_UNLOCK_OUTGOING                 = CM_UNLOCK_OUTGOING,
+        K_CM_START_SEND_FAIL                 = CM_START_SEND_FAIL,
+        K_CM_STOP_SEND_FAIL                  = CM_STOP_SEND_FAIL,
+        K_CM_END_OF_NUMBER                   = CM_END_OF_NUMBER,
+#if K3L_AT_LEAST(1,6,0)
+        K_CM_SS_TRANSFER                     = CM_SS_TRANSFER,
+        K_CM_GET_SMS                         = CM_GET_SMS,
+        K_CM_PREPARE_SMS                     = CM_PREPARE_SMS,
+        K_CM_SEND_SMS                        = CM_SEND_SMS,
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        K_CM_HOLD_SWITCH                     = CM_HOLD_SWITCH,
+        K_CM_MPTY_CONF                       = CM_MPTY_CONF,
+        K_CM_MPTY_SPLIT                      = CM_MPTY_SPLIT,
+#endif
+        K_CM_ENABLE_DTMF_SUPPRESSION         = CM_ENABLE_DTMF_SUPPRESSION,
+        K_CM_DISABLE_DTMF_SUPPRESSION        = CM_DISABLE_DTMF_SUPPRESSION,
+        K_CM_ENABLE_AUDIO_EVENTS             = CM_ENABLE_AUDIO_EVENTS,
+        K_CM_DISABLE_AUDIO_EVENTS            = CM_DISABLE_AUDIO_EVENTS,
+        K_CM_ENABLE_CALL_PROGRESS            = CM_ENABLE_CALL_PROGRESS,
+        K_CM_DISABLE_CALL_PROGRESS           = CM_DISABLE_CALL_PROGRESS,
+        K_CM_FLASH                           = CM_FLASH,
+        K_CM_ENABLE_PULSE_DETECTION          = CM_ENABLE_PULSE_DETECTION,
+        K_CM_DISABLE_PULSE_DETECTION         = CM_DISABLE_PULSE_DETECTION,
+        K_CM_ENABLE_ECHO_CANCELLER           = CM_ENABLE_ECHO_CANCELLER,
+        K_CM_DISABLE_ECHO_CANCELLER          = CM_DISABLE_ECHO_CANCELLER,
+        K_CM_ENABLE_AGC                      = CM_ENABLE_AGC,
+        K_CM_DISABLE_AGC                     = CM_DISABLE_AGC,
+        K_CM_ENABLE_HIGH_IMP_EVENTS          = CM_ENABLE_HIGH_IMP_EVENTS,
+        K_CM_DISABLE_HIGH_IMP_EVENTS         = CM_DISABLE_HIGH_IMP_EVENTS,
+#if K3L_AT_LEAST(1,6,0)
+        K_CM_ENABLE_CALL_ANSWER_INFO         = CM_ENABLE_CALL_ANSWER_INFO,
+        K_CM_DISABLE_CALL_ANSWER_INFO        = CM_DISABLE_CALL_ANSWER_INFO,
+#endif
+        K_CM_RESET_LINK                      = CM_RESET_LINK,
+#if K3L_AT_LEAST(1,6,0)
+        K_CM_CLEAR_LINK_ERROR_COUNTER        = CM_CLEAR_LINK_ERROR_COUNTER,
+#endif
+        K_CM_SEND_DTMF                       = CM_SEND_DTMF,
+        K_CM_STOP_AUDIO                      = CM_STOP_AUDIO,
+        K_CM_HARD_RESET                      = CM_HARD_RESET,
+        K_CM_SEND_TO_CTBUS                   = CM_SEND_TO_CTBUS,
+        K_CM_RECV_FROM_CTBUS                 = CM_RECV_FROM_CTBUS,
+        K_CM_SETUP_H100                      = CM_SETUP_H100,
+        K_CM_MIXER                           = CM_MIXER,
+        K_CM_CLEAR_MIXER                     = CM_CLEAR_MIXER,
+        K_CM_PLAY_FROM_FILE                  = CM_PLAY_FROM_FILE,
+        K_CM_RECORD_TO_FILE                  = CM_RECORD_TO_FILE,
+        K_CM_PLAY_FROM_STREAM                = CM_PLAY_FROM_STREAM,
+        K_CM_INTERNAL_PLAY                   = CM_INTERNAL_PLAY,
+        K_CM_STOP_PLAY                       = CM_STOP_PLAY,
+        K_CM_STOP_RECORD                     = CM_STOP_RECORD,
+        K_CM_PAUSE_PLAY                      = CM_PAUSE_PLAY,
+        K_CM_PAUSE_RECORD                    = CM_PAUSE_RECORD,
+        K_CM_RESUME_PLAY                     = CM_RESUME_PLAY,
+        K_CM_RESUME_RECORD                   = CM_RESUME_RECORD,
+        K_CM_INCREASE_VOLUME                 = CM_INCREASE_VOLUME,
+        K_CM_DECREASE_VOLUME                 = CM_DECREASE_VOLUME,
+        K_CM_LISTEN                          = CM_LISTEN,
+        K_CM_STOP_LISTEN                     = CM_STOP_LISTEN,
+        K_CM_PREPARE_FOR_LISTEN              = CM_PREPARE_FOR_LISTEN,
+        K_CM_PLAY_SOUND_CARD                 = CM_PLAY_SOUND_CARD,
+        K_CM_STOP_SOUND_CARD                 = CM_STOP_SOUND_CARD,
+        K_CM_MIXER_CTBUS                     = CM_MIXER_CTBUS,
+        K_CM_PLAY_FROM_STREAM_EX             = CM_PLAY_FROM_STREAM_EX,
+        K_CM_INTERNAL_PLAY_EX                = CM_INTERNAL_PLAY_EX,
+        K_CM_ENABLE_PLAYER_AGC               = CM_ENABLE_PLAYER_AGC,
+        K_CM_DISABLE_PLAYER_AGC              = CM_DISABLE_PLAYER_AGC,
+        K_CM_START_STREAM_BUFFER             = CM_START_STREAM_BUFFER,
+        K_CM_ADD_STREAM_BUFFER               = CM_ADD_STREAM_BUFFER,
+        K_CM_STOP_STREAM_BUFFER              = CM_STOP_STREAM_BUFFER,
+        K_CM_SEND_BEEP                       = CM_SEND_BEEP,
+        K_CM_SEND_BEEP_CONF                  = CM_SEND_BEEP_CONF,
+        K_CM_ADD_TO_CONF                     = CM_ADD_TO_CONF,
+        K_CM_REMOVE_FROM_CONF                = CM_REMOVE_FROM_CONF,
+        K_CM_RECORD_TO_FILE_EX               = CM_RECORD_TO_FILE_EX,
+        K_CM_SET_VOLUME                      = CM_SET_VOLUME,
+        K_CM_SET_LINE_CONDITION              = CM_SET_LINE_CONDITION,
+        K_CM_SEND_LINE_CONDITION             = CM_SEND_LINE_CONDITION,
+        K_CM_SET_CALLER_CATEGORY             = CM_SET_CALLER_CATEGORY,
+        K_CM_DIAL_MFC                        = CM_DIAL_MFC,
+#if !K3L_AT_LEAST(2,0,0)
+        K_CM_VOIP_START_DEBUG                = CM_VOIP_START_DEBUG,
+        K_CM_VOIP_STOP_DEBUG                 = CM_VOIP_STOP_DEBUG,
+        K_CM_VOIP_DUMP_STAT                  = CM_VOIP_DUMP_STAT,
+        K_CM_ISDN_DEBUG                      = CM_ISDN_DEBUG,
+        K_CM_PING                            = CM_PING,
+        K_CM_LOG_REQUEST                     = CM_LOG_REQUEST,
+        K_CM_LOG_CREATE_DISPATCHER           = CM_LOG_CREATE_DISPATCHER,
+        K_CM_LOG_DESTROY_DISPATCHER          = CM_LOG_DESTROY_DISPATCHER,
+#endif
+#if K3L_AT_LEAST(1,6,0)
+        K_CM_START_CADENCE                   = CM_START_CADENCE,
+        K_CM_STOP_CADENCE                    = CM_STOP_CADENCE,
+        K_CM_CHECK_NEW_SMS                   = CM_CHECK_NEW_SMS,
+        K_CM_SEND_TO_MODEM                   = CM_SEND_TO_MODEM,
+#endif
+#if K3L_AT_LEAST(2,1,0)
+        K_CM_START_FAX_TX                    = CM_START_FAX_TX,
+        K_CM_STOP_FAX_TX                     = CM_STOP_FAX_TX,
+        K_CM_ADD_FAX_FILE                    = CM_ADD_FAX_FILE,
+        K_CM_ADD_FAX_PAGE_BREAK              = CM_ADD_FAX_PAGE_BREAK,
+        K_CM_START_FAX_RX                    = CM_START_FAX_RX,
+        K_CM_STOP_FAX_RX                     = CM_STOP_FAX_RX,
+        K_CM_SIM_CARD_SELECT                 = CM_SIM_CARD_SELECT,
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        K_CM_NOTIFY_WATCHDOG                = CM_NOTIFY_WATCHDOG,
+        K_CM_STOP_WATCHDOG                  = CM_STOP_WATCHDOG,
+        K_CM_WATCHDOG_COUNT                 = CM_WATCHDOG_COUNT,
+        K_CM_START_WATCHDOG                 = CM_START_WATCHDOG,
+#endif
+
+    }
+    kcommand;
+
+    typedef enum
+    {
+        K_EV_CHANNEL_FREE                    = EV_CHANNEL_FREE,
+        K_EV_CONNECT                         = EV_CONNECT,
+        K_EV_DISCONNECT                      = EV_DISCONNECT,
+        K_EV_CALL_SUCCESS                    = EV_CALL_SUCCESS,
+        K_EV_CALL_FAIL                       = EV_CALL_FAIL,
+        K_EV_NO_ANSWER                       = EV_NO_ANSWER,
+        K_EV_BILLING_PULSE                   = EV_BILLING_PULSE,
+        K_EV_SEIZE_SUCCESS                   = EV_SEIZE_SUCCESS,
+        K_EV_SEIZE_FAIL                      = EV_SEIZE_FAIL,
+        K_EV_SEIZURE_START                   = EV_SEIZURE_START,
+        K_EV_CAS_LINE_STT_CHANGED            = EV_CAS_LINE_STT_CHANGED,
+        K_EV_CAS_MFC_RECV                    = EV_CAS_MFC_RECV,
+        K_EV_NEW_CALL                        = EV_NEW_CALL,
+        K_EV_USER_INFORMATION                = EV_USER_INFORMATION,
+        K_EV_DIALED_DIGIT                    = EV_DIALED_DIGIT,
+#if K3L_AT_LEAST(1,6,0)
+        K_EV_SIP_REGISTER_INFO               = EV_SIP_REGISTER_INFO,
+        K_EV_RING_DETECTED                   = EV_RING_DETECTED,
+#endif
+        K_EV_CALL_HOLD_START                 = EV_CALL_HOLD_START,
+        K_EV_CALL_HOLD_STOP                  = EV_CALL_HOLD_STOP,
+#if K3L_AT_LEAST(1,6,0)
+        K_EV_SS_TRANSFER_FAIL                = EV_SS_TRANSFER_FAIL,
+        K_EV_FLASH                           = EV_FLASH,
+#endif
+        K_EV_DTMF_DETECTED                   = EV_DTMF_DETECTED,
+        K_EV_DTMF_SEND_FINISH                = EV_DTMF_SEND_FINISH,
+        K_EV_AUDIO_STATUS                    = EV_AUDIO_STATUS,
+        K_EV_CADENCE_RECOGNIZED              = EV_CADENCE_RECOGNIZED,
+        K_EV_END_OF_STREAM                   = EV_END_OF_STREAM,
+        K_EV_PULSE_DETECTED                  = EV_PULSE_DETECTED,
+        K_EV_POLARITY_REVERSAL               = EV_POLARITY_REVERSAL,
+#if K3L_AT_LEAST(1,6,0)
+        K_EV_ISDN_PROGRESS_INDICATOR         = EV_ISDN_PROGRESS_INDICATOR,
+        K_EV_CALL_ANSWER_INFO                = EV_CALL_ANSWER_INFO,
+        K_EV_COLLECT_CALL                    = EV_COLLECT_CALL,
+        K_EV_SIP_DTMF_DETECTED               = EV_SIP_DTMF_DETECTED,
+        K_EV_RECV_FROM_MODEM                 = EV_RECV_FROM_MODEM,
+        K_EV_NEW_SMS                         = EV_NEW_SMS,
+        K_EV_SMS_INFO                        = EV_SMS_INFO,
+        K_EV_SMS_DATA                        = EV_SMS_DATA,
+        K_EV_SMS_SEND_RESULT                 = EV_SMS_SEND_RESULT,
+#endif
+#if K3L_HAS_MPTY_SUPPORT
+        K_EV_CALL_MPTY_START                 = EV_CALL_MPTY_START,
+        K_EV_CALL_MPTY_STOP                  = EV_CALL_MPTY_STOP,
+        K_EV_GSM_COMMAND_STATUS              = EV_GSM_COMMAND_STATUS,
+#endif
+        K_EV_CHANNEL_FAIL                    = EV_CHANNEL_FAIL,
+        K_EV_REFERENCE_FAIL                  = EV_REFERENCE_FAIL,
+        K_EV_INTERNAL_FAIL                   = EV_INTERNAL_FAIL,
+        K_EV_HARDWARE_FAIL                   = EV_HARDWARE_FAIL,
+        K_EV_LINK_STATUS                     = EV_LINK_STATUS,
+#if K3L_AT_LEAST(1,6,0)
+        K_EV_PHYSICAL_LINK_UP                = EV_PHYSICAL_LINK_UP,
+        K_EV_PHYSICAL_LINK_DOWN              = EV_PHYSICAL_LINK_DOWN,
+#endif
+        K_EV_CLIENT_RECONNECT                = EV_CLIENT_RECONNECT,
+        K_EV_VOIP_SEIZURE                    = EV_VOIP_SEIZURE,
+        K_EV_SEIZURE                         = EV_SEIZURE,
+
+#if K3L_AT_LEAST(2,1,0)
+        K_EV_FAX_CHANNEL_FREE                = EV_FAX_CHANNEL_FREE,
+        K_EV_FAX_FILE_SENT                   = EV_FAX_FILE_SENT,
+        K_EV_FAX_FILE_FAIL                   = EV_FAX_FILE_FAIL,
+        K_EV_FAX_MESSAGE_CONFIRMATION        = EV_FAX_MESSAGE_CONFIRMATION,
+        K_EV_FAX_TX_TIMEOUT                  = EV_FAX_TX_TIMEOUT,
+        K_EV_FAX_PAGE_CONFIRMATION           = EV_FAX_PAGE_CONFIRMATION,
+        K_EV_FAX_REMOTE_INFO                 = EV_FAX_REMOTE_INFO,
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+        K_EV_WATCHDOG_COUNT                 = EV_WATCHDOG_COUNT,
+#endif
+
+#if !K3L_AT_LEAST(2,0,0)
+        K_EV_PONG                            = EV_PONG,
+#endif
+    }
+    kevent;
+
+    typedef enum
+    {
+        R2_COUNTRY_ARG = 1,
+        R2_COUNTRY_BRA = 2,
+        R2_COUNTRY_CHI = 3,
+        R2_COUNTRY_MEX = 4,
+        R2_COUNTRY_URY = 5,
+        R2_COUNTRY_VEN = 6
+    }
+    R2CountryType;
+
+    typedef enum
+    {
+        HUMAN,
+        EXACT
+    }
+    Presentation;
+
+    /* dynamic (object) stuff */
+
+    Verbose(K3LAPI & api): _api(api) {};
+
+#if K3L_AT_LEAST(2,0,0)
+    std::string event(int32, K3L_EVENT*, R2CountryType r2_country = R2_COUNTRY_BRA,
+        Presentation fmt = HUMAN);
+#else
+    std::string event(int32, K3L_EVENT*, Presentation fmt = HUMAN);
+#endif
+
+    std::string channelStatus(int32, int32, int32, Presentation fmt = HUMAN);
+
+    /* end of dynamic (object) stuff */
+
+ protected:
+    K3LAPI & _api;
+
+    /* used internally */
+    struct internal_not_found {};
+
+ public:
+
+    /* static (class) stuff */
+
+    static std::string echoLocation(KEchoLocation, Presentation fmt = HUMAN);
+    static std::string echoCancellerConfig(KEchoCancellerConfig, Presentation fmt = HUMAN);
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string event(KSignaling, int32, K3L_EVENT*, R2CountryType = R2_COUNTRY_BRA,
+        Presentation fmt = HUMAN);
+#else
+    static std::string event(KSignaling, int32, K3L_EVENT*, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string command(int32, K3L_COMMAND*, R2CountryType = R2_COUNTRY_BRA,
+         Presentation fmt = HUMAN);
+    static std::string command(int32, int32, int32, const char *, R2CountryType = R2_COUNTRY_BRA,
+         Presentation fmt = HUMAN);
+#else
+    static std::string command(int32, K3L_COMMAND*, Presentation fmt = HUMAN);
+    static std::string command(int32, int32, int32, const char *, Presentation fmt = HUMAN);
+#endif
+
+
+    static std::string deviceName(KDeviceType, int32, Presentation fmt = HUMAN);
+
+    static std::string deviceType(KDeviceType, Presentation fmt = HUMAN);
+    static std::string deviceModel(KDeviceType, int32, Presentation fmt = HUMAN);
+
+    static std::string channelFeatures(int32, Presentation fmt = HUMAN);
+    static std::string signaling(KSignaling, Presentation fmt = HUMAN);
+    static std::string systemObject(KSystemObject, Presentation fmt = HUMAN);
+    static std::string mixerTone(KMixerTone, Presentation fmt = HUMAN);
+    static std::string mixerSource(KMixerSource, Presentation fmt = HUMAN);
+
+    static std::string seizeFail(KSeizeFail, Presentation fmt = HUMAN);
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string callFail(KSignaling, R2CountryType, int32, Presentation fmt = HUMAN);
+#else
+    static std::string callFail(KSignaling, int32, Presentation fmt = HUMAN);
+#endif
+
+    static std::string channelFail(KSignaling, int32, Presentation fmt = HUMAN);
+    static std::string internalFail(KInternalFail, Presentation fmt = HUMAN);
+
+    static std::string linkErrorCounter(KLinkErrorCounter, Presentation fmt = HUMAN);
+
+    static std::string linkStatus(KSignaling, int32, Presentation fmt = HUMAN);
+    static std::string channelStatus(KSignaling, int32, Presentation fmt = HUMAN);
+    static std::string callStatus(KCallStatus, Presentation fmt = HUMAN);
+    static std::string status(KLibraryStatus, Presentation fmt = HUMAN);
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string signGroupB(KSignGroupB, R2CountryType contry = R2_COUNTRY_BRA,
+        Presentation fmt = HUMAN);
+#else
+    static std::string signGroupB(KSignGroupB, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string signGroupII(KSignGroupII, R2CountryType contry = R2_COUNTRY_BRA,
+        Presentation fmt = HUMAN);
+#else
+    static std::string signGroupII(KSignGroupII, Presentation fmt = HUMAN);
+#endif
+
+    static std::string h100configIndex(KH100ConfigIndex, Presentation fmt = HUMAN);
+
+    static std::string eventName(int32);
+    static std::string commandName(int32);
+
+#if K3L_AT_LEAST(1,5,0)
+    static std::string sipFailures(KSIP_Failures, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(1,5,1)
+    static std::string isdnCause(KQ931Cause, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(1,5,2)
+    static std::string isdnDebug(int32, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+    static std::string callStartInfo(KCallStartInfo, Presentation fmt = HUMAN);
+
+    static std::string gsmCallCause(KGsmCallCause, Presentation fmt = HUMAN);
+    static std::string gsmMobileCause(KGsmMobileCause, Presentation fmt = HUMAN);
+    static std::string gsmSmsCause(KGsmSmsCause, Presentation fmt = HUMAN);
+
+    static std::string q931ProgressIndication(KQ931ProgressIndication,
+        Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(2,1,0)
+    static std::string faxResult(KFaxResult code, Presentation fmt = HUMAN);
+    static std::string faxFileErrorCause(KFaxFileErrorCause code, Presentation fmt = HUMAN);
+#endif
+
+    /* end of static (class) stuff */
+
+ private:
+    static std::string internal_deviceType(KDeviceType);
+    static std::string internal_deviceModel(KDeviceType, int32);
+
+#if K3L_AT_LEAST(1,5,0)
+    static std::string internal_sipFailures(KSIP_Failures, Presentation fmt = HUMAN);
+#endif
+#if K3L_AT_LEAST(1,5,1)
+    static std::string internal_isdnCause(KQ931Cause, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(2,0,0)
+    static std::string internal_signGroupB(KSignGroupB, R2CountryType contry, Presentation fmt = HUMAN);
+    static std::string internal_signGroupII(KSignGroupII, R2CountryType contry, Presentation fmt = HUMAN);
+#else
+    static std::string internal_signGroupB(KSignGroupB, Presentation fmt = HUMAN);
+    static std::string internal_signGroupII(KSignGroupII, Presentation fmt = HUMAN);
+#endif
+
+#if K3L_AT_LEAST(1,6,0)
+    static std::string internal_gsmCallCause(KGsmCallCause, Presentation fmt = HUMAN);
+    static std::string internal_gsmMobileCause(KGsmMobileCause, Presentation fmt = HUMAN);
+    static std::string internal_gsmSmsCause(KGsmSmsCause, Presentation fmt = HUMAN);
+
+    static std::string internal_q931ProgressIndication(KQ931ProgressIndication, Presentation fmt = HUMAN);
+#endif
+
+ private:
+    enum Type
+    {
+        DEVICE,
+        CHANNEL,
+        PLAYER,
+        MIXER,
+        LINK,
+        NONE
+    };
+
+    struct Target
+    {
+        Target(Type _type)
+        : type(_type), device(-1), object(-1)
+        {};
+
+        Target(Type _type, int32 _device)
+        : type(_type), device(_device), object(-1)
+        {};
+
+        Target(Type _type, int32 _device, int32 _object)
+        : type(_type), device(_device), object(_object)
+        {};
+
+        Type  type;
+        int32 device;
+        int32 object;
+    };
+
+    static void generate(std::string &, std::string &, Target, std::string &);
+
+    static std::string show(std::string &, std::string, Target, std::string &);
+    static std::string show(std::string &, std::string, Target);
+
+    template < typename ReturnType >
+    static ReturnType presentation(Presentation fmt, ReturnType str_exact, ReturnType str_human)
+    {
+        switch (fmt)
+        {
+            case HUMAN: return str_human;
+            case EXACT: return str_exact;
+        };
+
+        return str_exact;
+    }
+};
+
+#endif /* _VERBOSE_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/docs/Manual.html b/src/mod/endpoints/mod_khomp/docs/Manual.html
new file mode 100644 (file)
index 0000000..fc63f0d
--- /dev/null
@@ -0,0 +1,1093 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Mod Khomp: Manual</title></head><body>
+<a name="Considera.C3.A7.C3.B5es_iniciais" id="Considera.C3.A7.C3.B5es_iniciais"></a><h1> <span class="mw-headline"> Considerações iniciais </span></h1>
+<p>Este documento aborda informações sobre o <i>Endpoint</i> da Khomp como um todo, desde opções disponíveis de configuração, os <i>applications</i> disponibilizados, os possíveis comandos de <b>CLI</b>, entre outros.
+</p><p>Para procedimentos sobre a instalação, favor consultar o <a href=".htmlMod_Khomp/README" title="Mod Khomp/README">README do Endpoint</a>.
+<br />
+</p>
+<a name="Configura.C3.A7.C3.A3o" id="Configura.C3.A7.C3.A3o"></a><h1> <span class="mw-headline"> Configuração </span></h1>
+<p>Configurar o Endpoint da Khomp é uma tarefa que consiste de três etapas:
+</p>
+<ul><li> Configuração das placas, através da K3L;
+</li><li> Configuração do Endpoint;
+</li><li> Configuração do FreeSWITCH.
+</li></ul>
+<p>Estas etapas são descritas mais detalhadamente abaixo.
+<br />
+</p>
+<a name="Configura.C3.A7.C3.A3o_da_API_K3L" id="Configura.C3.A7.C3.A3o_da_API_K3L"></a><h2> <span class="mw-headline"> Configuração da API K3L </span></h2>
+<p>Esta etapa é realizada de maneira semi-automatizada através do programa <b>khompwizard</b>, um assistente que configura os parâmetros básicos das placas do sistema. Esse assistente inicializa os arquivos de configuração através de informações obtidas do usuário, quando estas forem necessárias, inicializando as configurações menos utilizadas com os valores padrões.
+</p><p>Normalmente, este programa é executado automaticamente após a instalação do sistema. Entretanto, pode ser necessário executá-lo manualmente caso uma atualização esteja sendo realizada, ou se novas placas foram adicionadas no sistema após a instalação dos <i>drivers</i> da placa.
+</p><p>Caso seja necessária a configuração de parâmetros avançados da placa e/ou da sinalização, o programa <b>k3lconfig</b> permite acessar todas as configurações disponíveis de cada placa instalada. Para maiores informações sobre este programa, consulte a documentação do mesmo. Para soluções de problemas de sincronismo, consulte a seção <a href="#Solu.C3.A7.C3.A3o_de_problemas" title="">Solução de problemas</a> sobre o procedimento de configuração manual das placas.
+<br />
+</p>
+<a name="Configura.C3.A7.C3.A3o_do_Endpoint" id="Configura.C3.A7.C3.A3o_do_Endpoint"></a><h2> <span class="mw-headline"> Configuração do Endpoint </span></h2>
+<p>A configuração padrão do sistema costuma atender à maior parte das necessidades. Entretanto, as configurações do Endpoint da Khomp podem ser modificadas através do arquivo de configuração '<b>/usr/local/freeswitch/conf/autoload_configs/khomp.conf.xml'</b>.
+</p><p>A lista de opções é a seguinte:
+</p>
+<a name=".3Cchannels.3E" id=".3Cchannels.3E"></a><h4> <span class="mw-headline"> &lt;channels&gt; </span></h4>
+<p>Define as configurações gerais de todos os canais da Khomp.
+</p>
+<pre><b>Sintaxe:</b> &lt;param name="..." value="..."/&gt;
+</pre>
+<ul><li><b>auto-fax-adjustment</b>: Ativa ("yes") ou desativa ("no") o ajuste automático do canal (desabilitar o cancelador de eco e a supressão DTMF) ao detectar tom de FAX; 
+</li><li><b>auto-gain-control</b>: Ativa ("yes") ou desativa ("no") a ativação do controle automático de ganho (AGC) pelo Endpoint; 
+</li><li><b>context-digital</b>: Contexto de entrada para ligações em placas digitais (o padrão é "khomp-DD-LL", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "LL" pelo número do link, "CCC" pelo número do canal e "SSSS" pelo número serial do dispositivo); 
+</li><li><b>context-fxo</b>: Contexto de entrada para placas FXO (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo); 
+</li><li><b>context-fxo-alt</b>: Contexto de entrada alternativo para placas FXO (o padrão é vazio, no entanto quando definido, segue a mesma regra de substituição da opção <b>context-fxo</b>); 
+</li><li><b>context-fxs</b>: Contexto de entrada para placas FXS (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo); 
+</li><li><b>context-fxs-alt</b>: Contexto de entrada alternativo para placas FXS (o padrão é vazio, no entanto quando definido, segue a mesma regra de substituição da opção <b>context-fxs</b>); 
+</li><li><b>context-gsm-call</b> (ou "context-gsm"): Contexto de entrada para ligações GSM (o padrão é "khomp-DD-CC", onde "DD" será substituído no momento da ligação pelo número do dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo); 
+</li><li><b>context-gsm-call-alt</b> (ou "context-gsm-alt"): Contexto de entrada alternativo para ligações GSM (o padrão é vazio, no entanto quando definido, segue a mesma regra de substituição da opção <b>context-gsm-call</b>); 
+</li><li><b>context-gsm-sms</b>: Contexto de entrada para SMSs (o padrão é "khomp-sms-DD-CC", onde "DD" será substituído pelo número de dispositivo, "CC" pelo número do canal, e "SSSS" pelo número serial do dispositivo);
+</li><li><b>context-pr</b>: Contexto de entrada para ligações em placas KPR (o padrão é "khomp-DD-CC", onde "DD" será substituído, no momento da ligação, pelo número do dispositivo, "CC" pelo número do canal); 
+</li><li><b>disconnect-delay</b>: Define o tempo em milissegundos para realizar o processamento de um evento de desconexão, para ignorar situações onde outros equipamentos realizam o duplo atendimento para derrubar chamadas a cobrar;
+</li><li><b>echo-canceller</b>: Ativa ("yes") ou desativa ("no") o cancelamento de eco automático pelo Endpoint; 
+</li><li><b>fxo-send-pre-audio</b>: Quando ativada ("yes") libera canal de áudio sainte antes da conexão da chamada em placas KFXO (o valor padrão é "yes");
+</li><li><b>fxs-global-orig</b>: Número inicial para numeração seqüencial de ramais das placas <b>KFXS</b> que não estiverem listadas na seção <b>&lt;fxs-branches&gt;</b> (a numeração segue ordem crescente por número da placa e número do canal físico) (o padrão é "0"); 
+</li><li><b>fxs-co-dialtone</b>: Seqüências de números, separados por vírgula, que disparam um tom contínuo (de central pública) em ramais FXS (ex: "0,99" faz com que, ao discar "0" ou "99", o usuário receba o tom de linha contínuo) (o padrão é vazio);
+</li><li><b>fxs-bina</b>: Quando ativada ("yes"), ligações para ramais FXS enviarão os dígitos correspondentes ao telefone de origem em sinalização BINA DTMF (o valor padrão é "no");
+</li><li><b>input-volume</b>: Define o volume de entrada das ligações, varia de -10 a +10&nbsp;; 
+</li><li><b>kommuter-activation</b>: Define se a ativação de dispositivos kommuter encontrados no sistema será feita de forma automática ("auto"), ou de forma manual ("manual") pelo usuário, através do comando "khomp kommuter on/off"; 
+</li><li><b>kommuter-timeout</b>: Define o <i>timeout</i> (em segundos) com que os kommuters serão inicializados. Se chegarem a este <i>timeout</i> sem receberem notificação do channel, os dispositivos irão comutar para o estado "desligado". O valor mínimo é "0" , onde os links permanecerão sempre comutados no estado "ligado", e o valor máximo é "255"; 
+</li><li><b>language</b>: Define idioma para ligações nas placas Khomp; 
+</li><li><b>log-to-console</b>: Define mensagens de log que devem ser impressas na console; 
+</li><li><b>log-to-disk</b>: Define mensagens de log que devem ser salvar em disco; 
+</li><li><b>out-of-band-dtmfs</b>: Ativa ("yes") ou desativa ("no") a supressão DTMF e o envio destes out-of-band; 
+</li><li><b>output-volume</b>: Define o volume de saída das ligações, varia de -10 a +10&nbsp;; 
+</li><li><b>pulse-forwarding</b>: Ativa ("yes") ou desativa ("no") a detecção de pulsos e a conversão dos mesmos em DTMFs; 
+</li><li><b>r2-preconnect-wait</b>: Define o tempo de espera do envio da sinalização de ringback, no protocolo R2/MFC, para iniciar o envio de áudio de silêncio. Apenas utilizado quando "r2-strict-behaviour" estiver ajustado para "no"; 
+</li><li><b>r2-strict-behaviour</b>: Ativa ("yes") ou desativa ("no") o comportamento da sinalização R2/MFC conforme a norma define. O padrão é "no", e pode ser alterado para "yes" caso seja necessário receber/enviar dados precisos da sinalização do protocolo (condição de B, por exemplo); 
+</li><li><b>ringback-delay-co</b>: Define o tempo de <i>delay</i> para ativar a geração de tom de controle de chamada (<i>ringback</i>) pelo Endpoint da Khomp quando há uma indicação de <i>ringback</i>, e não há áudio sendo enviado por quem indicou a situação de controle da chamada;
+</li><li><b>ringback-delay-pbx</b>: Define o tempo de <i>delay</i> para ativar a geração de controle de chamada (<i>ringback</i>) pelo Endpoint da Khomp quando há uma indicação de <i>ringback</i>, e o áudio de controle enviado não possui nenhum tom (ou seja, está em silêncio);
+</li><li><b>suppression-delay</b>: Ativa ("yes") ou desativa ("no") o delay necessário para supressão DTMF. Se desativado ("no"), também desativa supressão de DTMFs; 
+</li><li><b>trace</b>: Define opções de depuração. Não deve ser utilizado em produção a não ser que estritamente necessário;
+</li><li><b>user-transfer-digits</b>: Define uma seqüência de dígitos DTMF para iniciar a transferencia entre o FreeSWITCH&reg; e um outro PABX (utilizando sinalização de usuário, como QSig ou FXO FLASH);
+</li></ul>
+<p><br />
+</p>
+<a name=".3Cgroups.3E" id=".3Cgroups.3E"></a><h4> <span class="mw-headline"> &lt;groups&gt; </span></h4>
+<p>Define os grupos para serem usados na alocação de canal.
+</p><p>Neste caso, as opções são usadas para definir nomes para <i>strings de alocação de canais</i>. O formato segue o padrão &lt;param name="nome grupo" value="string alocação"/&gt;, onde as <i>strings de alocação de canais</i> são as mesmas utilizadas no application bridge, e <i>nome do grupo</i> é um nome arbitrário escolhido pelo usuário. 
+</p>
+<dl><dd>Por exemplo, para definir o grupo <b>pstn</b> como os canais 0 e 5 da placa 0, deveria-se utilizar a linha:
+</dd></dl>
+<pre>&lt;param name="pstn" value="b0c0 + b0c5"/&gt; 
+</pre>
+<p>Este grupo, por sua vez, poderia ser usado no <i>application bridge</i> como <b>&lt;action application="bridge" data="Khomp/Gpstn/..."/&gt;</b>.
+</p>
+<dl><dd>Pode-se também associar um determinado contexto de entrada a um grupo de canais, bastando especificar um nome de contexto após a <i>string</i> de alocação, separado por ':' da mesma.
+</dd></dl>
+<p>Por exemplo, para definir o mesmo grupo <b>pstn</b> acima como os canais 0 até 20 da placa 0, com contexto de entrada <b>from-pstn</b>, poderia-se utilizar a linha:
+</p>
+<pre>&lt;param name="pstn" value="b0c0-20:from-pstn"/&gt;
+</pre>
+<p>Este grupo, por sua vez, poderia ser usado no <i>application bridge</i> como <b>&lt;action application="bridge" data="Khomp/Gpstn/..."/&gt;</b>, e todas as ligações vindas destes canais seriam tratadas no contexto <b>from-pstn</b>.
+<br />
+</p>
+<a name=".3Ccadences.3E" id=".3Ccadences.3E"></a><h4> <span class="mw-headline"> &lt;cadences&gt; </span></h4>
+<p>Define configurações de cadências para o Endpoint. 
+</p><p>Neste caso, as opções são nomes de cadências e um ou dois pares de números, que definem os intervalos de tom e silêncio a ser utilizado nas cadências. Para maiores detalhes, favor consultar o arquivo de configuração.
+<br />
+</p>
+<a name=".3Cfxs-branches.3E" id=".3Cfxs-branches.3E"></a><h4> <span class="mw-headline"> &lt;fxs-branches&gt; </span></h4>
+<p>Define números de origem para a placa KFXS. 
+</p><p>Neste caso, as opções são seqüências de prefixos de ramais e números seriais das placas, que definem os números base dos endereços de origem, e a ordem numérica das placas. O formato das opções é:
+</p>
+<pre>&lt;param name="prefixo" value="serial1, serial2, ...."/&gt;
+</pre>
+<p>Por exemplo, para definir que as placas K0374 e K2352 devem ser numeradas seqüencialmente, partido do ramal 200, basta escrever:
+</p>
+<pre>&lt;param name="200" value="374, 2352"/&gt;
+</pre>
+<p>Para maiores detalhes, favor consultar o arquivo de configuração.
+<br />
+</p>
+<a name=".3Cfxs-hotlines.3E" id=".3Cfxs-hotlines.3E"></a><h4> <span class="mw-headline"> &lt;fxs-hotlines&gt; </span></h4>
+<p>Define hotlines para a placa KFXS.
+</p><p>Neste caso, as opções são seqüências de ramais e números de destino, definindo os ramais listados nesta seção para serem tratados como "hotlines". Para cada ramal listado, o número de destino especificado será discado quando o ramal for retirado do gancho. Exemplo:
+</p>
+<pre>&lt;param name="100" value="1234"/&gt;
+&lt;param name="200" value="4321"/&gt; 
+</pre>
+<p>No primeiro exemplo, o ramal de número 100 irá telefonar para número 1234 ao ser retirado do gancho; no segundo, o ramal de número 200 irá telefonar para o número 4321 ao ser retirado do gancho.
+</p>
+<a name=".3Cfxs-options.3E" id=".3Cfxs-options.3E"></a><h4> <span class="mw-headline"> &lt;fxs-options&gt; </span></h4>
+<p>Permite definir configurações específicas por ramal FXS.
+</p><p>Neste caso, as configurações são números de ramais (baseado nos definidos na seção &lt;fxs-branches&gt;), e as opções e seus valores. As opções disponíveis são: 
+</p>
+<ul><li>context; 
+</li><li>input-volume; 
+</li><li>output-volume; 
+</li><li>accountcode; 
+</li><li>calleridnum; 
+</li><li>calleridname;
+</li><li>mailbox.
+</li></ul>
+<p>Cada opção é separada uma da outra por um pipe "|" ou uma barra "/" e definidas após dois pontos ":", exemplo:
+</p>
+<pre> &lt;param name="200" value="language:en|context:master-branch" /&gt;
+</pre>
+<p>Para maiores informações sobre a sintaxe e exemplos, favor consultar o arquivo de configuração.
+</p><p><br />
+</p><p>Para maiores informações, consultar o arquivo de configuração '<b>khomp.conf.xml'</b>.
+<br />
+</p>
+<a name="Configura.C3.A7.C3.A3o_do_FreeSWITCH" id="Configura.C3.A7.C3.A3o_do_FreeSWITCH"></a><h2> <span class="mw-headline"> Configuração do FreeSWITCH </span></h2>
+<p>Quando as ligações são recebidas nas placas e dispositivos Khomp, estas são encaminhadas pelo <i>Endpoint</i> da Khomp para contextos específicos dentro do plano de discagem do FreeSWITCH&reg;. Estes contextos podem ser alterados através do arquivo de configurações <b>khomp.conf.xml</b>, disponível no diretório de configuração do FreeSWITCH (por padrão, "<b>/usr/local/freeswitch/conf/autoload_configs</b>").
+</p><p>Para maiores detalhes sobre os contextos específicos, consultar a seção de <a href="#Configura.C3.A7.C3.A3o_do_Endpoint" title="">Configuração do Endpoint</a>.
+</p><p>Abaixo, encontram-se informações de como configurar os contextos de entrada de chamadas:
+<br />
+</p><p><br />
+</p>
+<a name="Contextos_de_entrada_em_canais_E1" id="Contextos_de_entrada_em_canais_E1"></a><h3> <span class="mw-headline"> Contextos de entrada em canais E1 </span></h3>
+<p>Para placas E1, as ligações de entrada por padrão chegam em um contexto pré-definido conforme a opção <b>context-digital</b>:
+</p>
+<pre>&lt;param name="context-digital" value="khomp-DD-LL"/&gt;
+</pre>
+<p>Este contexto padrão define que as ligações serão redirecionadas de acordo com o número da placa e número do <i>link</i>: <b>DD</b> é o número dispositivo (com dois dígitos), e <b>LL</b> é o número do <i>link</i> (também com dois dígitos).
+</p><p>Entretanto, é possível configurar outros contextos de entrada, com formatos diferenciados. Pode-se utilizar a opção <b>CCC</b>, que significa o número do canal na placa (com três dígitos), e <b>SSSS</b>, que representa o número serial da placa (com quatro dígitos).
+</p><p>Exemplos de configuração no arquivo <b>khomp.conf.xml</b>:
+</p>
+<pre>&lt;!-- número seqüencial da placa e do link (ex: khomp-01-00) --&gt;
+&lt;param name="context-digital" value="khomp-DD-LL"/&gt;
+</pre>
+<pre>&lt;!-- número serial da placa e seqüencial do link (ex: khomp-3049-00) --&gt;
+&lt;param name="context-digital" value="khomp-SSSS-LL"/&gt;
+</pre>
+<pre>&lt;!-- número seqüencial da placa e do canal (ex: khomp-00-001) --&gt;
+&lt;param name="context-digital" value="khomp-DD-CCC"/&gt;
+</pre>
+<pre>&lt;!-- recebe todas as chamadas em um só contexto (khomp-digital) --&gt;
+&lt;param name="context-digital" value="khomp-digital"/&gt;
+</pre>
+<p>Abaixo um exemplo de contexto no plano de discagem:
+<!-- NEED 6 -->
+</p>
+<pre>&lt;!-- 
+Este contexto presente em seu arquivo de dialplan, irá manipular chamadas
+de entrada no link 0 (primeiro link) da placa 0.
+--&gt;
+&lt;context name="khomp-00-00"&gt;
+             .
+             .
+             .
+&lt;/context&gt;
+</pre>
+<p>Outro exemplo, utilizando o mesmo formato:
+<!-- NEED 6 -->
+</p>
+<pre>&lt;!-- 
+Este contexto presente em seu arquivo de dialplan, irá manipular chamadas
+de entrada no link 1 (segundo link) da placa 0.
+--&gt;
+&lt;context name="khomp-00-01&gt;
+             .
+             .
+             .
+&lt;/context&gt;
+</pre>
+<p>Um exemplo completo, com algumas ações simples:
+<!-- NEED 10 -->
+</p>
+<pre>&lt;context name="khomp-00-00"&gt;
+    &lt;extension name="exemplo_1"&gt;
+        &lt;condition field="destination_number" expression="^1234$"&gt;
+            &lt;action application="bridge" data="Khomp/b0L1/2345"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+    &lt;extension name="exemplo_2"&gt;
+        &lt;condition field="destination_number" expression="^23(\d{2})$"&gt;
+            &lt;action application="bridge" data="sofia/${use_profile}/11$1@${sip_from_host}"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<pre>&lt;context name="khomp-00-01"&gt;
+    &lt;extension name="exemplo_3"&gt;
+        &lt;condition field="destination_number" expression="^1111$"&gt;
+            &lt;action application="bridge" data="Khomp/b0L0/2345"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<p>Este plano de discagem define o recebimento de chamadas na placa <b>0</b> e no link <b>0</b>, redirecionando chamadas para o número 1234 feitas para o link <b>1</b> da placa <b>0</b>, pro ramal/telefone <b>2345</b>, e redirecionando qualquer número de quatro dígitos começado com <b>23</b> para telefones SIP de quatro dígitos começados com <b>11</b> mais os dois últimos dígitos recebidos.
+</p><p>Também há mais uma extensão definida, onde as ligações recebidas no link <b>1</b> da placa <b>0</b> para o número <b>1111</b>, são redirecionadas para o link <b>0</b> da placa <b>0</b>, para o telefone/ramal <b>2345</b>.
+<br />
+</p>
+<a name="Contextos_de_entrada_em_canais_FXS.2FFXO.2FGSM" id="Contextos_de_entrada_em_canais_FXS.2FFXO.2FGSM"></a><h3> <span class="mw-headline"> Contextos de entrada em canais FXS/FXO/GSM </span></h3>
+<p>Da mesma forma que no contexto de placas E1, as ligações de entrada são encaminhadas pelo <i>Endpoint</i> para o FreeSWITCH. Entretanto, estas sinalizações possuem dois contextos pré-definidos, buscados com uma ordem de preferência.
+</p><p>O primeiro contexto é pré-definido da seguinte forma, conforme o arquivo <b>khomp.conf.xml</b>:
+</p>
+<pre>&lt;param name="context-gsm" value="khomp-DD-CC"/&gt;&nbsp;;placas GSM
+</pre>
+<pre>&lt;param name="context-fxs" value="khomp-DD-CC"/&gt;&nbsp;; placas FXS
+</pre>
+<pre>&lt;param name="context-fxo" value="khomp-DD-CC"/&gt;&nbsp;; placas FXO
+</pre>
+<p>Enquanto o segundo contexto possui o seguinte formato padrão:
+</p>
+<pre>&lt;param name="context-gsm-alt" value="khomp-DD"/&gt;&nbsp;; placas GSM
+</pre>
+<pre>&lt;param name="context-fxs-alt" value="khomp-DD"/&gt;&nbsp;; placas FXS
+</pre>
+<pre>&lt;param name="context-fxo-alt" value="khomp-DD"/&gt;&nbsp;; placas FXO
+</pre>
+<p>Nestes casos, <b>DD</b> é o número dispositivo (com dois dígitos), e <b>CC</b> é o número do canal da placa. Pode-se utilizar também <b>SSSS</b>, que representa o número serial da placa. 
+</p>
+<ul><li> <b>IMPORTANTE</b>: No caso da placa <b>KGSM</b>, as ligações entrantes são <b>sempre</b> encaminhadas para o <i>extension</i> <b>"s"</b> por padrão, visto que o protocolo GSM não identifica o número de destino nas ligações entrantes, apenas o número de origem - quando não omitido.
+</li></ul>
+<a name="Prioridade_de_contextos_na_placa_FXS" id="Prioridade_de_contextos_na_placa_FXS"></a><h4> <span class="mw-headline"> Prioridade de contextos na placa FXS </span></h4>
+<p>Em ligações originadas a partir de um ramal FXS, o Endpoint driver procura uma extensão válida dos dígitos discados em três contextos diferentes. A prioridade dos contextos é a seguinte:
+</p>
+<ol><li> Contexto específico do ramal, definido na seção <b>&lt;fxs-options&gt;</b> do arquivo de configuração do <b>khomp.conf.xml</b>;
+</li><li> Contexto definido na opção <b>context-fxs</b>;
+</li><li> Contexto definido na opção <b>context-fxs-alt</b>.
+</li></ol>
+<p>Caso durante a discagem, nenhuma extensão válida puder ser encontrada, a extensão <b>i</b> é procurada nos contextos em ordem de prioridade, e por fim no contexto <b>default</b>. Caso ocorra um <i>timeout</i> durante a discagem (configurável pela opção <b>fxs-digit-timeout</b>, no arquivo <b>khomp.conf.xml</b>) durante a discagem, o mesmo comportamento será aplicado - no entanto, a busca se dará inicialmente pelo número já discado até o <i>timeout</i> e, se não encontrado, a busca nos contextos será repetida para a extensão "t".
+<br />
+</p>
+<a name="Contextos_de_mensagens_SMS_.28apenas_GSM.29" id="Contextos_de_mensagens_SMS_.28apenas_GSM.29"></a><h3> <span class="mw-headline"> Contextos de mensagens SMS (apenas GSM) </span></h3>
+<p>Mensagens SMS são recebidas pelo <i>Endpoint</i> da Khomp e encaminhadas para o FreeSWITCH como uma ligação normal, mas sem áudio, que possui algumas variáveis ajustadas com informações recebidas na mensagem - para maiores informações sobre estas variáveis, consulte a documentação das variáveis do <i>Endpoint</i>. Este contexto também pode ser alterado, de mesma forma que o contextos acima.
+</p><p>Esta ligação entra no seguinte contexto, conforme o arquivo <b>khomp.conf.xml</b>:
+</p>
+<pre>&lt;param name="context-gsm-sms" value="khomp-sms-DD-CC"/&gt; 
+</pre>
+<p>Onde <b>DD</b> é o número dispositivo (com dois dígitos), e <b>CC</b> é o número do canal (também com dois dígitos). Por exemplo:
+</p>
+<pre>&lt;context name="khomp-sms-00-01"&gt;
+    &lt;extension name="sms"&gt;
+        &lt;condition field="destination_number" expression="^s$"&gt;
+            &lt;action application="log" data="DEBUG KSmsType=${KSmsType}"/&gt;
+            &lt;action application="log" data="DEBUG KSmsBody=${KSmsBody}"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<a name="Contexto_de_entrada_em_canais_Khomp_PR_.28KPR.29" id="Contexto_de_entrada_em_canais_Khomp_PR_.28KPR.29"></a><h3> <span class="mw-headline"> Contexto de entrada em canais Khomp_PR (KPR) </span></h3>
+<p>Para estas placas, as ligações de entrada possuem um contexto pré-definido, conforme exemplo abaixo:
+</p>
+<pre>&lt;param name="context-pr" value="khomp-DD-CC"/&gt; 
+</pre>
+<p>Neste caso, <b>DD</b> é o número do dispositivo (com dois dígitos), e <b>CC</b> é o número do canal da placa.
+<br />
+</p><p><br />
+<br />
+</p>
+<a name="Utiliza.C3.A7.C3.A3o_do_application_bridge" id="Utiliza.C3.A7.C3.A3o_do_application_bridge"></a><h3> <span class="mw-headline">Utilização do <i>application</i> bridge </span></h3>
+<p>O aplicativo (ou <i>application</i>) <b>bridge</b> é responsável por gerar chamadas no FreeSWITCH a partir de um <i>dialplan</i>. Este aplicativo pode ser utilizado para gerar chamadas a partir de diversos tipos de <i>Endpoints</i>, sendo que cada <i>Endpoint</i> segue um formato específico para definir tanto as opções quanto os canais de comunicações a serem utilizados.
+</p>
+<a name="Campos_relativos_ao_Endpoint" id="Campos_relativos_ao_Endpoint"></a><h4> <span class="mw-headline"> Campos relativos ao <i>Endpoint</i> </span></h4>
+<p>Quando utilizado para canais da <b>Khomp</b>, a <i>string</i> de <b>bridge</b> pode ter dois, três ou quatro campos separados por uma barra (/). Algumas <i>strings</i> de exemplo:
+<!-- NEED 11 -->
+</p>
+<pre>&lt;action application="bridge" data="Khomp/B2L0/32625644"/&gt;
+&lt;action application="bridge" data="Khomp/*B2L0/32625644"/&gt;
+&lt;action application="bridge" data="Khomp/S0411/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/Gpstn/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/*Gpstn/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/B2C58/32625644/category=4:orig=4855553232"/&gt;
+&lt;action application="bridge" data="Khomp/b0c9"/&gt;
+&lt;action application="bridge" data="Khomp/b0c1+b0c14"/&gt;
+&lt;action application="bridge" data="Khomp/r304"/&gt;
+</pre>
+<p>Nos cinco primeiros exemplos, temos três campos sendo especificados; no sexto, quatros campos são utilizados; e por fim, nos três últimos exemplos, apenas dois são utilizados.
+</p><p>Sobre os campos utilizados, segue a descrição:
+</p>
+<ul><li> <b>1° campo</b>, 'Khomp': identifica o tipo do <i>Endpoint</i> em questão;
+</li><li> <b>2° campo</b>, 'B2L0', 'S0411', 'Gpstn', etc: representa a <b>Política de Alocação de Canais</b>;
+</li><li> <b>3° campo</b>, '32625644' e '99991234': são os números de destino, para onde será efetuada a ligação (ausente em placas <b>KFXS</b>);
+</li><li> <b>4° campo</b>, 'category=4:orig=4855553232': opções adicionais não-obrigatórias, detalhadas mais à frente.
+</li></ul>
+<p>OBS: A <i>string</i> de <b>bridge</b> com somente dois campos é específica à ligações para uma placa KFXS, onde o destino está atrelado automaticamente ao canal alocado, ou ao ramal especificado.
+</p>
+<a name="Pol.C3.ADtica_de_aloca.C3.A7.C3.A3o_de_canais" id="Pol.C3.ADtica_de_aloca.C3.A7.C3.A3o_de_canais"></a><h4> <span class="mw-headline"> Política de alocação de canais </span></h4>
+<p>A política de alocação de canais, no módulo da <b>Khomp</b>, pode ser especificado na própria <i>string</i> de <i>bridge</i> ou através de grupos, no arquivo de configuração <b>khomp.conf.xml</b>. Para especificar placas, canais e links a serem alocados existe a seguinte sintaxe disponível (considerando X, Y e Z como números quaisquer):
+</p>
+<ul><li> b<b>X</b>      -- busca os canais na placa 'X', de maneira crescente.
+</li><li> b<b>X</b>L<b>Y</b>    -- busca canais no link 'Y' da placa 'X', fazendo uma procura crescente (com relação ao número dos canais).
+</li><li> b<b>X</b>c<b>Y</b>    -- utiliza apenas o canal 'Y' da placa 'X'.
+</li><li> b<b>X</b>c<b>Y</b>-<b>Z</b>  -- busca por canais, iniciando do canal 'Y' e indo até o canal 'Z' (inclusive), da placa 'X', de maneira crescente.
+</li><li> B<b>X</b>c<b>Y</b>-<b>Z</b>  -- idem ao anterior, de maneira decrescente.
+</li><li> s<b>X</b>      -- busca os canais na placa de serial 'X', de maneira crescente.
+</li><li> s<b>X</b>L<b>Y</b>    -- busca canais no link 'Y' da placa de serial 'X', fazendo uma procura crescente (com relação ao número dos canais).
+</li><li> s<b>X</b>c<b>Y</b>    -- utiliza apenas o canal 'Y' da placa de serial 'X'.
+</li><li> s<b>X</b>c<b>Y</b>-<b>Z</b>  -- busca por canais, iniciando do canal 'Y' e indo até o canal 'Z' (inclusive), da placa de serial 'X', de maneira crescente.
+</li><li> S<b>X</b>c<b>Y</b>-<b>Z</b>  -- idem ao anterior, de maneira decrescente.
+</li></ul>
+<p>Para buscar por ramais de placas <b>KFXS</b> de acordo com o número do ramal, pode ser utilizada a seguinte sintaxe (considerando X e Y números de ramais válidos):
+</p>
+<ul><li> r<b>X</b>      -- busca ramal 'X'.
+</li><li> R<b>X</b>      -- equivalente ao anterior.
+</li><li> r<b>X</b>-<b>Y</b>    -- busca de ramal 'X' a 'Y', ordem crescente.
+</li><li> R<b>X</b>-<b>Y</b>    -- busca de ramal 'X' a 'Y', ordem decrescente.
+</li></ul>
+<p>É interessante notar que apenas a capitalização da letra 'B', 'S' ou 'R' define a ordem de busca dos canais; se minúscula, crescente, e se maiúscula, decrescente.
+</p><p>Já para a alocação de canais através de grupos, existe a seguinte sintaxe disponível:
+</p>
+<ul><li> Ggroupname  -- utiliza a string de <i>bridge</i> definida ao grupo "groupname" no arquivo de configuração; já detalhado na seção de configuração do Endpoint.
+</li><li> ggroupname  -- equivalente ao anterior.
+</li></ul>
+<a name="Agrupando_aloca.C3.A7.C3.B5es_de_canais" id="Agrupando_aloca.C3.A7.C3.B5es_de_canais"></a><h4> <span class="mw-headline"> Agrupando alocações de canais  </span></h4>
+<p>Existem casos onde é necessário buscar canais mais de um determinado dispositivo, ou determinado grupo de ramais. Para isto, existe uma extensão disponível na string de alocação, que diz respeito ao uso do símbolo de soma (<b>+</b>) para concatenar várias <i>strings</i> de ligação, da seguinte forma: <!-- NEED 6 --> 
+</p>
+<pre>&lt;action application="bridge" data="Khomp/B1L0+B2L0/32332933"/&gt;
+&lt;action application="bridge" data="Khomp/*B2+B3+B4/99887766"/&gt;
+&lt;action application="bridge" data="Khomp/S0411+B1L0/99887766"/&gt;
+&lt;action application="bridge" data="Khomp/Gpstn1+Gpstn2/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/*gOperadora1+gOperadora2/98891234"/&gt;
+</pre>
+<p>Esta extensão está disponível tanto no <i>application</i> <b>bridge</b> quanto na especificação de grupos, e pode ser utilizada para agrupar qualquer <i>string</i> de alocação válida à outra. O processamento das <i>strings</i> de alocação se dá da esquerda para a direita - exceto quanto utilizando a alocação cíclica, onde <b>todos</b> os canais especificados são verificados simultaneamente.
+</p>
+<a name="Escolha_c.C3.ADclica_e.2Fou_justa" id="Escolha_c.C3.ADclica_e.2Fou_justa"></a><h4> <span class="mw-headline"> Escolha cíclica e/ou <i>justa</i>  </span></h4>
+<p>Uma variação da alocação de canais é através de uma escolha cíclica e/ou <i>justa</i>, que consiste em escolher o canal que <b>completou</b> - até o momento - o menor número de ligações <b>saintes</b>. Essa forma é caracterizada por um asterisco (<b>*</b>) antes da string de alocação de canais (conforme pode ser verificado acima, no segundo e quinto exemplos). 
+</p><p>Quando iniciada com um asterisco (<b>*</b>), as outras formas de alocação subseqüentes (crescente, decrescente, etc) são utilizadas para decidir, entre os canais com menor número de ligações saintes, qual será verificado primeiro para realizar a chamada. 
+</p>
+<ul><li><b>AVISO: O uso da alocação justa e/ou cíclica é recomendável <u>somente</u> em placas analógicas (KFXO), de ramais (KFXS) e de interface celular (KGSM)</b>. Conexões E1 tendem a alocar os canais de maneira crescente ou decrescente de um lado (na operadora, por exemplo), e o inverso do outro (no PABX, por exemplo), para evitar problemas de dupla ocupação (o que pode ocorrer na sinalização R2/MFC). A alocação cíclica/justa também consome mais recursos de memória e processamento que a alocação tradicional, o que é agravado ainda mais pelo fato de placas E1 terem um número muito maior de canais (30 por link).<br /><br />Por estes motivos, alocações justas e/ou cíclicas devem ser utilizadas apenas em sinalizações onde isso pode representar alguma diferença real, como equalizar a tarifação das linhas, o uso das mesmas, ou o número de ligações recebidas por cada ponto de atendimento (PA).
+</li></ul>
+<a name="Op.C3.A7.C3.B5es_dispon.C3.ADves" id="Op.C3.A7.C3.B5es_dispon.C3.ADves"></a><h4> <span class="mw-headline"> Opções disponíves </span></h4>
+<ul><li><b>orig</b>: Define o número de origem a ser utilizado na chamada, <b>sem alterar a variável ${origination_caller_id_number}</b>. Ou seja, a opção <b>orig</b> serve <b>apenas</b> para repassar um número de origem diferente do ${origination_caller_id_number}. Caso o FreeSWITCH já tenha ajustado a variável ${origination_caller_id_number}, o que é o comportamento padrão, o Endpoint utiliza este valor automaticamente como referência do número de origem, sem ser necessário repassar nenhuma opção adicional.<br /><br />Nas placas <b>KGSM</b>, se ajustado para <b>restricted</b>, omite o número de origem. Exemplo:<br />
+</li></ul>
+<pre>
+ &lt;action application=&quot;bridge&quot; data=&quot;Khomp/b0/99887766/orig=restricted&quot;/&gt;
+</pre>
+<ul><li><b>category</b>: Quando ajustado para um valor numérico, define a categoria do número de A. Disponível apenas em sinalização R2/MFC; 
+</li><li><b>uui</b>: Quando ajustado para um número e uma string de texto, separados por cerquilha ("#"), envia uma mensagem "User-to-User" para a outra ponta, antes de realizar a chamada, utilizando o descritor como o número e a mensagem como o texto. Disponível apenas em sinalização RDSI (ISDN); 
+</li><li><b>ring_cadence</b>: Quando ajustado para um identificador, utiliza cadência definida com este nome na seção "cadences" do arquivo de configuração do Endpoint da Khomp para chamar o canal desejado. Disponível apenas em sinalização FXS; 
+</li><li><b>ring</b>: Quando ajustado para dois números, separados por ponto ("."), define as cadências de chamada de um ramal FXS para estes valores, sendo o primeiro relativo ao tempo de chamando, e o segundo, ao tempo de silêncio; 
+</li><li><b>ring_ext</b>: Quando ajustado para dois números, separados por ponto ("."), define as cadências de chamada extendidas (a serem executadas depois da cadência principal) de um ramal FXS para estes valores, sendo o primeiro relativo ao tempo de chamando, e o segundo, ao tempo de silêncio; 
+</li><li><b>usr_xfer</b>: Quando ajustado para uma seqüência de dígitos DTMF, define estes como dígitos a serem utilizados para iniciar uma transferência entre PABXes (utilizando sinalizações de usuário); 
+</li><li><b>drop_on</b>: Quando ajustado para "message_box", "human_answer", "answering_machine", "carrier_message", "unknown" ou uma lista destes (separados por mais ("+") ou ponto (".")), faz com que a chamada seja derrubada ao detectar tons de caixa postal, atendimento humano, secretária eletrônica, mensagens da operadora, ou algum atendimento desconhecido - respectivamente. Disponível em sinalizações digitais (links E1 e placas KGSM). Adicionalmente, a informação de atendimento é reportada para o usuário na variável KCallAnswerInfo; 
+</li><li><b>answer_info</b>: Opção booleana (não necessita de valor). Quando especificada, reporta informações de atendimento para o usuário através da variável KCallAnswerInfo; 
+</li><li><b>pre</b>: Quando ajustado para uma seqüência de dígitos DTMF, utiliza estes para pre-alocar um canal de saída em um PABX analógico, discando o número de B desejado a seguir. Somente disponível para sinalização analógica (FXO);
+</li><li><b>pre_answer</b>: Opção booleana (não necessita de valor). Quando especificada, "antende" o canal antes de a ligação ser completada permitindo, por exemplo, que DTMFs possam ser enviados - útil para utilizar em um <b>DISA</b>;
+</li><li><b>output_volume</b>: Define o volume de saída da ligação. Varia de -10 a +10;
+</li><li><b>input_volume</b>: Define o volume de entrada da ligação. Varia de -10 a +10;
+</li></ul>
+<p><br />
+</p>
+<a name="Lista_das_vari.C3.A1veis" id="Lista_das_vari.C3.A1veis"></a><h3> <span class="mw-headline"> Lista das variáveis </span></h3>
+<p>Segue lista de variáveis disponíveis no Endpoint:
+</p>
+<ul><li><b>KDropCollectCall</b>: Quando definida antes do atendimento (ao receber uma chamada), ativa ("yes") ou desativa ("no", padrão) o derrubamento de chamadas à cobrar baseado na sinalização recebida da central pública; através do duplo atendimento; ou através do reconhecimento por áudio de uma chamada à cobrar (pode ser definido de maneira global);
+</li><li><b>KR2SendCondition</b>: Quando definida antes do envio de ringback pelo FreeSWITCH (ao receber uma chamada), ajusta a condição de B para o valor numérico que foi ajustada. Apenas disponível para sinalização R2; 
+</li><li><b>KR2GotCategory</b>: Ajustada pelo Endpoint ao receber uma chamada entrante, e possui a categoria do número de A. Apenas disponível para sinalização R2; 
+</li><li><b>KR2GotCondition</b>: Ajustada pelo Endpoint, e disponível após o retorno de uma chamada realizada pelo FreeSWITCH. Contém a condição de B recebida ao realizar a chamada. Apenas disponível para sinalização R2;
+</li><li><b>KISDNGotCause</b>: Ajustada pelo Endpoint, e disponível após o retorno de uma chamada realizada pelo FreeSWITCH. Contém o código de <i>cause</i> do ISDN recebido ao realizar a chamada. Apenas disponível para sinalização ISDN;
+</li><li><b>KCallAnswerInfo</b>: Ajustada pelo Endpoint, e disponível após o retorno de uma chamada realizada pelo FreeSWITCH. Contém as informações de atendimento detectadas ao realizar a chamada e está disponível apenas para sinalizações digitais (E1, GSM);
+</li><li><b>KSmsDelivered</b>: Ajustada pelo Endpoint ao enviar uma mensagem SMS com o <i>application</i> <b>KSendSMS</b>, e define se a mensagem foi entregue com sucesso ("yes") ou não ("no"); 
+</li><li><b>KSmsErrorCode</b>: Ajustada pelo Endpoint ao enviar uma mensagem SMS com o <i>application</i> <b>KSendSMS</b>, e define o código de erro ao enviar a mensagem; 
+</li><li><b>KSmsErrorName</b>: Ajustada pelo Endpoint ao enviar uma mensagem SMS com o <i>application</i> <b>KSendSMS</b>, contém o nome do erro em forma textual, ou "None" caso não tenha ocorrido nenhum erro.
+</li><li><b>KSmsType</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, define o tipo da mensagem recebida (pode conter os valores "message", "confirm" ou "broadcast"; 
+</li><li><b>KSmsFrom</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, define o número de origem da mensagem recebida (disponível em tipos "message" e "confirm"); 
+</li><li><b>KSmsDate</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, define a data de envio da mensagem (disponível em tipos "message" e "confirm"); 
+</li><li><b>KSmsSize</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o tamanho (em bytes) da mensagem recebida (disponível em tipos "message" e "broadcast"); 
+</li><li><b>KSmsMode</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o tipo codificação da mensagem recebida (disponível em tipos "message" e "broadcast"); 
+</li><li><b>KSmsBody</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o texto da mensagem recebida (disponível em tipos "message" e "broadcast");
+</li><li><b>KSmsDelivery</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém a data de entrega de mensagem enviada anteriormente cuja confirmação foi requisitada (disponível no tipo "confirm");
+</li><li><b>KSmsStatus</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o <i>status</i> de envio de mensagem anteriormente cuja confirmação foi requisitada (disponível no tipo "confirm");
+</li><li><b>KSmsSerial</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o número de série da mensagem recebida (disponível no tipo "broadcast");
+</li><li><b>KSmsPage</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o número da página relativo à mensagem recebida (disponível no tipo "broadcast");
+</li><li><b>KSmsPages</b>: Ajustada pelo Endpoint no contexto de entrada das mensagens SMS, contém o número total de páginas a serem recebidas (disponível no tipo "broadcast");
+</li><li><b>KUserInfoDescriptor</b>: Define/informa descritor do protoloco utilizado na mensagem User-to-User Information (RDSI). 
+</li><li><b>KUserInfoData</b>: Define/informa os dados na mensagem User-to-User Information (RDSI).
+</li><li><b>KFaxSent</b>: Ajustada pelo Endpoint ao enviar FAX com o application KSendFax, e define se o FAX foi enviado com sucesso ("yes") ou não ("no"); 
+</li><li><b>KFaxReceived</b>: Ajustada pelo Endpoint ao receber FAX com o application KReceiveFax, e define se o FAX foi recebido com sucesso ("yes") ou não ("no"); 
+</li><li><b>KFaxResult</b>: Ajustada pelo Endpoint ao enviar ou receber FAX com o application KSendFax ou KReceiveFax, respectivamente, e define o seu resultado.
+</li></ul>
+<p><br />
+</p>
+<a name="Descri.C3.A7.C3.A3o_das_vari.C3.A1veis" id="Descri.C3.A7.C3.A3o_das_vari.C3.A1veis"></a><h3> <span class="mw-headline"> Descrição das variáveis </span></h3>
+<p>Abaixo, segue uma explanação sobre como utilizar as variáveis do Endpoint da Khomp disponíveis no dialplan, tanto para comunicar quanto para receber informações: 
+</p><p><br />
+</p>
+<a name="KDropCollectCall" id="KDropCollectCall"></a><h4> <span class="mw-headline"> KDropCollectCall </span></h4>
+<p>Quando ativada, faz com que o Endpoint da Khomp derrube chamadas a cobrar através de duplo atendimento (disponível para sinalizações 'R2 Digital' e FXO), através da informação disponível no protocolo RDSI e R2/MFC, ou através da detecção do áudio de chamada a cobrar (disponível para qualquer sinalização digital por link E1, e para sinalização GSM).
+</p><p>Esta variável é útil para derrubar chamadas a cobrar para determinados ramais, e deve ser ajustado <b>obrigatoriamente</b> antes de realizar qualquer tipo de atendimento - aplicações como <b>playback</b> e <b>bridge</b> devem ser executadas sempre após ajustar esta variável, por exemplo.
+</p><p>Para melhor funcionalidade, é recomendado também que nenhum estado de chamada (<i>ringback</i>) seja enviado antes desta variável ser ajustada, então aplicações devem ser executadas apenas após o ajuste correto desta variável.
+</p><p>Esta variável pode ser ajustada localmente e globalmente, tanto para <b>yes</b> quanto para <b>no</b>. O ajuste da variável global para <b>yes</b> fará com que todas as chamadas a cobrar sejam derrubadas, a não ser que a chamada específica seja ajustada para <b>no</b> - isto permite a criação de um filtro global de chamadas a cobrar, com algumas poucas exceções.
+</p><p>Ativando a variável dentro do contexto <b>default</b>:
+<!-- NEED 5 --> 
+</p><p>&lt;context name="default"&gt;
+</p>
+<pre>&lt;extension name="exemplo"&gt;
+ .
+ .
+ .
+ &lt;action aplication="set" data="KDropCollectCall=yes"/&gt;
+ .
+ .
+ .
+&lt;/extension&gt;
+</pre>
+<p>&lt;/context&gt;
+</p><p>Ativando a variável no contexto global, lembrando que a mesma deve ser configurada no arquivo <b>vars.xml</b>:
+<!-- NEED 5 --> 
+</p>
+<pre>&lt;X-PRE-PROCESS cmd="set" data="KDropCollectCall=yes"/&gt;
+</pre>
+<a name="KR2SendCondition" id="KR2SendCondition"></a><h4> <span class="mw-headline"> KR2SendCondition </span></h4>
+<p>Ao receber uma chamada, pode ser definida antes do envio de ringback pelo FreeSWITCH (ou seja, antes do FreeSWITCH executar as aplicações answer, ou bridge). Quando utilizada em sinalização R2/MFC, esta variável ajusta a condição de B para o valor numérico desejado. 
+</p><p>Exemplo:
+<!-- NEED 6 --> 
+</p>
+<pre>&lt;!-- Condição "NUMBER CHANGED", avisa ao chamador que o número de B mudou. --&gt;
+&lt;action application="KR2SendCondition" data="3"/&gt;
+</pre>
+<a name="KR2GotCategory" id="KR2GotCategory"></a><h4> <span class="mw-headline"> KR2GotCategory </span></h4>
+<p>Ao receber uma chamada, é ajustada pelo Endpoint com a categoria recebida do número que originou a chamada. É ajustada na sinalização R2/MFC, e pode ser consultada em qualquer local do dialplan. 
+</p><p>Exemplo:
+<!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KR2GotCategory [${KR2GotCategory}]"/&gt; 
+</pre>
+<a name="KR2GotCondition" id="KR2GotCondition"></a><h4> <span class="mw-headline"> KR2GotCondition </span></h4>
+<p>Variável ajustada pelo Endpoint, e disponível após o retorno de uma chamada realizada pelo FreeSWITCH. Contém a condição de B recebida ao realizar a chamada. Disponível apenas para sinalização R2/MFC. 
+</p><p>Exemplo:
+<!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KR2GotCondition [${KR2GotCondition}]"/&gt;
+</pre>
+<a name="KUserInfoDescriptor" id="KUserInfoDescriptor"></a><h4> <span class="mw-headline"> KUserInfoDescriptor </span></h4>
+<p>Variável ajustada pelo Endpoint no contexto de entrada, a partir de informações recebidas pela rede RDSI através da funcionalidade User-to-User Information. Contém o número do descritor do protocolo utilizado pela outra ponta, e normalmente contém valor '0', mas este valor é dependente da aplicação utilizada. 
+</p><p>Maiores informações, consultar a especificação ITU-T Q931 (mais precisamente, a tabela 4-26 da especificação). 
+</p><p>Exemplo (trabalhando com o número do descritor do protocolo): <!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KUserInfoDescriptor [${KUserInfoDescriptor}]"/&gt;
+</pre>
+<a name="KUserInfoData" id="KUserInfoData"></a><h4> <span class="mw-headline"> KUserInfoData </span></h4>
+<p>Variável ajustada pelo Endpoint no contexto de entrada, a partir de informações recebidas pela rede RDSI através da funcionalidade User-to-User Information. Contém os dados propriamente ditos, que foram recebidos, em forma de uma 'string' de texto. 
+</p><p>Maiores informações sobre este recurso, consultar a especificação ITU-T Q931. 
+</p><p>Exemplo (trabalhando com os dados recebidos): <!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KUserInfoData [${KUserInfoData}]"/&gt;
+</pre>
+<p>É importante salientar que as variáveis são sensíveis à capitalização das letras (case sensitive).
+</p>
+<a name="KCallAnswerInfo" id="KCallAnswerInfo"></a><h4> <span class="mw-headline"> KCallAnswerInfo </span></h4>
+<p>Variável ajustada pelo Endpoint em ligações de saída, representando o tipo de atendimento realizado pela outra ponta. Pode conter os seguintes valores:
+</p>
+<dl><dd><ul><li> "MessageBox" (*): detectada caixa postal de um telefone celular;
+</li><li> "CarrierMessage": mensagem de operadora enviada antes do atendimento;
+</li><li> "AnsweringMachine" (**): atendimento por secretária eletrônica;
+</li><li> "HumanAnswer" (**): atendimento humano;
+</li><li> "Unknown": tipo de atendimento desconhecido;
+</li><li> "Fax": reportado quando um tom de fax for detectado.
+</li></ul>
+</dd></dl>
+<p><br />
+(*) Este tipo de atendimento é detectado por sinais em determinadas freqüências que são enviados antes da chamada entrar em uma caixa postal, e variam conforme a operadora. O algoritmo captura a maior parte das caixas postais, mas pode falhar se não existir um sinal claro, ou se o mesmo não estiver dentro dos padrões mais utilizados;
+</p><p>(**) A diferenciação entre estes dois tipos de atendimento depende de configuração específica utilizando o programa <b>k3lanswerinfoconfig</b>, sendo a detecção apenas baseada em heurísticas e <b>nunca</b> com precisão de 100%.
+<br />
+</p>
+<a name="Comandos_de_console" id="Comandos_de_console"></a><h1> <span class="mw-headline">Comandos de console </span></h1>
+<p>Lista de comandos disponíveis no console do FreeSWITCH para o Endpoint da Khomp:
+</p><p><br />
+</p>
+<ul><li> <b>khomp channels disconnect </b>: Desconecta um ou vários canais. Este comando envia uma mensagem diretamente para o canal físico da placa em questão, requisitando a desconexão. Use com cautela; 
+</li><li> <b>khomp channels unblock </b>: Desbloqueia canais bloqueados para entrada ou para saída. Somente disponível em sinalização digital via link E1; 
+</li><li> <b>khomp clear links</b>: Limpa os contadores de erros nos links;
+</li><li> <b>khomp clear statistics</b>: Limpa as estatísticas de ligações dos canais, ou as estatísticas de um canal específico; 
+</li><li> <b>khomp get </b>: Obtém as opções diversas do Endpoint da Khomp;
+</li><li> <b>khomp kommuter </b>: Ativa ou desativa os kommuters ligados via USB nesta máquina. Somente acessível quando a configuração "kommuter-activation" estiver setada como "manual";
+</li><li> <b>khomp kommuter count</b>: Obtém a quantidade de kommuters ligados via USB nesta máquina;
+</li><li> <b>khomp log console</b>: Ajusta opções de logs no console. 
+</li><li> <b>khomp log disk</b>:&nbsp;: Ajusta opções de log em disco. 
+<ul><li> <b>khomp log console</b> e <b>khomp log disk</b> dispõem de opções auxiliares <b>no</b>, que inverte a escolha de mensagens, e <b>just</b>, que generaliza a escolha. Exemplos:
+<ul><li> <b>khomp log disk just commands events</b> (Habilita <i>somente</i> o registro de comandos e eventos da API em disco).
+</li><li> <b>khomp log disk no commands</b> (Desabilita o registro em disco de comandos enviados à API).
+</li><li> <b>khomp log disk warnings</b> (Habilita <i>também</i> o registro em disco dos avisos do Endpoint).
+</li></ul>
+</li><li> Mais informações sobre as opções de <i>log</i> nos comando "<b>help khomp log disk</b>" ou "<b>help khomp log console</b>".
+</li></ul>
+</li><li> <b>khomp log rotate</b>: Rotaciona arquivos de log do Endpoint;
+</li><li> <b>khomp log status</b>: Mostra mensagens de log atualmente sendo escritas em disco e mostradas no console;
+</li><li> <b>khomp log trace isdn</b>: Ativa a depuração da sinalização RDSI (ISDN);
+</li><li> <b>khomp log trace k3l </b>: Ativa a depuração de baixo nível da API K3L;
+</li><li> <b>khomp log trace r2 </b>: Ativa a depuração de baixo nível da sinalização R2/MFC;
+</li><li> <b>khomp reset links</b>: Envia um comando de reset para um determinado link E1 de uma determinada placa; 
+</li><li> <b>khomp revision</b>: Mostra número da versão e revisão do Endpoint;
+</li><li> <b>khomp select sim</b>: Seleciona o SIM card, disponível nas placas KGSM;
+</li><li> <b>khomp send command </b>: Envia comando da API K3L diretamente para a placa. Apenas para depuração de problemas, pode compromenter a estabilidade do sistema se utilizado de maneira incorreta;
+</li><li> <b>khomp send raw command </b>: Envia um comando diretamente para o DSP da placa. Apenas para depuração de problemas, pode compromenter a estabilidade do sistema se utilizado de maneira incorreta;
+</li><li> <b>khomp set </b>: Ajusta opções diversas do Endpoint da Khomp;
+</li><li> <b>khomp show calls </b>: Mostra estados das chamadas Khomp, podendo listar também por placa ou canal específico;
+</li><li> <b>khomp show channels </b>: Mostra o estado dos canais Khomp, podendo listar também por placa específica; 
+</li><li> <b>khomp show links</b>: Mostra estados dos links E1 disponíveis. 
+</li><li> <b>khomp show statistics </b>: Mostra as estatísticas de ligações dos canais, ou as estatísticas de um canal específico; 
+</li><li> <b>khomp sms </b>: Envia uma mensagem SMS utilizando canais da placa KGSM para um determinado número;
+</li><li> <b>khomp summary </b>:Imprime um sumário das placas do sistema e de suas características;
+</li></ul>
+<p><br />
+</p>
+<a name="Recursos_adicionais" id="Recursos_adicionais"></a><h1> <span class="mw-headline">Recursos adicionais </span></h1>
+<p>Este capítulo trata de recursos adicionais do Endpoint, relacionados às funcionalidades especiais presentes em algumas sinalizações.
+<br />
+</p>
+<a name="Aplica.C3.A7.C3.B5es_.28applications.29_e_canais" id="Aplica.C3.A7.C3.B5es_.28applications.29_e_canais"></a><h2> <span class="mw-headline">Aplicações (applications) e canais  </span></h2>
+<p>O Endpoint da Khomp, além de registrar um tipo de canal de comunicação "Khomp", registra também os seguintes itens: 
+<br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KUserTransfer.22" id="Aplica.C3.A7.C3.A3o_.22KUserTransfer.22"></a><h3> <span class="mw-headline">Aplicação "KUserTransfer"  </span></h3>
+<p>Realiza o processo de transferência do canal atual para o ramal <i>número'</i> utilizando o protocolo de sinalização QSig (Single Step Call Transfer) para placas E1 configuradas com sinalização RDSI (ISDN), ou utiliza comando de FLASH para linhas FXO, LineSide, CAS_EL7 e E1LC.
+</p><p>A sintaxe segue: 
+</p>
+<pre>&lt;action application="KUserTransfer" data="<b>número</b>[,opções])"/&gt;
+</pre>
+<p>Exemplo: 
+</p>
+<pre>&lt;action application="answer"/&gt;
+&lt;action application="KUserTransfer" data="2345"/&gt;
+</pre>
+<p>Os campos têm o seguinte significado:
+</p>
+<ul><li><b>número</b>: Número para onde a ligação deve ser transferida.
+</li><li><b>opções</b>: Define as opções de transferência a utilizar, que são: 
+<ul><li><b>n</b>: Aguarda até o canal ser desconectado.
+</li></ul>
+</li></ul>
+<p><br />
+</p><p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KSendSMS.22" id="Aplica.C3.A7.C3.A3o_.22KSendSMS.22"></a><h3> <span class="mw-headline">Aplicação "KSendSMS"  </span></h3>
+<p>Esta aplicação tem a função de enviar mensagens SMS através das placas KGSM da Khomp, utilizando os módulos e SIM cards presentes na placa para tal. A sintaxe da aplicação é a seguinte: 
+</p>
+<pre>&lt;action application="KSendSMS" data="recurso|destino|mensagem" /&gt;
+</pre>
+<p>Podendo cada campo ser resumido em: 
+</p>
+<ul><li><b>recurso</b>: Segue uma sintaxe idêntica à alocação de canais do application Bridge, e define qual modem utilizar; 
+</li><li><b>destino</b>: Número para onde enviar a mensagem, podendo ser precedido ou sucedido por <b>!</b> para requisitar uma mensagem de confirmação de envio; 
+</li><li><b>mensagem</b>: Texto (sem aspas) que deve ser enviado para <b>destino</b>.
+</li></ul>
+<p>Após o envio da mensagem, as variáveis <b>KSmsDelivered</b> e <b>KSmsErrorCode</b> conterão o resultado do envio da mensagem. Para maiores informações sobre estas, favor consultar a seção sobre as variáveis utilizadas no Endpoint.
+</p><p>Exemplos de uso desta aplicação seguem abaixo: 
+</p>
+<ul><li>Envia "Mensagem de teste." para telefone "99887766" utilizando o modem "1" (segundo modem) da placa "0":
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Enviando SMS..." /&gt;
+&lt;action application="KSendSMS" data="b0c1|99887766|Mensagem de teste" /&gt;
+</pre>
+<ul><li>Envia "Mensagem de teste." para telefone "99887766" utilizando o primeiro modem livre da placa "0", e verifica retorno do envio:
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Enviando SMS..." /&gt;
+&lt;action application="KSendSMS" data="b0|99887766|Mensagem de teste" /&gt;
+&lt;action application="log" data="DEBUG Enviou? ${KSmsDelivered}" /&gt;
+&lt;action application="log" data="DEBUG Codigo: ${KSmsErrorCode}" /&gt;
+&lt;action application="log" data="DEBUG Descr.: ${KSmsErrorName}" /&gt;
+</pre>
+<ul><li>Envia "Mensagem de teste." para telefone "99887766" utilizando o primeiro modem livre da placa "0", ou para o primeiro canal livre da placa "1" (se não houver canal livre na primeira placa):
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Enviando SMS..." /&gt;
+&lt;action application="KSendSMS" data="b0+b1|99887766|Mensagem de teste" /&gt;
+</pre>
+<ul><li>Envia "Mensagem de teste." para telefone "99887766" utilizando o primeiro modem livre da placa "0", requisitando confirmação:
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Enviando SMS..." /&gt;
+&lt;action application="KSendSMS" data="b0|99887766!|Mensagem de teste" /&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KEchoCanceller.22" id="Aplica.C3.A7.C3.A3o_.22KEchoCanceller.22"></a><h3> <span class="mw-headline"> Aplicação "KEchoCanceller"  </span></h3>
+<p>Esta aplicação tem a função de habilitar ou desabilitar o cancelador de eco do canal.
+</p>
+<pre>&lt;action application="KEchoCanceller" data="<b>ação</b>[,opções])"/&gt;
+</pre>
+<p>Onde:
+</p>
+<ul><li><b>ação</b>: Pode ser <b>on</b> para habilitar o cancelador de eco, e <b>off</b> para desabilitar;
+</li></ul>
+<p>Exemplo de uso desta aplicação:
+</p>
+<pre>&lt;action application="KEchoCanceller" data="off"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KAutoGainControl.22" id="Aplica.C3.A7.C3.A3o_.22KAutoGainControl.22"></a><h3> <span class="mw-headline"> Aplicação "KAutoGainControl"  </span></h3>
+<p>Esta aplicação tem a função de habilitar ou desabilitar o controle automático de ganho no canal.
+</p>
+<pre>&lt;action application="KAutoGainControl" data="<b>ação</b>[,opções])"/&gt;
+</pre>
+<p>Onde: 
+</p>
+<ul><li><b>ação</b>: Pode ser <b>on</b> para habilitar o controle automático de ganho, e <b>off</b> para desabilitar;
+</li></ul>
+<p>Exemplo de uso desta aplicação: 
+</p>
+<pre>&lt;action application="KAutoGainControl" data="on"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KDTMFSuppression.22" id="Aplica.C3.A7.C3.A3o_.22KDTMFSuppression.22"></a><h3> <span class="mw-headline"> Aplicação "KDTMFSuppression"  </span></h3>
+<p>Esta aplicação tem a função de habilitar ou desabilitar a supressão de DTMF do canal. A sintaxe da aplicação é a seguinte: 
+</p>
+<pre>&lt;action applicatin="KDTMFSuppression" value="<b>ação</b>[,opções])"/&gt;
+</pre>
+<p>Onde: 
+</p>
+<ul><li><b>ação</b>: Pode ser <b>on</b> para habilitar a supressão DTMF, e <b>off</b> para desabilitar;
+</li></ul>
+<p>É importante notar que quando desabilitada a supressão de DTMF, os DTMFs serão passados <i>inband</i> e não serão mais reportados ao FreeSWITCH. Dessa forma o FreeSWITCH não reconhecerá os DTMFs, o que pode ocasionar em mau funcionamento de aplicações como por exemplo, URAs. 
+</p><p>Exemplo de uso desta aplicação: 
+</p>
+<pre>&lt;action applicatin="KDTMFSuppression" value="off"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KSetVolume.22" id="Aplica.C3.A7.C3.A3o_.22KSetVolume.22"></a><h3> <span class="mw-headline"> Aplicação "KSetVolume"  </span></h3>
+<p>Esta aplicação tem a função de ajustar o volume de entrade e saída de canais da Khomp, sendo a sua sintaxe a seguinte:
+</p>
+<pre>&lt;action application="KSetVolume" data="&lt;volume&gt;"/&gt;
+&lt;action application="KSetVolume" data="&lt;output-volume&gt;|&lt;input-volume&gt;"/&gt;
+</pre>
+<p>Onde os campos possuem o seguinte significado: 
+</p>
+<ul><li><b>volume</b>: Ajusta o volume de entrada e saída (-10 a +10);
+</li><li><b>output-volume</b>: Ajusta o volume de saída (-10 a +10, "none" para não alterar);
+</li><li><b>input-volume</b>: Ajusta o volume de entrada (-10 a +10, "none" para não alterar).
+</li></ul>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KAdjustForFax.22" id="Aplica.C3.A7.C3.A3o_.22KAdjustForFax.22"></a><h3> <span class="mw-headline"> Aplicação "KAdjustForFax"  </span></h3>
+<p>Esta aplicação tem a função de ajustar um canal da Khomp para o recebimento de sinal de FAX/modem, otimizando o canal de comunicação para o tráfego de dados. Sintaxe:
+</p>
+<pre>&lt;action application="KAdjustForFax" data=""/&gt;
+</pre>
+<p>Esta aplicação não recebe parâmetros. Exemplo de utilização:
+</p>
+<pre>&lt;action application="KAdjustForFax" data=""/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KSendFax.22" id="Aplica.C3.A7.C3.A3o_.22KSendFax.22"></a><h3> <span class="mw-headline"> Aplicação "KSendFax"  </span></h3>
+<p>Esta aplicação tem a função de enviar fax utilizando canais digitais ou FXO da Khomp em ligações pré-estabelecidas, sendo a sua sintaxe a seguinte:
+</p>
+<pre>&lt;action application="KSendFax" data="&lt;arquivo&gt;[:&lt;arquivo2&gt;[:...]][|&lt;faxid&gt;]"/&gt;
+</pre>
+<p><strong>Esta aplicação necessita de uma licença adquirida à parte para ser utilizada em canais digitais</strong>. Os campos possuem os seguintes significados: 
+</p>
+<ul><li><b>arquivos</b>: Arquivos a serem enviados para o fax devem estar encapsulados no formato TIFF e possuírem resolução de 98, 196 ou 392 dpi;
+</li><li><b>faxid</b>: Número do fax. Caso não seja especificado, o valor será obtido pela id da ligação, e caso esta, também não seja válida, o número do fax será o configurado como padrão na K3L.
+</li></ul>
+<p>Exemplo de uso desta aplicação: 
+</p>
+<pre>&lt;action application="KSendFax" data="/tmp/fax.tif:/home/root/fax2.tif,1234"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Aplica.C3.A7.C3.A3o_.22KReceiveFax.22" id="Aplica.C3.A7.C3.A3o_.22KReceiveFax.22"></a><h3> <span class="mw-headline"> Aplicação "KReceiveFax"  </span></h3>
+<p>Esta aplicação tem a função de receber fax utilizando canais digitais ou FXO da Khomp, sendo a sua sintaxe a seguinte:
+</p>
+<pre>&lt;action application="KReceiveFax" data="&lt;arquivo&gt;[|&lt;faxid&gt;]/&gt;
+</pre>
+<p><strong>Esta aplicação necessita de uma licença adquirida à parte para ser utilizada em canais digitais</strong>. Os campos possuem os seguintes significados:
+</p>
+<ul><li><b>arquivo</b>: Nome que será atribuído ao arquivo de fax recebido.
+</li><li><b>faxid</b>: Número do fax. Caso não seja especificado, o valor será obtido pela id da ligação, e caso esta, também não seja válida, o número do fax será o configurado como padrão na K3L.
+</li></ul>
+<p>Exemplo de uso desta aplicação: 
+</p>
+<pre>&lt;action application="answer" /&gt;
+&lt;action application="KReceiveFax" data="/tmp/fax.tif"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Canal_.22Khomp_SMS.22" id="Canal_.22Khomp_SMS.22"></a><h3> <span class="mw-headline"> Canal "Khomp_SMS"  </span></h3>
+<p>Este canal de comunicação é utilizado para receber mensagens SMS e criar ligações entrantes no FreeSWITCH para cada mensagem recebida. Este canal não possui qualquer tipo de tratamento ou processamento de áudio, e é chamado com cinco variáveis ajustadas: 
+</p>
+<ul><li><b>KSmsFrom</b>, contendo o número de origem de quem enviou a mensagem; 
+</li><li><b>KSmsDate</b>, que define a data/hora do recebimento da mensagem; 
+</li><li><b>KSmsSize</b>, representando o tamanho da mensagem (em bytes); 
+</li><li><b>KSmsMode</b>, contendo a codificação utilizada para transmitir a mensagem; 
+</li><li><b>KSmsBody</b>, que é a mensagem em si.
+</li></ul>
+<p>O processamento do dialplan do FreeSWITCH pode ser utilizado para guardar esta mensagem em um banco de dados, executar alguma aplicação, entre outros. Entretanto, a única ação aceita por este channel é desligamento (hangup) - ou seja, esta ligação entrante não pode ser considerada uma ligação comum.
+<br />
+</p>
+<a name="Canal_.22Khomp_PR.22" id="Canal_.22Khomp_PR.22"></a><h3> <span class="mw-headline"> Canal "Khomp_PR"  </span></h3>
+<p>Este canal de comunicação é utilizado para receber ligações em placas de gravação passiva (família <b>KPR</b> e <b>KFXO-HI</b>), criando ligações entrantes no FreeSWITCH para cada chamada recebida. Este canal permite apenas o recebimento de áudio capturado do <i>link</i>, não permitindo tanto o envio de mensagens de áudio quanto o de sinalizações de controle.
+</p><p>O processamento do dialplan do FreeSWITCH pode ser utilizado para gravar dados sobre esta ligação em um banco de dados, executar alguma aplicação especial e/ou algum <i>application</i> de gravação (como o <b>record</b>), entre outros. Entretanto, a única ação aceita por este channel é desligamento (hangup) - ou seja, esta ligação entrante não pode ser considerada uma ligação comum.
+<br />
+</p><p><br />
+</p>
+<a name="C.C3.B3digos_e_significados" id="C.C3.B3digos_e_significados"></a><h1> <span class="mw-headline">Códigos e significados </span></h1>
+<p>Este capítulo apresenta os códigos presentes no Endpoint da Khomp e seus significados, utilizados nos comandos de console:
+<br />
+</p>
+<a name="Estados_de_canais" id="Estados_de_canais"></a><h2> <span class="mw-headline">Estados de canais </span></h2>
+<p>Refletem o estado do canal relativo à placa. No caso de links E1, o estado pode ter uma ou mais das seguintes opções:
+</p>
+<ul><li> <b>Free</b>: o canal está livre;
+</li><li> <b>Busy</b>: o canal não está livre (ou ocupado, ou em falha);
+</li><li> <b>Outgoing</b>: o canal possui uma ligação de saída;
+</li><li> <b>Incoming</b>: o canal possui uma ligação de entrada;
+</li><li> <b>Locked</b>: o canal está bloqueado;
+</li><li> <b>Outgoing Lock</b>: o canal está bloqueado para chamadas saintes;
+</li><li> <b>Local Fail</b>: o canal possui uma falha local (nesta ponta);
+</li><li> <b>Incoming Lock</b>: o canal está bloqueado para chamadas entrantes;
+</li><li> <b>Remote Lock</b>: há um bloqueio remoto (na outra ponta) neste canal.
+</li></ul>
+<p>No caso de um canal FXS, o estado é definido por um destes valores:
+</p>
+<ul><li> <b>On Hook</b>: o telefone conectado neste canal está no gancho ou desconectado;
+</li><li> <b>Off Hook</b>: o telefone conectado neste canal está fora do gancho;
+</li><li> <b>Ringing</b>: o canal está sendo chamado;
+</li><li> <b>Failure</b>: o canal está em falha devido a problemas de comunicação entre a central e a placa.
+</li></ul>
+<p>No caso de um canal GSM, o estado também é definido por um dos valores a seguir:
+</p>
+<ul><li> <b>Idle</b>: o canal está livre e disponível para realizar chamadas;
+</li><li> <b>Call In Progress</b>: o canal está ocupado em uma ligação;
+</li><li> <b>Modem Error</b>: ocorreu um erro na comunicação com o modem do canal;
+</li><li> <b>SIM Card Error</b>: o SIM card não está presente ou não foi inserido/detectado corretamente;
+</li><li> <b>Network Error</b>: ocorreu um erro ao comunicar-se com a rede;
+</li><li> <b>Not Ready</b>: o modem está sendo inicializado no canal.
+</li></ul>
+<p>E no caso de um canal FXO, os estados serão os seguintes:
+</p>
+<ul><li> <b>Disabled</b>: o canal está desabilitado;
+</li><li> <b>Enabled</b>: o canal está habilitado.
+</li></ul>
+<p><br />
+</p>
+<a name="Estados_de_chamada" id="Estados_de_chamada"></a><h2> <span class="mw-headline"> Estados de chamada </span></h2>
+<p>Define o estado de cada canal relativo ao software, que pode ser::
+</p>
+<ul><li><b>Free</b>: o canal está livre;
+</li><li><b>Incoming</b>: o canal está recebendo uma chamada;
+</li><li><b>Outgoing</b>: o canal está realizando uma chamada;
+</li><li><b>Failure</b>: o canal está em falha.
+</li></ul>
+<p><br />
+</p>
+<a name="Estados_da_chamada_FreeSWITCH" id="Estados_da_chamada_FreeSWITCH"></a><h2> <span class="mw-headline"> Estados da chamada FreeSWITCH </span></h2>
+<p>Reflete diretamente o estado de chamada controlado pelo FreeSWITCH, que pode se
+</p>
+<ul><li> <b>new</b>: Canal é recém criado;
+</li><li> <b>init</b>: Canal foi inicializado;
+</li><li> <b>routing</b>: Canal está procurando uma extensão para executar;
+</li><li> <b>execute</b>: Canal está executando seu dialplan;
+</li><li> <b>ex_media</b>: Canal está trocando media com outro canal;
+</li><li> <b>cs_media</b>: Canal está consumindo toda media;
+</li><li> <b>hangup</b>: O canal está marcada para hangup e pronto para terminar.
+</li></ul>
+<p><br />
+</p>
+<a name="C.C3.B3digos_GSM" id="C.C3.B3digos_GSM"></a><h2> <span class="mw-headline"> Códigos GSM </span></h2>
+<p>Os seguintes códigos numéricos são reportados:
+</p>
+<a name="C.C3.B3digos_de_SMS_.28SMS_cause.29" id="C.C3.B3digos_de_SMS_.28SMS_cause.29"></a><h3> <span class="mw-headline"> Códigos de SMS (<i>SMS cause</i>) </span></h3>
+<pre>1 Unassigned number
+8      Operator determined barring
+10     Call barred
+21     SMS transfer rejected
+27     Destination out of service
+28     Unidentified subscriber
+29     Facility rejected
+30     Unknown subscriber
+38     Network out of order
+41     Temporary failure
+42     Congestion
+47     Resources unavailable
+50     Facility not subscribed
+69     Facility not implemented
+81     Invalid SMS transfer reference value
+95     Invalid message
+96     Invalid mandatory information
+97     Message type non existent
+98     Message not compatible with SMS protection state
+99     Information element non existent
+111    Protocol error
+127    Interworking
+128    Telematic interworking not supported
+129    SMS type zero not supported
+130    Cannot replace SMS
+143    Unspecified TPPID error
+144    Alphabet not supported
+145    Message class not supported
+159    Unspecified TPDCS error
+160    Command cannot be actioned
+161    Command unsupported
+175    Unspecified TP command error
+176    TPDU not supported
+192    SC busy
+193    No SC subscription
+194    SC system failure
+195    Invalid SME address
+196    Destination SME barred
+197    SM rejected duplicate SM
+198    TPVPF not supported
+199    TPVP not supported
+208    SIM SMS storage full
+209    No SMS storage capability in SIM
+210    Error in SMS
+211    Memory capatity exceeded
+213    SIM data download error
+255    Unspecified error
+300    Phone failure
+301    SMS service reserved
+302    Operation not allowed
+303    Operation not supported
+304    Invalid PDU mode parameter
+305    Invalid text mode parameter
+310    SIM not inserted
+311    SIM PIN necessary
+312    Phone SIM PIN necessary
+313    SIM failure
+314    SIM busy
+315    SIM wrong
+320    Memory failure
+321    Invalid memory index
+322    Memory full
+330    SMSC address unknown
+331    No network service
+332    Network timeout
+500    Unknown error
+512    Network busy
+513    Invalid destination address
+514    Invalid message body length
+515    Phone is not in service
+516    Invalid preferred memory storage
+517    User terminated
+</pre>
+<a name="C.C3.B3digos_de_chamada_.28call_cause.29" id="C.C3.B3digos_de_chamada_.28call_cause.29"></a><h3> <span class="mw-headline"> Códigos de chamada (<i>call cause</i>) </span></h3>
+<pre>1 Unallocated number
+3      No route to destination
+6      Channel unacceptable
+8      Operator determined barring
+16     Normal call clear
+17     User busy
+18     No user responding
+19     No answer from user
+21     Call rejected
+22     Number changed
+26     Non Selected user clear
+27     Destination out of order
+28     Invalid number format
+29     Facility rejected
+30     Response status enquiry
+31     Normal, unspecified
+34     No circuit channel available
+38     Network out of order
+41     Temporary failure
+42     Switch congestion
+43     Access information discarded
+44     Requested channel unavailable
+47     Resource unavailable
+49     QoS unavailable
+50     Request facility not subscribed
+55     Call barred with UG
+57     Bearer capability not authorized
+58     Bearer capability not available
+63     Service not available
+65     Bearer capability not implemented
+69     Request facility not implemented
+70     Only restricted bearer capability available
+79     Service not implemented
+81     Invalid call reference value
+82     User not member of UG
+88     Incompatible destination
+91     Invalid transit network selected
+95     Invalid message
+96     Missing mandatory information element
+97     Message type not implemented
+98     Message incompatible with state
+99     Information element not implemented
+100    Invalid information element
+101    Message incompatible with state (2)
+102    Recovery on timer expiry
+111    Protocol error
+127    Interworking
+</pre>
+<a name="C.C3.B3digos_gerais_.28mobile_cause.29" id="C.C3.B3digos_gerais_.28mobile_cause.29"></a><h3> <span class="mw-headline"> Códigos gerais (<i>mobile cause</i>) </span></h3>
+<pre>0 Phone failure
+1      No connection to phone
+2      Phone adaptor link reserved
+3      Operation not allowed
+4      Operation not supported
+5      Phone SIM PIN required
+6      Phone FSIM PIN required
+7      Phone FSIM PUK required
+10     SIM not inserted
+11     SIM PIN required
+12     SIM PUK required
+13     SIM failure
+14     SIM busy
+15     SIM wrong
+16     Incorrect password
+17     SIM PIN2 required
+18     SIM PUK2 required
+20     Memory full
+21     Invalid index
+22     Not found
+23     Memory failure
+24     Text string too long
+25     Invalid character in text string
+26     Dial string too long
+27     Invalid character in dial string
+30     No network service
+31     Network timeout
+32     Network not allowed
+33     Command aborted
+34     Number parameter instead of text parameter
+35     Text parameter instead of number parameter
+36     Numeric parameter out of bounds
+37     Text string too short
+40     Network PIN required
+41     Network PUK required
+42     Network subset PIN required
+43     Network subset PUK required
+44     Network service provider PIN required
+45     Network service provider PUK required
+46     Corporate PIN required
+47     Corporate PUK required
+60     SIM Service option not supported
+100    Unknown
+103    Illegal MS #3
+106    Illegal MS #6
+107    GPRS service not allowed #7
+111    PLMN not allowed #11
+112    Location area not allowed #12
+113    Roaming not allowed #13
+132    Service option not supported #32
+133    Registration service option not subscribed #33
+134    Service option temporary out of order #34
+147    Long context activation
+148    Unspecified GPRS error
+149    PDP authentication failure
+150    Invalid mobile class
+151    GPRS disconnection TMR active
+256    Too many active calls
+257    Call rejected
+258    Unanswered call pending
+259    Unknown calling error
+260    No phone number recognized
+261    Call state not idle
+262    Call in progress
+263    Dial state error
+264    Unlock code required
+265    Network busy
+266    Invalid phone number
+267    Number entry already started
+268    Cancelled by user
+269    Number entry could not be started
+280    Data lost
+281    Invalid message body length
+282    Inactive socket
+283    Socket already open
+</pre>
+<p><br />
+</p>
+<a name="Solu.C3.A7.C3.A3o_de_problemas" id="Solu.C3.A7.C3.A3o_de_problemas"></a><h1> <span class="mw-headline"> Solução de problemas </span></h1>
+<p>Nesta seção, erros e suas soluções mais comuns são apresentados.
+</p>
+<a name="Erro_durante_a_instala.C3.A7.C3.A3o_do_m.C3.B3dulo_de_kernel" id="Erro_durante_a_instala.C3.A7.C3.A3o_do_m.C3.B3dulo_de_kernel"></a><h2> <span class="mw-headline"> Erro durante a instalação do módulo de kernel </span></h2>
+<p>Durante a instalação do <i>Endpoint</i> da Khomp, podem ocorrer as seguintes mensagens:
+<!-- NEED 3 --> 
+</p>
+<pre>K3L: WARNING: Unable to find a module for [...]
+</pre>
+<p>ou
+<!-- NEED 8 --> 
+</p>
+<pre>install: ******  THE KERNEL MODULE HAS NOT BEEN INSTALLED: *******
+install: 
+install: ** Please, untar the file kpdriver*.tar.gz located in: **
+install: **                 '/usr/src/khomp/'                   **
+install: **             then check the README.txt               **
+install: **  for knowing how to proceed with the installation.  **
+</pre>
+<p>Neste caso, será necessário compilar os <i>drivers</i> manualmente para o seu sistema. Prossiga para o item abaixo para maiores informações.
+<br />
+</p>
+<a name="Compilandos_os_drivers_e_iniciando_os_servi.C3.A7os" id="Compilandos_os_drivers_e_iniciando_os_servi.C3.A7os"></a><h3> <span class="mw-headline">Compilandos os <i>drivers</i> e iniciando os serviços </span></h3>
+<p>Basta seguir ao diretório <b>/usr/src/khomp</b>, descompactar o arquivo "kpdriver_2.0.0<b>XX</b>.tar.gz", e acompanhar procedimentos descritos no arquivo <b>README.txt</b>.
+</p><p>Após realizar a compilação e a instalação do módulo, basta carregá-lo no sistema, configurar as placas, e iniciar o servidor de processos da Khomp. 
+</p><p>Para carregar o driver de kernel, é necessário executar o seguinte comando:
+<!-- NEED 3 --> 
+</p>
+<pre># /etc/init.d/khompdrv start
+</pre>
+<p>Para configurar as placas, por sua vez,  necessário executar o comando:
+<!-- NEED 3 --> 
+</p>
+<pre># khompwizard
+</pre>
+<p>Isto executará um assistente de configuração, que irá perguntar a sinalização utilizada no sistema, bem como outros parâmetros de utilização das placas.
+</p><p>Caso seja necessário configurar outros parâmetros adicionais, pode-se utilizar o seguinte comando:
+<!-- NEED 3 --> 
+</p>
+<pre># k3lconfig
+</pre>
+<p>Este configurador, por sua vez, mostra todas as opções possíveis de configuração da placa. Os parâmetros que não forem configurados assumem os valores padrão automaticamente, e são compatíveis com a maior parte dos sistemas. Maiores detalhes sobre este programa podem ser obtidos na seção de número '2'. 
+</p><p><br />
+</p>
+<ul><li> <b>IMPORTANTE</b>: Para o FreeSWITCH iniciar, é preciso que a placa da khomp esteja configurada e todos módulos estejam rodando (conforme mostrado acima). <b>Caso a placa não esteja configurada, o FreeSWITCH não iniciará</b>.<br /><br />Se você deseja rodar o sistema sem a placa da Khomp, é preciso configurar o FreeSWITCH para ele não carregar o módulo da Khomp. Para isso, abra o arquivo "<i>/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml</i>", e comente a linha que carrega o módulo:<br />
+</li></ul>
+<pre>
+  &lt;!-- &lt;load module=&quot;mod_khomp&quot; /&gt; --&gt;
+</pre><br />
+<p>Quando a placa da Khomp estiver devidamente configurada e os módulos da khomp carregados (explicado acima), lembre-se de descomentar esta linha no arquivo.
+</p><p><br />
+Por fim, para carregar o servidor de processos, basta executar o seguinte comando:
+<!-- NEED 3 --> 
+</p>
+<pre># kserver start
+</pre>
+<p>Após realizar estes procedimentos, o Endpoint já estará operacional, e o FreeSWITCH já pode ser carregado.
+<br />
+</p>
+<a name="Configurando_par.C3.A2metros_especiais_de_sinaliza.C3.A7.C3.A3o_ou_.C3.A1udio" id="Configurando_par.C3.A2metros_especiais_de_sinaliza.C3.A7.C3.A3o_ou_.C3.A1udio"></a><h2> <span class="mw-headline">Configurando parâmetros especiais de sinalização ou áudio </span></h2>
+<p>Para configurar parâmetros especiais de sincronismo e/ou sinalização, é possível utilizar o programa "k3lconfig": basta selecionar a placa desejada, e as opções das placas serão apresentadas, divididas em seções e subseções para facilitar o acesso. Não é necessário efetuar a configuração de todos os parâmetros: os valores padrão são assumidos, caso não sejam configurados.
+</p><p>Para ajustar a sinalização do link, basta - depois de selecionar a placa - entrar na seção "Opções de sinalização", e em seguida, em "Sinalização da linha". Para escolher uma sinalização específica, basta utilizar as teclas de direcionamento (setas) até selecioná-la, pressionar 'espaço', e confirmar a opção pressionando 'Enter' sobre o botão "Confirmar".
+</p><p>Por fim, para salvar as configurações modificadas, basta sair do programa: ele irá mostrar uma janela, com opções para salvar ou não as alterações realizadas.
+</p><p>É importante notar que <b>não é necessário alterar/ativar as seguintes opções</b>:
+</p>
+<ul><li> Cancelamento de eco automático;
+</li><li> Supressão de DTMFs automática;
+</li><li> Controle de ganho (AGC) automático.
+</li></ul>
+<p>Estas opções <b>são controladas pelo Endpoint</b>, e devem estar <b>desabilitadas</b> no 'k3lconfig'.
+<br />
+</p>
+<a name="Inicializa.C3.A7.C3.A3o_autom.C3.A1tica_dos_servi.C3.A7os_e_m.C3.B3dulos_de_kernel" id="Inicializa.C3.A7.C3.A3o_autom.C3.A1tica_dos_servi.C3.A7os_e_m.C3.B3dulos_de_kernel"></a><h2> <span class="mw-headline">Inicialização automática dos serviços e módulos de <i>kernel</i> </span></h2>
+<p>Se a carga dos módulos de <i>kernel</i> ou a inicialização dos serviços da Khomp não for realizada automaticamente na inicialização do sistema, é possível realizar esta instalação manualmente, criando um <i>link</i> para os <i>scripts</i> <b>/etc/init.d/khompdrv</b> e <b>/etc/init.d/kserver</b> no diretório de inicialização do sistema.
+</p><p>Na caso da distribuição <b>Debian</b>, o <i>script</i> de carga dos módulos de <i>kernel</i> seria <i>linkado</i> dentro do diretório <i>/etc/rcS.d/</i>, enquanto o <i>script</i> de inicialização dos serviços seria <i>linkado</i> dentro dos diretórios <i>/etc/rc2.d</i>, <i>/etc/rc3.d</i>, <i>/etc/rc4.d</i>, <i>/etc/rc5.d</i>, da seguinte forma:
+</p><p><!-- NEED 6 -->
+</p>
+<pre># ln -s /etc/init.d/khompdrv  /etc/rcS.d/S19khompdrv
+# ln -s /etc/init.d/kserver   /etc/rc2.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc3.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc4.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc5.d/S20kserver
+</pre>
+<p>É interessante verificar as normas da sua distribuição para inicializar os serviços de acordo com o que é esperado pela inicialização da mesma.
+<br />
+</p>
+<a name="Ap.C3.AAndice" id="Ap.C3.AAndice"></a><h1> <span class="mw-headline"> Apêndice </span></h1>
+<p>Nesta seção, encontram-se informações úteis sobre o Endpoint e componentes relacionados.
+</p>
+<a name="Disposi.C3.A7.C3.A3o_dos_arquivos" id="Disposi.C3.A7.C3.A3o_dos_arquivos"></a><h2> <span class="mw-headline"> Disposição dos arquivos </span></h2>
+<p>Os diretórios criados/modificados nesta instalação são:
+<!-- NEED 20 -->
+</p>
+<pre>/etc/init.d/                -- Scripts de inicialização;
+
+/etc/khomp/                 -- Arquivos de firmware e configurações;
+
+/usr/local/freeswitch/conf/ -- Configurações do FreeSWITCH e Endpoint;
+
+/usr/doc/khomp/             -- Documentação das placas, do mod_khomp e dos utilitários;
+
+/usr/sbin/                  -- Utilitários e servidor de processos;
+
+/usr/lib/                   -- Bibliotecas compartilhadas da K3L;
+
+/usr/local/freeswitch/mod/  -- Módulo 'mod_khomp.so';
+/var/log/khomp2.1/          -- Diretório de logs da K3L e Endpoint
+</pre>
+<p><br />
+O <i>script</i> <b>/etc/init.d/khompdrv</b> é responsável por carregar os módulos <i>kpci9030.ko</i> e <i>kpex8311.ko</i> no <i>kernel</i>, que deve ser realizada automaticamente na inicialização do sistema. Em caso de problemas, verifique a seção <a href="#Solu.C3.A7.C3.A3o_de_problemas" title="">Solução de problemas</a>.
+<br />
+</p><p><br />
+</p></body></html>
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_khomp/docs/Manual.pdf b/src/mod/endpoints/mod_khomp/docs/Manual.pdf
new file mode 100644 (file)
index 0000000..ea29f71
Binary files /dev/null and b/src/mod/endpoints/mod_khomp/docs/Manual.pdf differ
diff --git a/src/mod/endpoints/mod_khomp/docs/README.html b/src/mod/endpoints/mod_khomp/docs/README.html
new file mode 100644 (file)
index 0000000..e4cae5a
--- /dev/null
@@ -0,0 +1,39 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Mod Khomp: README</title></head><body><a name="Guia_R.C3.A1pido" id="Guia_R.C3.A1pido"></a><h1> <span class="mw-headline"> Guia Rápido  </span></h1>
+<p>Depois de instalar a placa no sistema, e executar o programa de instalação pela primeira vez, os <i>drivers</i> e serviços da Khomp serão adicionados na inicialização do sistema, e automaticamente carregados.
+</p><p>Se o sistema possuir pelo menos uma placa de tronco E1 e/ou uma placa FXO, uma tela de configuração básica deverá ser apresentada ao final do processo, questionando parâmetros de sinalização - no caso de existirem placas E1 - e/ou realizando o ajuste de cadências - no caso de existirem placas FXO.
+</p><p>Se todas estas etapas foram executadas com sucesso, prossiga para o item <b>Utilizando o <i>Endpoint</i> da Khomp</b>. Caso algum problema ocorra, consulte o <a href=".htmlMod_Khomp/Manual" title="Mod Khomp/Manual">Manual do Endpoint</a>, seguindo para a seção de <a href=".htmlMod_Khomp/Manual#Solu.C3.A7.C3.A3o_de_problemas" title="Mod Khomp/Manual">Solução de problemas</a>.
+</p>
+<a name="Utilizando_o_Endpoint_da_Khomp" id="Utilizando_o_Endpoint_da_Khomp"></a><h1> <span class="mw-headline"> Utilizando o <i>Endpoint</i> da Khomp </span></h1>
+<p>Após a instalação e inicialização dos serviços necessários pela Khomp, o FreeSWITCH já pode ser carregado ou inicializado.
+</p>
+<ul><li> <b>AVISO</b>: É imprescindível que o <b>FreeSWITCH</b> não seja executado utilizando a opção que desabilita o escalonamento em tempo real (-nort), <b>especialmente</b> se este estiver sendo executado lado-a-lado com servidores <i>web</i> ou servidores de banco de dados. Não realizar este procedimento pode resultar em perda de qualidade do áudio, gerando um sério comprometimento no andamento das ligações do sistema.
+</li></ul>
+<p>Após a inicialização do FreeSWITCH, pode-se verificar se o módulo da Khomp foi carregado através do seguinte comando:<br /> 
+</p>
+<pre> freeswitch@hostname&gt; module_exists mod_khomp
+</pre>
+<p>A próxima linha deverá responder algo tipo:
+</p>
+<pre> true
+</pre>
+<p>Para verificar se o FreeSWITCH reconheceu todas as placas, digite: 
+</p>
+<pre> freeswitch@hostname&gt; khomp summary
+</pre>
+<p>A saída desse comando mostrará detalhes de todas placas reconhecidas.
+</p><p>No caso de uma placa de tronco E1, pode-se verificar o estado dos links com o seguinte comando:
+</p>
+<pre> freeswitch@hostname&gt; khomp show links
+</pre>
+<p>O estado dos canais individuais, por sua vez, pode ser aferido com o comando:
+</p>
+<pre> freeswitch@hostname&gt; khomp show channels
+</pre>
+<p>Para mais detalhes sobre os comandos do Endpoint da khomp digite no console do FreeSWITCH: 
+</p>
+<pre> freeswitch@hostname&gt; help khomp
+</pre>
+<ul><li> <b>IMPORTANTE</b>: Para fazer completo uso da sua placa Khomp, será preciso configurar suas regras de discagem, seja através do arquivo <i>default.xml</i> ou de um aplicativo externo, definindo regras específicas para realizar ao receber ligações.<br /><br />No <a href=".htmlMod_Khomp/Manual" title="Mod Khomp/Manual">Manual do Endpoint</a>, podem ser encontradas informações sobre o formato dos contextos de entrada (responsáveis por receber as ligações) e sobre as opções disponíveis no application Bridge (responsável por realizar ligações) que podem ser utilizadas com o Endpoint da Khomp, além de outras funcionalidades especiais providas pelo mesmo.
+</li></ul>
+<p><br />
+</p></body></html>
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_khomp/docs/README.pdf b/src/mod/endpoints/mod_khomp/docs/README.pdf
new file mode 100644 (file)
index 0000000..698ab83
Binary files /dev/null and b/src/mod/endpoints/mod_khomp/docs/README.pdf differ
diff --git a/src/mod/endpoints/mod_khomp/docs/README_en.html b/src/mod/endpoints/mod_khomp/docs/README_en.html
new file mode 100644 (file)
index 0000000..5d44b82
--- /dev/null
@@ -0,0 +1,40 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Mod Khomp: README: en</title></head><body><a name="Quick_guide" id="Quick_guide"></a><h1> <span class="mw-headline"> Quick guide </span></h1>
+<p>After installing the card in the system and run the installation program for the first time, the <i>drivers</i> and Khomp services will be added at system startup, and automatically loaded.
+</p><p>If your system has at least one E1 trunk card and / or an FXO card, a basic setup screen will be presented at the end of the process, questioning signaling parameters - if there are signs E1 - and/or performing the adjustment cadences - where that FXO cards.
+</p><p>If all these steps were performed successfully, proceed to the item <b>Using Khomp Endpoint</b>. If a problem occurs, see the <a href=".htmlMod_Khomp/User_Guide" title="Mod Khomp/User Guide">User Guide</a>, in the section <a href=".htmlMod_Khomp/User_Guide#Troubleshooting" title="Mod Khomp/User Guide">Troubleshooting</a>.
+</p>
+<a name="Using_the_Khomp_Endpoint" id="Using_the_Khomp_Endpoint"></a><h1> <span class="mw-headline"> Using the Khomp Endpoint </span></h1>
+<p>After installation and startup services required by Khomp, FreeSWITCH can now be loaded or initialized.
+</p>
+<ul><li><b>WARNING</b>: It is imperative that the<b>FreeSWITCH</b> is not executed using the option that disables the escalation in real time (-nort), <b>especially</b> if this is running side-by server-side with web servers or database. Failure to do so may result in loss of audio quality, causing a serious commitment on the progress of system connections.
+</li></ul>
+<p>After initialization of FreeSWITCH, you can verify that the module was loaded Khomp through the following command: <br />
+</p><p><br />
+</p>
+<pre> freeswitch@hostname&gt; module_exists mod_khomp
+</pre>
+<p>The next line should answer something like:
+</p>
+<pre> true
+</pre>
+<p>To verify that the FreeSwitch recognize all the cards, type:
+</p>
+<pre> freeswitch@hostname&gt; khomp summary
+</pre>
+<p>The output of this command will show details of all cards accepted.
+</p><p>In the case of an E1 card, you can check the status of links with the following command:
+</p>
+<pre> freeswitch@hostname&gt; khomp show links
+</pre>
+<p>The state of individual channels, in turn, can be measured with the command:
+</p>
+<pre> freeswitch@hostname&gt; khomp show channels
+</pre>
+<p>For more details on the commands of the Endpoint khomp type in the console of FreeSWITCH:
+</p>
+<pre> freeswitch@hostname&gt; help khomp
+</pre>
+<ul><li><b>IMPORTANT</b>: To make full use of your card Khomp, you must configure your dialing rules, either through the extension.conf or from an external application by setting specific rules for conduct by receiving connections. <br /> In the <a href=".htmlMod_Khomp/User_Guide" title="Mod Khomp/User Guide">User Guide</a>, information can be found on the format of input contexts (responsible for receiving calls) and on the options available on application Dial (responsible for make calls) that can be used with the Endpoint Khomp, and other special features provided by it.
+</li></ul>
+<p><br />
+</p></body></html>
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_khomp/docs/README_en.pdf b/src/mod/endpoints/mod_khomp/docs/README_en.pdf
new file mode 100644 (file)
index 0000000..e36d6f1
Binary files /dev/null and b/src/mod/endpoints/mod_khomp/docs/README_en.pdf differ
diff --git a/src/mod/endpoints/mod_khomp/docs/User_Guide.html b/src/mod/endpoints/mod_khomp/docs/User_Guide.html
new file mode 100644 (file)
index 0000000..1a276b9
--- /dev/null
@@ -0,0 +1,1099 @@
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title>Mod Khomp: User Guide</title></head><body>
+<a name="First_considerations" id="First_considerations"></a><h1> <span class="mw-headline"> First considerations </span></h1>
+<p>This document covers information about the <i>Endpoint</i> of Khomp as a whole, include the options, <i>applications</i>, <b>CLI</b> commands, among others.
+</p><p>For first installation procedures, please see the <a href=".htmlMod_Khomp/README/en" title="Mod Khomp/README/en">README</a>.
+<br />
+</p>
+<a name="Configuration" id="Configuration"></a><h1> <span class="mw-headline"> Configuration </span></h1>
+<p>Configuring the Khomp Endpoint is a task that consists of three steps:
+</p>
+<ul><li> Configuration of the boards through the K3L;
+</li><li> Setting up the Endpoint;
+</li><li> Setting up the FreeSWITCH.
+</li></ul>
+<p>These steps are described more fully below.
+<br />
+</p>
+<a name="K3L_API_Configuration" id="K3L_API_Configuration"></a><h2> <span class="mw-headline"> K3L API Configuration </span></h2>
+<p>This step is carried out in a semi-automated way using the <b>khompwizard</b> program, a wizard that configures the basic parameters of the system boards. This wizard initializes the configuration files using information from the user when they are needed, initializing the standard settings to default values.
+</p><p>Typically, this program runs automatically after installation of the system. However, you may need to run it manually if an update is being performed, or if new cards were added to the system after installing new drivers.
+</p><p><br />
+If you need to set advanced parameters of the board and/or signaling, the program <b>k3lconfig</b> allows you to access all the available settings for each installed card. For more information about this program, check the <b><a href="http://169.254.1.3/kdevwiki/wikidocs/index.php?title=K3lconfig_-_User%27s_Guide&amp;action=edit&amp;redlink=1" class="new" title="K3lconfig - User&#39;s Guide (página não existe)">k3lconfig User's Guide</a></b>. For solving synchronization issues, check the <a href="#_Troubleshooting" title="">Troubleshooting</a> section for manual configuration of the boards.
+<br />
+</p>
+<a name="Endpoint_Configuration" id="Endpoint_Configuration"></a><h2> <span class="mw-headline"> Endpoint Configuration </span></h2>
+<p>The system's default configuration normally meet most user's needs. However, the configuration of the Endpoint Khomp can be modified through the configuration file '<b>/usr/local/freeswitch/conf/autoload_configs/khomp.conf.xml'</b>.
+</p><p>The list of options is as follows:
+</p>
+<a name=".3Cchannels.3E" id=".3Cchannels.3E"></a><h4> <span class="mw-headline"> &lt;channels&gt; </span></h4>
+<p>Define general settings of all channels of Khomp:
+</p>
+<pre><b>Sintaxe:</b> &lt;param name="..." value="..."/&gt;
+</pre>
+<ul><li><b>auto-fax-adjustment</b>: Enable ("yes") or disables ("no") the automatic adjustment of the channel (disable the echo canceller and the suppression DTMF) tone to detect FAX (local option)&nbsp;;
+</li><li><b>auto-gain-control</b>:Enable ("yes") or disables ("no") the activation of the automatic gain control (AGC) by the Endpoint (local option);
+</li><li><b>context-digital</b>: Context for incoming connections on digital boards (the default is "khomp-DD-LL", where "DD" will be replaced at the time of connection by the device number, "LL" by the number of the link, "CCC" by channel number and "SSSS" for the device serial number);
+</li><li><b>context-fxo</b>: Context for incoming connections on FXO cards (the default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC" by channel number, and "SSSS" by the device serial number);
+</li><li><b>context-fxo-alt</b>: Alternative input context for FXO cards (the default is empty - when set, follows the same substitution rules for <b>context-fxo</b>);
+</li><li><b>context-fxs</b>: Context for incoming connections on FXS cards (the default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC" by channel number, and "SSSS" by the device serial number); 
+</li><li><b>context-fxs-alt</b>: Alternative input context for FXS cards (the default is empty - when set, follows the same substitution rules for context-fxs); number); 
+</li><li><b>context-gsm-call</b> (or <b>context-gsm</b>): Context of entry for GSM boards (the default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC" by channel number, and "SSSS" by the device serial number);
+</li><li><b>context-gsm-alt-call</b> (or <b>context-gsm-alt</b>): Alternative input context for GSM (the default is zero - when set, follows the same substitution rules for <b>context-gsm-call</b>);
+</li><li><b>context-gsm-sms</b>: Context for incoming SMSs (the default is "khomp-sms-CC-DD", where "DD" will be replaced by the number of device, "CC" by channel number and "SSSS" by the device's serial number);
+</li><li><b>context-gsm-wait</b>: Context used for pre-processing of incoming GSM calls that are on waiting state - to disable this feature, use <b>none</b> (the default is "khomp-wait-CC-DD", where "DD" will be replaced by the number of device, "CC" by channel number and "SSSS" by the device's serial number);
+</li><li><b>context-pr</b>: Context for incoming connections on boards KPR (default is "khomp-CC-DD", where "DD" will be replaced at the time of connection by the device number, "CC "by channel number);
+</li><li><b>disconnect-delay</b>: Sets the time in milliseconds to perform processing a disconnect event, to ignore situations where other equipment performing the double service to overthrow collect calls (local option);
+</li><li><b>echo-canceller</b> (former 'echocanceller): Active ("yes") or disables ("no") echo cancellation automatic Endpoint (local option);
+</li><li><b>fxo-send-pre-audio</b>: When enabled ("yes") releases audio channel before the outgoing call connection boards KFXO (the default value is "yes");
+</li><li><b>fxs-global-orig</b>: Start number for sequencial branch numbering in FXS cards that are not listed in the <b>[fxs-branches]</b> section (the numbering follows ascending order from board number and physical channel number) (default is "0");
+</li><li><b>fxs-co-dialtone</b>: Sequences of numbers, separated by commas, which fires a continuous tone (of central office) in FXS branches (eg: "0,99" means that, when you dial "0" or "99", the user will hear a continuous dial tone) (default is empty);
+</li><li><b>fxs-bina</b>: When enabled ("yes"), calls to FXS lines will send digits corresponding to the source phone identification using BINA DTMF signaling (the default value is "no") (local option);
+</li><li><b>input-volume</b>: Sets the volume gain for incoming audio (entering the board), from -10 to +10 (local option);
+</li><li><b>kommuter-activation</b>: Sets whether to activate devices kommuter found in the system will be done automatically ("auto") by the channel, or manually ("manual") by the user through the command "khomp kommuter on/off" 
+</li><li><b>kommuter-timeout</b>: Sets the timeout (in seconds) for initializing the kommuter devices. If this timeout is reached without receiving notification of the channel, the devices will switch back to "off" condition. The minimum value is "0", where the links will always remain switched "on", and the maximum is "255";
+</li><li><b>language</b>: Set language to Khomp channel calls (local option);
+</li><li><b>log-to-console</b>: Set log messages to be printed on the console;
+</li><li><b>log-to-disk</b> (old "log"): Set log messages to be saved to disk;
+</li><li><b>out-of-band-DTMF</b> (former <b>dtmfsuppression</b>): Activate ("yes") or disables ("no") the removal and DTMF sending these out-of-band (local option);
+</li><li><b>output-volume</b>: Define o volume de saída das ligações, varia de -10 a +10&nbsp;; 
+</li><li><b>pulse-forwarding</b> (former 'pulsedetection): Active ("yes") or disables ("no") for the detection of pulses and converting them into DTMF (local option);
+</li><li><b>r2-preconnect-wait</b> (former 'r2preconnectwait): Sets the timeout sending the ringback signaling, protocol R2/MFC to start sending audio silence. Only used when "r2-strict-Behavior" is set to "no" (local option);
+</li><li><b>r2-strict-Behaviour</b>: Enable ("yes") or disables ("no") the behavior of signaling R2/MFC as the standard sets. The default is "no", and can be changed to "yes" if needed to receive / send data precise signaling protocol (condition B, for example) (local option);
+</li><li><b>ringback-delay-co</b>: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication from signaling and there is no audio being sent by the channel which indicated the situation (local option);
+</li><li><b>ringback-delay-pbx</b>: Sets the delay to enable the generation of call control tone (ringback) by the Endpoint Khomp when there is an ringback indication, and the audio has no tone (silence) (local option);
+</li><li><b>suppression-delay</b> (former <b>suppressiondelay</b>): Activate ("yes") or disables ("no") the delay necessary to suppress DTMF. If disabled ("no"), also disables suppression of DTMF (local option);
+</li><li><b>trace</b>: Set debugging options. Should not be used in production unless absolutely necessary;
+</li><li><b>user-transfer-digits</b>: Defines a sequence of DTMF digits to initiate the transfer between FreeSWITCH&reg; and another PBX (using user signaling, like QSig or FXO FLASH).
+</li></ul>
+<p><br />
+</p>
+<a name=".3Cgroups.3E" id=".3Cgroups.3E"></a><h4> <span class="mw-headline"> &lt;groups&gt; </span></h4>
+<p>Defines the groups to be used in channel allocation.
+</p><p>In this case, the options are used to define names for <i>strings allocation of channels</i>. The format follows the standard <b>&lt;group name&gt; = &lt;allocation string&gt;</b>, where the <b>allocation string</b> is the same string used in the bridge application, and <b>group name</b> is an arbitrary name chosen by the user.
+</p>
+<dl><dd>For example, to define the group <b>pstn</b> as the channels 0 and 5 of the board 0, the following line could be used:
+</dd></dl>
+<pre>&lt;param name="pstn" value="b0c0 + b0c5"/&gt; 
+</pre>
+<p>This group, in turn, could be used in the <i>bridge application</i> as <b>&lt;action application="bridge" data="Khomp/Gpstn/..."/&gt;</b>.
+</p>
+<dl><dd>You can associate a given input context to a channel group, simply specify a name of context string after the allocation, separated by ':'.
+</dd></dl>
+<p>For example, to define the same group <b>pstn</b> as channels 0 to 20 of card 0, and defining the incoming context to for channels in this groups to <b>from-pstn</b>, one could use the line:
+</p>
+<pre>&lt;param name="pstn" value="b0c0-20:from-pstn"/&gt;
+</pre>
+<p>This group would be used the same way as before in the <i>bridge application</i>, and all the calls coming from these channels would be treated in context <b>from-pstn</b>.
+<br />
+</p>
+<a name=".3Ccadences.3E" id=".3Ccadences.3E"></a><h4> <span class="mw-headline"> &lt;cadences&gt; </span></h4>
+<p>Defines settings for the Endpoint cadences.
+</p><p>In this case, the options are names cadences, followed by one or two pairs of numbers - that define the ranges of tone and silence to be used in cadences.
+For details, please refer to the configuration file for examples.
+<br />
+</p>
+<a name=".3Cfxs-branches.3E" id=".3Cfxs-branches.3E"></a><h4> <span class="mw-headline"> &lt;fxs-branches&gt; </span></h4>
+<p>Defines source numbers for the board KFXS.
+</p><p>In this case, the options are sequences of prefixes of branches and serial numbers of the boards, which define the basic numbers of source addresses, and the numerical order of the boards. The format of the options is:
+</p>
+<pre>&lt;param name="prefixo" value="serial1, serial2, ...."/&gt;
+</pre>
+<p>For example, if two <b>KFXS-300 SPX</b> boards with serial numbers <b>K0374</b> and <b>K2352</b> must be numbered sequentially, starting from branch 200, you may write:
+</p>
+<pre>&lt;param name="200" value="374, 2352"/&gt;
+</pre>
+<p>This will define the first branch of board '<i>K0374</i> as number 200, the second as 201, and so one. The first branch from board K2352 will have number 230 (as K0374 has 30 channels), the second will be numbered 231, and so on - until the last channel, numbered 259.
+</p><p>For more details, please refer to the configuration file for other exemples.
+<br />
+</p>
+<a name=".3Cfxs-hotlines.3E" id=".3Cfxs-hotlines.3E"></a><h4> <span class="mw-headline"> &lt;fxs-hotlines&gt; </span></h4>
+<p>Sets hotlines for the KFXS based boards
+</p><p>In this case, the options are sequences of branches and sequences of destination numbers, which define branches to be treated as "hotlines" and numbers to be dialed when they are take off hook. For instance:
+</p>
+<pre>&lt;param name="100" value="1234"/&gt;
+&lt;param name="200" value="4321"/&gt; 
+</pre>
+<p>In the first line, the branch numbered 100 will call extension 1234 when taken off hook, while in the second one, branch 200 will call number 4321 when taken off hook.
+<br />
+</p>
+<a name=".3Cfxs-options.3E" id=".3Cfxs-options.3E"></a><h4> <span class="mw-headline"> &lt;fxs-options&gt; </span></h4>
+<p>Allows you to set specific settings for FXS extension.
+</p><p>In this case, the settings are extension numbers (based on those defined in the <b>&lt;fxs-branches&gt;</b>), and the options and their values.
+</p>
+<ul><li>context; 
+</li><li>input-volume; 
+</li><li>output-volume; 
+</li><li>accountcode; 
+</li><li>calleridnum; 
+</li><li>calleridname;
+</li><li>mailbox.
+</li></ul>
+<p>Each option is separated from each other by a pipe "|" or a slash "/" and defined after the colon ":". Example:
+</p>
+<pre>&lt;param name="200" value="language:en|context:master-branch" /&gt;
+</pre>
+<p>For more information on the syntax and examples, please refer to the configuration file.
+</p><p>For more information visit the configuration file '<b>khomp.conf.xml'</b>.
+<br />
+</p>
+<a name="FreeSWITCH_Configuration" id="FreeSWITCH_Configuration"></a><h2> <span class="mw-headline"> FreeSWITCH Configuration </span></h2>
+<p>When connections are received on the boards and devices Khomp, they are forwarded by the <i>Endpoint</i> to specific contexts within the dialplan of FreeSWITCH&reg;. These settings can be changed via the configuration file <b>khomp.conf.xml</b>, available on the FreeSWITCH configuration directory (by default, "<b>/usr/local/freeswitch/conf/autoload_configs</b>").
+</p><p>For details about the specific contexts, see section <a href="#Endpoint_Configuration" title="">Endpoint configuration</a>.
+</p><p>Below are details of how to configure the settings for incoming calls
+<br />
+</p><p><br />
+</p>
+<a name="Contexts_for_E1_channels" id="Contexts_for_E1_channels"></a><h3> <span class="mw-headline"> Contexts for E1 channels </span></h3>
+<p>For E1 boards, inbound contexts are predefined as option <b>context-digital</b> with default value as following:
+</p>
+<pre>&lt;param name="context-digital" value="khomp-DD-LL"/&gt;
+</pre>
+<p>This standard defines the context that links will be redirected in accordance with the number of the board and number of the link: <b>DD</b> is the device number (two digits), and <b>LL</b> is the number of the link (also with two digits).
+</p><p>However, it is possible to configure other inbound contexts, with different formats. There is format <b>CCC</b>, which means the channel number on the card (three digits), and <b>SSSS</b>, which represents the serial board number (with four digits).
+</p><p>Examples for configuration entries (<b>khomp.conf.xml</b>):
+</p>
+<pre>&lt;!-- Serial board number and sequential link (ex: khomp-01-00) --&gt;
+&lt;param name="context-digital" value="khomp-DD-LL"/&gt;
+</pre>
+<pre>&lt;!-- Serial board number and sequential link (ex: khomp-3049-00) --&gt;
+&lt;param name="context-digital" value="khomp-SSSS-LL"/&gt;
+</pre>
+<pre>&lt;!-- Sequential board number and the channel (ex: khomp-00-001) --&gt;
+&lt;param name="context-digital" value="khomp-DD-CCC"/&gt;
+</pre>
+<pre>&lt;!-- Receive all calls in one context (khomp-digital) --&gt;
+&lt;param name="context-digital" value="khomp-digital"/&gt;
+</pre>
+<p>Follows an example the context usage inside the dialplan:
+<!-- NEED 6 -->
+</p>
+<pre>&lt;!--
+The present context in 'extensions.conf' will handle calls
+that come from the link 0 (first link) of the board 0.
+--&gt;
+&lt;context name="khomp-00-00"&gt;
+             .
+             .
+             .
+&lt;/context&gt;
+</pre>
+<p>Another example, using the same format:
+<!-- NEED 6 -->
+</p>
+<pre>&lt;!-- 
+The present context in 'extensions.conf' will handle calls
+that come from the link 1 (second link) of the board 0.
+--&gt;
+&lt;context name="khomp-00-01&gt;
+             .
+             .
+             .
+&lt;/context&gt;
+</pre>
+<p>A complete example, with a few simple actions:
+<!-- NEED 10 -->
+</p>
+<pre>&lt;context name="khomp-00-00"&gt;
+    &lt;extension name="exemplo_1"&gt;
+        &lt;condition field="destination_number" expression="^1234$"&gt;
+            &lt;action application="bridge" data="Khomp/b0L1/2345"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+    &lt;extension name="exemplo_2"&gt;
+        &lt;condition field="destination_number" expression="^23(\d{2})$"&gt;
+            &lt;action application="bridge" data="sofia/${use_profile}/11$1@${sip_from_host}"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<pre>&lt;context name="khomp-00-01"&gt;
+    &lt;extension name="exemplo_3"&gt;
+        &lt;condition field="destination_number" expression="^1111$"&gt;
+            &lt;action application="bridge" data="Khomp/b0L0/2345"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<p>This dialplan defines that:
+</p>
+<ol><li> The incoming calls on the link <b>0</b> of the board <b>0</b> will have the following handling:
+<ul><li> Calls to the extension 1234 for will be redirected to the second link on the first board (b0L1), calling number <b>2345</b>;
+</li><li> Calls to any four digit number starting with<b>23</b> will be redirected to SIP phones numbered <b>11</b> plus the last two digits of the number dialed.
+</li></ul>
+</li><li> The incoming calls on the link <b>1</b> of the board <b>0</b> for the number <b>1111</b> will be redirected to the first link of the first board (b0L0) calling number <b>2345</b>.
+</li></ol>
+<a name="Contexts_of_FXS.2FFXO.2FGSM_channels" id="Contexts_of_FXS.2FFXO.2FGSM_channels"></a><h3> <span class="mw-headline"> Contexts of FXS/FXO/GSM channels </span></h3>
+<p>Just as in the context of E1 cards, inbound links are forwarded to the Endpoint FreeSwitch. However, these signals have two pre-defined contexts, sought with a preference order.
+</p><p>The first context is pre-defined as follows, according to the file <b>khomp.conf.xml</b>:
+</p>
+<pre>&lt;param name="context-gsm" value="khomp-DD-CC"/&gt;&nbsp;;placas GSM
+</pre>
+<pre>&lt;param name="context-fxs" value="khomp-DD-CC"/&gt;&nbsp;; placas FXS
+</pre>
+<pre>&lt;param name="context-fxo" value="khomp-DD-CC"/&gt;&nbsp;; placas FXO
+</pre>
+<p>There is also an alternative context, which has the following default value:
+</p>
+<pre>&lt;param name="context-gsm-alt" value="khomp-DD"/&gt;&nbsp;; placas GSM
+</pre>
+<pre>&lt;param name="context-fxs-alt" value="khomp-DD"/&gt;&nbsp;; placas FXS
+</pre>
+<pre>&lt;param name="context-fxo-alt" value="khomp-DD"/&gt;&nbsp;; placas FXO
+</pre>
+<p>For these options, <b>DD</b> is the device number (two digits), and <b>CC</b> is the channel number (also two digits). There is also the <b>SSSS</b> format, which represents the serial number board.
+</p>
+<ul><li><b>NOTE</b>: In the <b>KGSM</b> board, incoming calls are <b>always</b> redirected to the <b>"s"</b> extension, since the GSM protocol does not identify the target number, only the originator - if not omitted.
+</li></ul>
+<a name="Priority_settings_on_the_FXS_branches" id="Priority_settings_on_the_FXS_branches"></a><h4> <span class="mw-headline"> Priority settings on the FXS branches </span></h4>
+<p>On calls originated from an FXS branch, the Endpoint searches for a valid extension in three different contexts. The priority of contexts is as follows:
+</p>
+<ol><li> Branch-specific extension, defined in section <b>&lt;fxs-options&gt;</b> of file <b>khomp.conf.xml</b>;
+</li><li> Context defined in <b>context-fxs</b>;
+</li><li> Context defined in <b>context-fxs-alt</b>.
+</li></ol>
+<p>If no valid extension can be found, the extension <b>i</b> is searched in the contexts above, and also in the <b>default</b> context. If the dialing timeout is reached (option <b>fxs-digit-timeout</b>), the search will consider all digits dialed until the timeout; if no extension is found, it will search extension "t"; if nothing is found again, then extension "i" will be searched; if no extension is found, "fast-busy" cadence will be played.
+<br />
+</p>
+<a name="Contexts_for_SMS_messages_.28GSM_only.29" id="Contexts_for_SMS_messages_.28GSM_only.29"></a><h3> <span class="mw-headline"> Contexts for SMS messages (GSM only) </span></h3>
+<p>SMS messages are received by the Khomp <i>Endpoint</i> and forwarded to FreeSWITCH as a normal connection but no audio, which has some variables set with information received in the message - for more information on these variables, see the documentation of the variables of the <i>Endpoint</i>. This context can also be modified in the same way as the above contexts.
+</p><p>The default value for this option follows (<b>khomp.conf.xml</b>):
+</p>
+<pre>&lt;param name="context-gsm-sms" value="khomp-sms-DD-CC"/&gt; 
+</pre>
+<p>Where <b>DD</b> is the device number (two digits), and <b>CC</b> is the channel number (also with two digits). For example:
+</p>
+<pre>&lt;context name="khomp-sms-00-01"&gt;
+    &lt;extension name="sms"&gt;
+        &lt;condition field="destination_number" expression="^s$"&gt;
+            &lt;action application="log" data="DEBUG KSmsType=${KSmsType}"/&gt;
+            &lt;action application="log" data="DEBUG KSmsBody=${KSmsBody}"/&gt;
+        &lt;/condition&gt;
+    &lt;/extension&gt;
+&lt;/context&gt;
+</pre>
+<a name="Contexts_for_Khomp_PR_channels_.28KPR.29" id="Contexts_for_Khomp_PR_channels_.28KPR.29"></a><h3> <span class="mw-headline"> Contexts for Khomp_PR channels (KPR) </span></h3>
+<p>For these cards, inbound links have a pre-defined context, as shown below:
+</p>
+<pre>&lt;param name="context-pr" value="khomp-DD-CC"/&gt; 
+</pre>
+<p>In this case, <b>DD</b> is the device number (two digits), and<b>CC</b> is the channel number (also two digits). The name and format of this context can also be changed through the "context-pr" in the configuration file.
+<br />
+<br />
+</p>
+<a name="Using_the_bridge_application" id="Using_the_bridge_application"></a><h3> <span class="mw-headline"> Using the <i>bridge</i> application </span></h3>
+<p>The <b>bridge</b> application is responsible for generating calls from the FreeSWITCH from a dialplan. This application can be used to generate calls from different Endpoints technologies, following a specific format to define destination, dialing options and define the communication <i>Endpoint</i> to be used.
+</p>
+<a name="Fields_relating_to_the_Khomp_Endpoint" id="Fields_relating_to_the_Khomp_Endpoint"></a><h4> <span class="mw-headline"> Fields relating to the Khomp <i>Endpoint</i> </span></h4>
+<p>When used for <b>Khomp</b> channels, the <i>bridge</i> <i>string</i> can have two, three or four fields separated by slash (/). Some example strings:
+<!-- NEED 11 -->
+</p>
+<pre>&lt;action application="bridge" data="Khomp/B2L0/32625644"/&gt;
+&lt;action application="bridge" data="Khomp/*B2L0/32625644"/&gt;
+&lt;action application="bridge" data="Khomp/S0411/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/Gpstn/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/*Gpstn/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/B2C58/32625644/category=4:orig=4855553232"/&gt;
+&lt;action application="bridge" data="Khomp/b0c9"/&gt;
+&lt;action application="bridge" data="Khomp/b0c1+b0c14"/&gt;
+&lt;action application="bridge" data="Khomp/r304"/&gt;
+</pre>
+<p>In the first five examples, three fields have been specified; in the sixth, four fields are used; in the last three examples, just two are used.
+</p><p>The fields description for the Khomp Endpoint:
+</p>
+<ul><li><b>1st</b> field: <b>Khomp</b>: identifying the type of <i>Endpoint</i> in question;
+</li><li><b>2nd</b> field: <b>B2L0</b>, <b>S0411</b>, <b>Gpstn</b>, etc: represents the <b>Policy for channel allocation</b> (detailed below);
+</li><li><b>3rd</b> field: <b>32625644</b> and <b>99991234</b>: the destination numbers (missing for calls to <b> KFXS</b> channels);
+</li><li><b>4th</b> field: <b>category=4:orig=4855553232</b>: additional options, detailed below.
+</li></ul>
+<p>NOTE: The <i>bridge</i> allocation string with only two fields is specific to the KFXS boards, where the destination is the channel itself.
+</p>
+<a name="Policy_for_channel_allocation" id="Policy_for_channel_allocation"></a><h4> <span class="mw-headline"> Policy for channel allocation </span></h4>
+<p>The policy for allocation of channels on the <b>Khomp</b> Endpoint can be specified in the <b>bridge</b> string itself or in the <b>groups</b> section (inside the configuration file <b>khomp.conx.conf</b>). To specify boards, links and channels, the following syntax is available (considering X, Y and Z as any numbers):
+</p>
+<ul><li> b<b>X</b> -- search the channels on the board <b>X</b>, ascending order;
+</li><li> b<b>X</b>L<b>Y</b> -- search channel on the link <b>Y</b> from <b>X</b> board, ascending order;
+</li><li> b<b>X</b>c<b>Y</b> -- try to allocate channel <b>Y</b> from board <b>X</b>;
+</li><li> b<b>X</b>c<b>Y</b>-<b>Z</b> -- search for channels starting from channel <b>Y</b> to channel <b>Z</b> (inclusive) of board <b>X</b>, ascending order;
+</li><li> B<b>X</b>c<b>Y</b>-<b>Z</b> -- same as above, but descending order;
+</li><li> s<b>X</b> -- search the channels on the board of serial number <b>X</b>, ascending order;
+</li><li> s<b>X</b>L<b>Y</b> -- search channel on the link <b>Y</b> from board of serial number <b>X</b>, ascending order;
+</li><li> s<b>X</b>c<b>Y</b> -- try to allocate channel <b>Y</b> from board of serial number <b>X</b>;
+</li><li> s<b>X</b>c<b>Y</b>-<b>Z</b> -- search for channels starting from channel <b>Y</b> to channel <b>Z</b> (inclusive) from board of serial number <b>X</b>, ascending order;
+</li><li> S<b>X</b>c<b>Y</b>-<b>Z</b>-- same as above, but descending order.
+</li></ul>
+<p>To search for extensions of cards<b>KFXS</b> according to the extension number, can be used the following syntax (whereas X and Y valid extension numbers):
+</p>
+<ul><li> r<b>X</b>- search branch numbered <b>X</b>;
+</li><li> R<b>X</b>- equivalent to the above;
+</li><li> r<b>X</b>-<b>Y</b>- search from branch <b>X</b> to <b>Y</b>, ascending order;
+</li><li> R<b>X</b>-<b>Y</b>- search from branch <b>X</b> to <b>Y</b>, descending order.
+</li></ul>
+<p>The capitalization of the letter 'B', 'S' or 'R' defines the search order of the channels: if capitalized, order is descending; otherwise, ascending.
+</p><p>As for the allocation of channels across groups, the following syntax is available:
+</p>
+<ul><li> ggroupname - uses the string defined the group "groupname" in the configuration file (detailed in the configuration section of the Endpoint).
+</li><li> Ggroupname - equivalent to the above.
+</li></ul>
+<a name="Grouping_channel_allocations" id="Grouping_channel_allocations"></a><h3> <span class="mw-headline"> Grouping channel allocations </span></h3>
+<p>There are cases where you need to get more channels for a particular device or particular group of extensions. For this, there is an extension available in string allocation, with respect to the use of token sum (<b>+</b>) to concatenate multiple strings<i>binding</i>, as follows:
+<!-- NEED 6 --> 
+</p>
+<pre>&lt;action application="bridge" data="Khomp/B1L0+B2L0/32332933"/&gt;
+&lt;action application="bridge" data="Khomp/*B2+B3+B4/99887766"/&gt;
+&lt;action application="bridge" data="Khomp/S0411+B1L0/99887766"/&gt;
+&lt;action application="bridge" data="Khomp/Gpstn1+Gpstn2/99991234"/&gt;
+&lt;action application="bridge" data="Khomp/*gOperadora1+gOperadora2/98891234"/&gt;
+</pre>
+<p>This grouping is available for the <i>application</i> <b>bridge</b> and on the specification of groups. The processing of allocation takes place from left to right - except when using cyclic channel allocation, where<b>all</b> the specified channels are scanned simultaneously.
+</p>
+<a name="Cyclical_and.2For_fair_allocation" id="Cyclical_and.2For_fair_allocation"></a><h4> <span class="mw-headline"> Cyclical and/or <i>fair</i> allocation </span></h4>
+<p>Another way for allocation of channels is the cyclic and/or <i>fair</i> allocation, which chooses the channel that has <b>completed</b> the the lowest number of <b>outgoing</b> calls. This mode of allocation may be used by passing an asterisk (<b>*</b>) before the allocation string of channels (as can be seen in the section above, in the second and fifth examples).
+</p><p>When started with an asterisk (<b>*</b>), other forms of allocation (increasing, decreasing, etc) are used to decide what channel will be allocated when there are two or more channels with less number of outgoing calls.
+</p>
+<ul><li><b>WARNING: The use of fair and/or cyclic is recommended <u>only</u> for analog (KFXO), branches (KFXS) and cellular interface (KGSM) boards</b>. E1 connections should allocate channels in one way (ascending/descending) from one side and the opposite on the other to avoid problems of double seizure (which may occur in R2/MFC signaling). Fair/cyclic allocation also costs more in memory and processor footprint, which tends to be a higher cost in E1 due to the higher number of channels (30 in each link).<br /><br /> For these reasons, fair/cyclic allocations should only be used on signalizations where it can represent any real difference, like equalizing the charge costs of the lines, the total usage, or the number of connections received by each branch.
+</li></ul>
+<a name="Available_options" id="Available_options"></a><h4> <span class="mw-headline"> Available options </span></h4>
+<ul><li><b>orig</b>: Sets the originator number, <b>without changing the variable ${CALLERID(num)}</b>. That is, the option <b>orig</b> serves <b>only</b> to pass a number of different source of${origination_caller_id_number}. If FreeSWITCH has already set the variable ${origination_caller_id_number}, which is the default behavior, Endpoint automatically uses this value as a reference to the number of origin, without having to pass any additional options.<br /><br />On the boards <b>KGSM</b>, is set to <b>restricted</b>, omits the number of origin. Example:<br />
+</li></ul>
+<pre>
+ &lt;action application=&quot;bridge&quot; data=&quot;Khomp/b0/99887766/orig=restricted&quot;/&gt;
+</pre>
+<ul><li><b>category</b>: When set to a numeric value, sets the category of outgoing call to this value (available only in R2/MFC signaling);
+</li><li><b>uui</b>: When adjusted for a number and a string of text, separated by hash ("#"), sends a "UserToUser" to the other end before making the call - the first value will be the descriptor and the second one will be the message as the text (available only in ISDN signaling);
+</li><li><b>ring_cadence</b>: When set to a cadence name (listed in the <b>[cadences]</b> section), uses this for ringing FXS channels;
+</li><li><b>ring</b>: When set to two numbers separated by a dot ("."), defines the cadences to be used while ringing a FXS channel - the first time is the ringing time, and the second one, the silence time;
+</li><li><b>ring_ext</b>: When set to two numbers separated by a dot ("."), defines the extended cadences to be used while ringing a FXS channel, executed after the <b>ring</b> specification - the first time 
+</li><li><b>usr_xfer</b>: Defines a group of DTMF digits to initiate a transfer between PBXes (using QSig or FXO FLASH, for instance);
+</li><li><b>drop_on</b>: When set to "message_box", "human_answer", "answering_machine", "carrier_message", "unknown" or a list them - separated by plus sign ("+") or dot ("." ) - drops the call when detect voice mail box, human answer, answering machine messages, operator messages, or unknown answer pattern - respectively. Available in digital signals (E1 links and boards KGSM). Additionally, the information service is reported to the user in the variable<b>KCallAnswerInfo</b>;
+</li><li><b>answer_info</b>: When specified (take no parameters), report answer information to the user through the variable<b>KCallAnswerInfo</b>
+</li><li><b>pre</b>: When set to a string of DTMF digits, uses these to pre-allocate an output channel in an analog PABX, dial the desired number of B below. Only available for signaling analog (FXO);
+</li><li><b>pre_answer</b>: When set (need no value), answers the channel before the connection is completed - allowing, for instance, DTMF tones to sent (useful for use in a <b>DISA</b>);
+</li><li><b>output_volume</b>: Sets the output volume of the link (ranges from -10 to +10);
+</li><li><b>input_volume</b>: Sets the volume of inbound link (ranges from -10 to +10);
+</li></ul>
+<p><br />
+</p>
+<a name="List_of_variables" id="List_of_variables"></a><h3> <span class="mw-headline"> List of variables </span></h3>
+<p>Here's a list of variables available in the Endpoint:
+</p>
+<ul><li><b>KDropCollectCall</b>: When set before ringing or answer an incoming call, enables ("yes") or disables ("no", default) the drop of collect calls based on signaling received from the central public, double answer, audio tone recognition (can be defined globally);
+</li><li><b>KR2SendCondition</b>: When set to a numeric value, before the ringing an incoming call, adjusts the condition for this Endpoint to this value (available only on R2 signaling);
+</li><li><b>KR2GotCategory</b>: Adjusted by the Endpoint when an incoming call is received, with the category number of the caller (only available on R2 signaling);
+</li><li><b>KR2GotCondition *</b>: Adjusted by the Endpoint, available after returning from a call made by FreeSWITCH (<b>bridge</b> application). Has the condition of the remote end received when making the call (available only for R2 signaling);
+</li><li><b>KISDNGotCause *</b>: Adjusted by the Endpoint, available after returning from a call made by FreeSWITCH (<b>bridge</b> application). Has the ISDN "cause" code received when making the call (available only for ISDN signaling);
+</li><li><b>KCallAnswerInfo *</b>: Adjusted by the Endpoint, available after returning from a call made by FreeSWITCH (<b>bridge</b> application). Contains the service information identified to make the call (available only for digital signaling - E1 and GSM);
+</li><li><b>KSmsDelivered</b>: Adjusted by the Endpoint when sending a SMS message with the application <b>KSendSMS</b>, saying whether the message was delivered successfully ("yes") or not ("no");
+</li><li><b>KSmsErrorCode</b>: Adjusted by the Endpoint when sending a SMS message with the application <b>KSendSMS</b>, containing the error code that happened when sending the message;
+</li><li><b>KSmsErrorName</b>: Adjusted by the Endpoint when sending a SMS message with the application <b>KSendSMS</b>, contains the name of the error or "None" if there has been no error;
+</li><li><b>KSmsType</b>: Adjusted for the input Endpoint in the context of SMS messages, defines the type of message received (can contain the values "message", "confirm" or "broadcast";
+</li><li><b>KSmsFrom</b>: Adjusted for the input Endpoint in the context of SMS messages, sets the number of origin of the received message (available on types" message "and" confirm ");
+</li><li><b>KSmsDate</b>: Adjusted for the input Endpoint in the context of SMS messages, sets the date of sending the message (available on types "message" and "confirm");
+</li><li><b>KSmsSize</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the size (in bytes) of the received message (available on types "message" and "broadcast");
+</li><li><b>KSmsMode</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the encoding type of the received message (available on types "message" and "broadcast");
+</li><li><b>KSmsBody</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the text of the received message (available in types "message" and "broadcast");
+</li><li><b>KSmsDelivery</b>: Adjusted for the input Endpoint in the context of SMS messages, containing the date of delivery of the message sent earlier (available in type "confirm");
+</li><li><b>KSmsStatus</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the status of the message sent earlier (available on the type "confirm");
+</li><li><b>KSmsSerial</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the serial number of the received message (available on the type "broadcast");
+</li><li><b>KSmsPage</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the page number of the received message (available on the type broadcast");
+</li><li><b>KSmsPages</b>: Adjusted for the input Endpoint in the context of SMS messages, contains the total number of pages to be received (available in type "broadcast");
+</li><li><b>KUserInfoDescriptor</b>: Sets/reports protocol descriptor of the User-to-User Information message (ISDN).
+</li><li><b>KUserInfoData</b>: Sets/reports data in the User-to-User Information message (ISDN).
+</li><li><b>KFaxSent</b>: Adjusted by the Endpoint when sending FAX with <b>KSendFax</b> application, and determines whether the fax was successfully sent ("yes") or not ("No");
+</li><li><b>KFaxReceived</b>: Adjusted by channel when receiving FAX with <b>KReceiveFax</b> application, and determines whether the fax was successfully received ("yes") or not ("no");
+</li><li><b>KFaxResult</b>: Adjusted by the channel when sending or receiving FAX with the application <b>KSendFax</b> or <b>KReceiveFax</b> (respectively), and defines the result of execution.
+</li></ul>
+<p><br />
+</p>
+<a name="Description_of_variables" id="Description_of_variables"></a><h3> <span class="mw-headline"> Description of variables </span></h3>
+<p>Below, follows an explanation on how to use variables of Khomp Endpoint in the dialplan, to communicate and/or to receive information:
+</p><p><br />
+</p>
+<a name="KDropCollectCall" id="KDropCollectCall"></a><h4> <span class="mw-headline"> KDropCollectCall </span></h4>
+<p>When activated, causes the Endpoint to drop Khomp collect calls through dual service (available for signaling 'R2 Digital' and FXO), through information available on the ISDN protocol and R2/MFC, or by detecting the audio call collect (available for any digital signage for E1, and GSM signaling).
+</p><p>This variable is useful to filter collect calls to certain extensions, and <b>must</b> be set before making any type of answer - applications such as <b>playback</b> and <b>bridge</b> should always be executed after setting this variable, for example.
+</p><p>For better functionality, is also recommended that no call status (<i>ringback</i>) is sent before this variable is set, so applications should be performed only after the correct setting of this variable.
+</p><p>This variable can be set locally and globally, both to <b>yes</b> or <b>no</b>. The adjustment of global variable to <b>yes</b> will drop all the collect calls, unless the particular call is set to <b>no</b> - this allows the creation of a global filter of collect calls, with few exceptions.
+</p><p>Enabling the variable in context <b>default</b>:
+</p><p><!-- NEED 5 -->
+&lt;context name="default"&gt;
+</p>
+<pre>&lt;extension name="example"&gt;
+ .
+ .
+ .
+ &lt;action aplication="set" data="KDropCollectCall=yes"/&gt;
+ .
+ .
+ .
+&lt;/extension&gt;
+</pre>
+<p>&lt;/context&gt;
+</p><p>Enabling the variable in the global context, remembering that it must be configured in the file <b>vars.xml</b>:
+<!-- NEED 5 --> 
+</p>
+<pre>&lt;X-PRE-PROCESS cmd="set" data="KDropCollectCall=yes"/&gt;
+</pre>
+<a name="KR2SendCondition" id="KR2SendCondition"></a><h4> <span class="mw-headline"> KR2SendCondition </span></h4>
+<p>When you receive a call, can be set before sending ringback by FreeSWITCH (ie, before the run FreeSWITCH applications <b>answer</b>, <b>bridge</b>). When used in signaling R2/MFC, this variable sets the condition for B to the numeric value desired.
+</p><p>Exemplo:
+<!-- NEED 6 --> 
+</p>
+<pre>&lt;!-- Condition "NUMBER CHANGED" warns the caller that the number of B has changed. --&gt;
+&lt;action application="KR2SendCondition" data="3"/&gt;
+</pre>
+<a name="KR2GotCategory" id="KR2GotCategory"></a><h4> <span class="mw-headline"> KR2GotCategory </span></h4>
+<p>When you receive a call, is set by the Endpoint with the category received from the number that originated the call. It is set in signaling R2/MFC, and can be found anywhere in the dialplan.
+</p><p>Example:
+<!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KR2GotCategory [${KR2GotCategory}]"/&gt;
+</pre>
+<a name="KR2GotCondition" id="KR2GotCondition"></a><h4> <span class="mw-headline"> KR2GotCondition </span></h4>
+<p>Variable adjusted by the Endpoint, and available after returning from a call made by FreeSWITCH. Has the condition of B received when making the call. Available only for signaling R2/MFC.
+</p><p>Example:
+<!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KR2GotCondition [${KR2GotCondition}]"/&gt;
+</pre>
+<a name="KUserInfoDescriptor" id="KUserInfoDescriptor"></a><h4> <span class="mw-headline"> KUserInfoDescriptor </span></h4>
+<p>Variable adjusted by the Endpoint in the context of entry, from information received by the ISDN network functionality through user-to-User Information. Contains the descriptor number of the protocol used by the other end, and usually contains the value '0 ', but this is dependent on application.
+</p><p>For further information, consult the specification ITU-T Q931 (more precisely, the specification table 4-26).
+</p><p>Example (working with the descriptor number of the protocol):
+<!-- NEED 3 --> 
+</p>
+<pre>&lt;action application="log" data="DEBUG KUserInfoDescriptor [${KUserInfoDescriptor}]"/&gt;
+</pre>
+<a name="KUserInfoData" id="KUserInfoData"></a><h4> <span class="mw-headline"> KUserInfoData </span></h4>
+<p>Variable adjusted by the channel in the context of entry, from information received by the ISDN network functionality through user-to-User Information. Contains the actual data, which were received in the form of a string of text.
+</p><p>More information about this feature, see the specification ITU-T Q931.
+</p><p>Example (working with the data received):
+<!-- NEED 3 -->
+</p>
+<pre>&lt;action application="log" data="DEBUG KUserInfoData [${KUserInfoData}]"/&gt;
+</pre>
+<p>It is important to note that the variables are sensitive to the capitalization of letters (case sensitive).
+</p>
+<a name="KCallAnswerInfo" id="KCallAnswerInfo"></a><h4> <span class="mw-headline"> KCallAnswerInfo </span></h4>
+<p>Variable adjusted by the Endpoint. It is set in outbound connections, representing the type of answer performed by the other end. May contain the following values:
+</p>
+<dl><dd><ul><li> "MessageBox" (*): detected mailbox of a cell phone;
+</li><li> "CarrierMessage": message sent before the service provider;
+</li><li> "AnsweringMachine" (**): answering answering machine;
+</li><li> "HumanAnswer" (**): human service;
+</li><li> "Fax": reported when a fax tone is detected.
+</li><li> "Unknown": unknown type of care;
+</li></ul>
+</dd></dl>
+<p>(*) This type of service is detected by signals at certain frequencies that are sent before the call comes into a mailbox, and vary by operator. The algorithm captures most of the mailboxes, but can fail if there is not a clear signal, or if it is not within the standards most commonly used;
+</p><p>(**) The difference between these two types of care depends on the specific configuration using the program <b>k3lanswerinfoconfig</b>, with the detection only based on heuristics and <b>never</b> with an accuracy of 100%.
+<br />
+</p>
+<a name="Console_commands" id="Console_commands"></a><h1> <span class="mw-headline"> Console commands </span></h1>
+<p>List of available commands in the console for the FreeSWITCH Endpoint of Khomp:
+</p><p><br />
+</p>
+<ul><li> <b>khomp channels disconnect </b>: Disconnect one or more channels. This command sends a message directly to the physical channel of the card in question, requesting a disconnection. Use with caution;
+</li><li> <b>khomp channels unblock </b>: Unlock blocked channels for input or output. Only available in digital signage via E1;
+</li><li> <b>khomp clear links</b>: Clears error counters on the links;
+</li><li> <b>khomp clear statistics</b>: Clears the statistics of channel connections, or statistics for a particular channel;
+</li><li> <b>khomp get </b>: Gets the number of options Endpoint Khomp;
+</li><li> <b>khomp kommuter </b>: Enables or disables kommuters connected via USB on this machine. Only accessible when the configuration "kommuter-activation" is set to "manual".
+</li><li> <b>khomp kommuter count</b>: Gets the amount of kommuters connected via USB on this machine;
+</li><li> <b>khomp log console</b>: Sets options in the console logs;
+</li><li> <b>khomp log disk</b>: Sets logging options to disk;
+<ul><li> <b>khomp log console</b> and <b>khomp log disk</b> have auxiliary options <b>No</b>, which reverses the selection of messages, and <b>just</b>, which generalizes the choice. Examples:
+<ul><li> <b>khomp log disk just commands events</b> (Enables <b>only</b> logging to the disk of commands and events);
+</li><li> <b>khomp log disk no commands </b> (Disable logging to the disk of commands sent to board);
+</li><li> <b>khomp log disk warnings</b> (Enables also logging to the disk of warnings from Endpoint).
+</li></ul>
+</li><li> More information on options for the <b>log</b> command, type: "<b>help khomp log disk</b>" or "<b>help console log khomp</b>".
+</li></ul>
+</li><li> <b>khomp log rotate</b>: Rotate log files from the Endpoint;
+</li><li> <b>khomp log status</b>: Shows log messages currently being written to disk and displayed on the console;
+</li><li> <b>khomp log trace isdn</b>: Enable Debugging ISDN signaling;
+</li><li> <b>khomp log trace k3l </b>: Enables debugging low-level API K3L;
+</li><li> <b>khomp log trace r2 </b>: Enables debugging low-level signaling R2/MFC;
+</li><li> <b>khomp reset links</b>: Sends a reset command for a specific <b>E1</b> of a particular <i>card</i>; 
+</li><li> <b>khomp revision</b>: Shows version number and revision of the Endpoint;
+</li><li> <b>khomp select sim</b>: Select the SIM card, available on the boards KGSM;
+</li><li> <b>khomp send command </b>: Sends command API K3L directly to the board (only for debugging, may compromise the stability of the system if used improperly);
+</li><li> <b>khomp send raw command </b>: Sends a command directly to the DSP board (only for debugging, may compromise the stability of the system if used improperly);
+</li><li> <b>khomp set </b>: Sets various options of the Endpoint Khomp;
+</li><li> <b>khomp show calls </b>: Shows states for calls, may also listing specific channels or boards;
+</li><li> <b>khomp show channels </b>: Shows the status of the channels Khomp and may also list specific adapter; 
+</li><li> <b>khomp show links</b>: Display states of E1 links available. 
+</li><li> <b>khomp show statistics </b>: Shows the statistics of channel connections, or statistics for a particular channel;
+</li><li> <b>khomp sms </b>: Send an SMS message for a given number, using KGSM channels;
+</li><li> <b>khomp summary </b>: Prints a summary of system boards and their features;
+</li></ul>
+<p><br />
+</p>
+<a name="Additional_features" id="Additional_features"></a><h1> <span class="mw-headline"> Additional features </span></h1>
+<p>This chapter discusses additional features of the Endpoint, related to the special features present in certain signs.
+<br />
+</p>
+<a name="Aplica.C3.A7.C3.B5es_.28applications.29_e_canais" id="Aplica.C3.A7.C3.B5es_.28applications.29_e_canais"></a><h2> <span class="mw-headline">Aplicações (applications) e canais  </span></h2>
+<p>The Endpoint Khomp, and to record a type of communication channel "Khomp" also records the following items:
+<br />
+</p>
+<a name=".22KUserTransfer.22_application" id=".22KUserTransfer.22_application"></a><h3> <span class="mw-headline"> "KUserTransfer" application </span></h3>
+<p>Performs the transfer process from the current channel <i>number</i> for the extension using the signaling protocol QSig (Single Step Call Transfer) for boards configured with E1 ISDN signaling (ISDN), or use the FLASH command for FXO.
+</p><p>The syntax follows:
+</p>
+<pre> &lt;action application="KUserTransfer" data="<b>number</b>[,options])"/&gt;
+</pre>
+<p>Example:
+</p>
+<pre>&lt;action application="answer"/&gt;
+&lt;action application="KUserTransfer" data="2345"/&gt;
+</pre>
+<p>The fields have the following meanings:
+</p>
+<ul><li><b>number</b>: Number where the link should be transferred.
+</li><li><b>options</b>: Sets the transfer options to be used, which are:
+<ul><li><b> N</b>: Wait until the channel is disconnected.
+</li></ul>
+</li></ul>
+<p><br />
+</p>
+<a name="Application_.22KSendSMS.22" id="Application_.22KSendSMS.22"></a><h3> <span class="mw-headline"> Application "KSendSMS" </span></h3>
+<p>This application has the function of sending SMS messages through the boards of KGSM Khomp using modules and SIM cards in the board to do so. The syntax of the application is as follows:
+</p>
+<pre>&lt;action application="KSendSMS" data="resource | destination | message" /&gt;
+</pre>
+<p>Each field can be summarized in:
+</p>
+<ul><li><b>resource</b>: The following is a syntax identical to the allocation of channels Dial application, and defines what modem use;
+</li><li><b>destination</b>: Number where to send the message, may be preceded or succeeded by<b>!</b> to request a confirmation of transmission;
+</li><li><b>message</b>: Text (without quotes) to be sent to<b>destination</b>.
+</li></ul>
+<p>After sending the message, the variables <b>KSmsDelivered</b> and <b>KSmsErrorCode</b> will contain the result of the post. For more information about these, please consult the section on variables used in the Endpoint.
+</p><p>Examples of use of this application are as follows:
+</p>
+<ul><li> Sends "Test message." phone for "99887766" using the modem "1" (second modem) card "0":
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Sending SMS ..." /&gt;
+&lt;action application="KSendSMS" data="b0c1|99887766|Test message" /&gt;
+</pre>
+<ul><li> Sends "Test message." phone for "99887766" using the first free modem card "0", and checks the return shipment:
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG  Sending SMS ..." /&gt;
+&lt;action application="KSendSMS" data="b0|99887766|Test message" /&gt;
+&lt;action application="log" data="DEBUG Sent? ${KSmsDelivered}" /&gt;
+&lt;action application="log" data="DEBUG Code: ${KSmsErrorCode}" /&gt;
+&lt;action application="log" data="DEBUG Desc: ${KSmsErrorName}" /&gt;
+</pre>
+<ul><li> Sends "Test message." phone for "99887766" using the first free modem card "0", or the first free channel board "1" (if no free channel at the first sign):
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Sending SMS ..." /&gt;
+&lt;action application="KSendSMS" data="b0+b1|99887766|Test message" /&gt;
+</pre>
+<ul><li> Sends "Test message." phone for "99887766" using the first free modem card "0", requesting confirmation:
+</li></ul>
+<pre>&lt;action application="log" data="DEBUG Sending SMS ..." /&gt;
+&lt;action application="KSendSMS" data="b0|99887766!|Test message" /&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KEchoCanceller.22" id="Application_.22KEchoCanceller.22"></a><h3> <span class="mw-headline"> Application "KEchoCanceller" </span></h3>
+<p>This application has the function to enable or disable the echo canceller channel.
+</p>
+<pre>&lt;action application="KEchoCanceller" data="<b>action</b>[,options])"/&gt;
+</pre>
+<p>Where:
+</p>
+<ul><li><b>actions</b>: It is <b>on</b> to enable the echo canceller, and <b>off</b> to disable;
+</li></ul>
+<p>Example usage of this application:
+</p>
+<pre>&lt;action application="KEchoCanceller" data="off"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KAutoGainControl.22" id="Application_.22KAutoGainControl.22"></a><h3> <span class="mw-headline"> Application "KAutoGainControl" </span></h3>
+<p>This application has the function to enable or disable the automatic gain control in the channel.
+</p>
+<pre>&lt;action application="KAutoGainControl" data="<b>action</b>[,options])"/&gt;
+</pre>
+<p>Where:
+</p>
+<ul><li><b>actions</b>: It is <b>on</b> to enable the automatic gain control, and <b>off</b> to disable;
+</li></ul>
+<p>Example usage of this application:
+</p>
+<pre>  &lt;action application="KAutoGainControl" data="on"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KDTMFSuppression.22" id="Application_.22KDTMFSuppression.22"></a><h3> <span class="mw-headline"> Application "KDTMFSuppression" </span></h3>
+<p>This application has the function to enable or disable the suppression of DTMF channel. The syntax of the application is as follows:
+</p>
+<pre>&lt;action applicatin="KDTMFSuppression" value="<b>action</b>[,options])"/&gt;
+</pre>
+<p>Where:
+</p>
+<ul><li><b>actions</b>: It is<b>on</b> to enable DTMF suppression, and <b>off</b> to disable;
+</li></ul>
+<p>It is important to note that when disabled suppression of DTMF, DTMF tones are passed inband <i>and</i> will not be reported to FreeSWITCH. Thus FreeSWITCH does not recognize the DTMF tones, which may result in malfunction of applications such as IVR.
+</p><p>Example usage of this application:
+</p>
+<pre>&lt;action applicatin="KDTMFSuppression" value="off"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KSetVolume.22" id="Application_.22KSetVolume.22"></a><h3> <span class="mw-headline"> Application "KSetVolume" </span></h3>
+<p>This application has the function to adjust the volume of incoming and outgoing channels Khomp, and its syntax as follows:
+</p>
+<pre>&lt;action application="KSetVolume" data="&lt;volume&gt;"/&gt;
+&lt;action application="KSetVolume" data="&lt;output-volume&gt;|&lt;input-volume&gt;"/&gt;
+</pre>
+<p>Where the fields have the following meanings:
+</p>
+<ul><li><b>volume</b>: Sets the volume of input and output (-10 to +10);
+</li><li><b>output-volume</b>: Sets the output volume (-10 to +10, "none" for no change);
+</li><li><b>input-volume</b>: Sets the input level (-10 to +10, "none" for no change).
+</li></ul>
+<p><br />
+</p>
+<a name="Application_.22KAdjustForFax.22" id="Application_.22KAdjustForFax.22"></a><h3> <span class="mw-headline"> Application "KAdjustForFax" </span></h3>
+<p>This application has the function of setting a channel for receiving Khomp signal FAX/modem, optimizing the communication channel for data traffic. Syntax:
+</p>
+<pre>&lt;action application="KAdjustForFax" data=""/&gt;
+</pre>
+<p>This application does not receive parameters. Example of use:
+</p>
+<pre>&lt;action application="KAdjustForFax" data=""/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KSendFax.22" id="Application_.22KSendFax.22"></a><h3> <span class="mw-headline"> Application "KSendFax" </span></h3>
+<p>This application has the function to send faxes using digital channels or FXO connections Khomp in pre-established, and its syntax as follows:
+</p>
+<pre>&lt;action application="KSendFax" data="&lt;file&gt;[:&lt;file2&gt;[:...]][|&lt;faxid&gt;]"/&gt;
+</pre>
+<p><strong>This application requires a license purchased separately to be used in digital (non-FXO) channels</strong>. Fields have the following meanings:
+</p>
+<ul><li><b>file</b>: Files to be sent to the fax should be encapsulated in TIFF format and have a resolution of 98, 196 or 392 dpi;
+</li><li><b>faxid</b>: the fax number. If not specified, the value is obtained by the id of the link, and if this also is not valid, the fax number will be set as default in K3L.
+</li></ul>
+<p>Example usage of this application:
+</p>
+<pre>&lt;action application="KSendFax" data="/tmp/fax.tif:/home/root/fax2.tif,1234"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Application_.22KReceiveFax.22" id="Application_.22KReceiveFax.22"></a><h3> <span class="mw-headline"> Application "KReceiveFax" </span></h3>
+<p>This application has the function of receiving digital channels or fax using the FXO Khomp, and its syntax as follows:
+</p>
+<pre>&lt;action application="KReceiveFax" data="&lt;file&gt;[|&lt;faxid&gt;]/&gt;
+</pre>
+<p><strong>This application requires a license purchased separately to be used in digital (non-FXO) channels</strong>. Fields have the following meanings:
+</p>
+<ul><li><b>file</b>: Name that file will be assigned to incoming fax.
+</li><li><b>faxid</b>: the fax number. If not specified, the value is obtained by the id of the link, and if this also is not valid, the fax number will be set as default in K3L.
+</li></ul>
+<p>Example usage of this application:
+</p>
+<pre>&lt;action application="answer" /&gt;
+&lt;action application="KReceiveFax" data="/tmp/fax.tif"/&gt;
+</pre>
+<p><br />
+</p>
+<a name="Channel_.22Khomp_SMS.22" id="Channel_.22Khomp_SMS.22"></a><h3> <span class="mw-headline"> Channel "Khomp_SMS" </span></h3>
+<p>This communication channel is used to receive SMS and create incoming links in FreeSWITCH for each message received. This channel does not have any treatment or audio processing, and is called with five variables set:
+</p>
+<ul><li><b>KSmsFrom</b>, containing the number of source who sent the message;
+</li><li><b>KSmsDate</b>, which sets the date/time of receipt of the message;
+</li><li><b>KSmsSize</b>, representing the message size (in bytes);
+</li><li><b>KSmsMode</b>, containing the encoding used to transmit the message;
+</li><li><b>KSmsBody</b>, that is the message itself.
+</li></ul>
+<p>The FreeSWITCH dialplan processing can be used to store this message in a database, run any application, among others. However, the only action accepted by this channel is shutdown (Hangup), so this incoming call should be considered a special dialplan execution without audio streams or channel allocation.
+<br />
+</p>
+<a name="Channel_.22Khomp_PR.22" id="Channel_.22Khomp_PR.22"></a><h3> <span class="mw-headline"> Channel "Khomp_PR" </span></h3>
+<p>This communication channel is used to receive calls on boards passive recording (<b>KPR family</b> and <b>KFXO-HI</b>), creating incoming links on FreeSWITCH for each incoming call. This channel allows only receiving audio captured the <i>link</i>by not allowing both the transmission of audio signalings as the control.
+</p><p>The FreeSWITCH dialplan processing can be used to record data on this link in a database, perform some special application and/or some recording application (such as <b>record</b>), among others. However, the only action accepted by this channel is shutdown (Hangup), so this should not be considered a common call.
+<br />
+</p>
+<a name="Codes_and_meanings" id="Codes_and_meanings"></a><h1> <span class="mw-headline"> Codes and meanings </span></h1>
+<p>This chapter presents the codes present in the channel Khomp and their meanings, used in both events as in the AMI console commands:
+<br />
+</p>
+<a name="Channel_state" id="Channel_state"></a><h2> <span class="mw-headline"> Channel state </span></h2>
+<p>Reflect the state of the channel on the board. In the case of E1 links, the state may have one or more of the following:
+</p>
+<ul><li><b>Free</b>: the channel is free;
+</li><li><b>Busy</b>: the channel is not free (or occupied, or failure);
+</li><li><b>Outgoing</b>: the channel has an output connection;
+</li><li><b>Incoming</b>: the channel has an input connection;
+</li><li><b>Locked</b>: the channel is blocked;
+</li><li><b>Outgoing Lock</b>: The channel is blocked for outgoing calls;
+</li><li><b>Local Fail</b>: The channel has a fault (at this point);
+</li><li><b>Incoming Lock</b>: the channel is blocked for incoming calls;
+</li><li><b>Remote Lock</b>: there is a remote lock (at the other end) in this channel.
+</li></ul>
+<p>In the case of a FXS channel, the state is defined by one of these values:
+</p>
+<ul><li><b>On Hook</b>: the phone connected to this channel is on-hook or disconnected;
+</li><li><b>Off Hook</b>: the phone connected to this channel is off the hook;
+</li><li><b>Ringing</b>: the channel is being called;
+</li><li><b>Failure</b>: the channel is in failure due to communication problems between the central and the plate.
+</li></ul>
+<p>In the case of a GSM channel, the state is defined by one of the following values:
+</p>
+<ul><li><b>Idle</b>: the channel is free and available for calls;
+</li><li><b>Call In Progress</b>: the channel is busy on a call;
+</li><li><b>SMS In Progress</b>: the channel is busy sending / receiving SMS messages;
+</li><li><b>Modem Error</b>: an error occurred communicating with the modem channel;
+</li><li><b>SIM Card Error</b>: The SIM card is not present or is not inserted / detected correctly;
+</li><li><b>Network Error</b>: an error occurred while communicating with the network;
+</li><li><b>Not Ready</b>: The modem is initializing the channel.
+</li></ul>
+<p>And in the case of an FXO channel, the states are as follows:
+</p>
+<ul><li><b>Disabled</b>: the channel is disabled;
+</li><li><b>Enabled</b>: the channel is enabled.
+</li></ul>
+<p><br />
+</p>
+<a name="Call_state" id="Call_state"></a><h2> <span class="mw-headline"> Call state </span></h2>
+<p>Defines the logical state for each channel, which can be:
+</p>
+<ul><li><b>Free</b>: the channel is free;
+</li><li><b>Incoming</b>: the channel is receiving a call;
+</li><li><b>Outgoing</b>: the channel is making a call;
+</li><li><b>Failure</b>: the channel is in fault.
+</li></ul>
+<p><br />
+</p>
+<a name="FreeSWITCH_call_states" id="FreeSWITCH_call_states"></a><h2> <span class="mw-headline"> FreeSWITCH call states </span></h2>
+<p>Directly reflects the call state controlled by FreeSWITCH, which can be:
+</p><p><br />
+</p>
+<ul><li> <b>new</b>: Channel is newly created;
+</li><li> <b>init</b>: Channel has been initialized;
+</li><li> <b>routing</b>: Channel is looking for an extension to execute;
+</li><li> <b>execute</b>: Channel is executing its dialplan;
+</li><li> <b>ex_media</b>: Channel is exchanging media with another channel;
+</li><li> <b>cs_media</b>: Channel is consuming all media;
+</li><li> <b>hangup</b>: Channel is flagged for hangup and ready to end.
+</li></ul>
+<p><br />
+</p>
+<a name="GSM_Codes" id="GSM_Codes"></a><h2> <span class="mw-headline"> GSM Codes </span></h2>
+<p>The following numeric codes are reported:
+</p>
+<a name="SMS_codes_.28SMS_causes.29" id="SMS_codes_.28SMS_causes.29"></a><h3> <span class="mw-headline"> SMS codes (SMS causes) </span></h3>
+<pre>1 Unassigned number
+8      Operator determined barring
+10     Call barred
+21     SMS transfer rejected
+27     Destination out of service
+28     Unidentified subscriber
+29     Facility rejected
+30     Unknown subscriber
+38     Network out of order
+41     Temporary failure
+42     Congestion
+47     Resources unavailable
+50     Facility not subscribed
+69     Facility not implemented
+81     Invalid SMS transfer reference value
+95     Invalid message
+96     Invalid mandatory information
+97     Message type non existent
+98     Message not compatible with SMS protection state
+99     Information element non existent
+111    Protocol error
+127    Interworking
+128    Telematic interworking not supported
+129    SMS type zero not supported
+130    Cannot replace SMS
+143    Unspecified TPPID error
+144    Alphabet not supported
+145    Message class not supported
+159    Unspecified TPDCS error
+160    Command cannot be actioned
+161    Command unsupported
+175    Unspecified TP command error
+176    TPDU not supported
+192    SC busy
+193    No SC subscription
+194    SC system failure
+195    Invalid SME address
+196    Destination SME barred
+197    SM rejected duplicate SM
+198    TPVPF not supported
+199    TPVP not supported
+208    SIM SMS storage full
+209    No SMS storage capability in SIM
+210    Error in SMS
+211    Memory capatity exceeded
+213    SIM data download error
+255    Unspecified error
+300    Phone failure
+301    SMS service reserved
+302    Operation not allowed
+303    Operation not supported
+304    Invalid PDU mode parameter
+305    Invalid text mode parameter
+310    SIM not inserted
+311    SIM PIN necessary
+312    Phone SIM PIN necessary
+313    SIM failure
+314    SIM busy
+315    SIM wrong
+320    Memory failure
+321    Invalid memory index
+322    Memory full
+330    SMSC address unknown
+331    No network service
+332    Network timeout
+500    Unknown error
+512    Network busy
+513    Invalid destination address
+514    Invalid message body length
+515    Phone is not in service
+516    Invalid preferred memory storage
+517    User terminated
+</pre>
+<a name="Call_codes_.28call_causes.29" id="Call_codes_.28call_causes.29"></a><h3> <span class="mw-headline"> Call codes (call causes) </span></h3>
+<pre>1 Unallocated number
+3      No route to destination
+6      Channel unacceptable
+8      Operator determined barring
+16     Normal call clear
+17     User busy
+18     No user responding
+19     No answer from user
+21     Call rejected
+22     Number changed
+26     Non Selected user clear
+27     Destination out of order
+28     Invalid number format
+29     Facility rejected
+30     Response status enquiry
+31     Normal, unspecified
+34     No circuit channel available
+38     Network out of order
+41     Temporary failure
+42     Switch congestion
+43     Access information discarded
+44     Requested channel unavailable
+47     Resource unavailable
+49     QoS unavailable
+50     Request facility not subscribed
+55     Call barred with UG
+57     Bearer capability not authorized
+58     Bearer capability not available
+63     Service not available
+65     Bearer capability not implemented
+69     Request facility not implemented
+70     Only restricted bearer capability available
+79     Service not implemented
+81     Invalid call reference value
+82     User not member of UG
+88     Incompatible destination
+91     Invalid transit network selected
+95     Invalid message
+96     Missing mandatory information element
+97     Message type not implemented
+98     Message incompatible with state
+99     Information element not implemented
+100    Invalid information element
+101    Message incompatible with state (2)
+102    Recovery on timer expiry
+111    Protocol error
+127    Interworking
+</pre>
+<a name="General_codes_.28mobile_causes.29" id="General_codes_.28mobile_causes.29"></a><h3> <span class="mw-headline"> General codes (mobile causes) </span></h3>
+<pre>0 Phone failure
+1      No connection to phone
+2      Phone adaptor link reserved
+3      Operation not allowed
+4      Operation not supported
+5      Phone SIM PIN required
+6      Phone FSIM PIN required
+7      Phone FSIM PUK required
+10     SIM not inserted
+11     SIM PIN required
+12     SIM PUK required
+13     SIM failure
+14     SIM busy
+15     SIM wrong
+16     Incorrect password
+17     SIM PIN2 required
+18     SIM PUK2 required
+20     Memory full
+21     Invalid index
+22     Not found
+23     Memory failure
+24     Text string too long
+25     Invalid character in text string
+26     Dial string too long
+27     Invalid character in dial string
+30     No network service
+31     Network timeout
+32     Network not allowed
+33     Command aborted
+34     Number parameter instead of text parameter
+35     Text parameter instead of number parameter
+36     Numeric parameter out of bounds
+37     Text string too short
+40     Network PIN required
+41     Network PUK required
+42     Network subset PIN required
+43     Network subset PUK required
+44     Network service provider PIN required
+45     Network service provider PUK required
+46     Corporate PIN required
+47     Corporate PUK required
+60     SIM Service option not supported
+100    Unknown
+103    Illegal MS #3
+106    Illegal MS #6
+107    GPRS service not allowed #7
+111    PLMN not allowed #11
+112    Location area not allowed #12
+113    Roaming not allowed #13
+132    Service option not supported #32
+133    Registration service option not subscribed #33
+134    Service option temporary out of order #34
+147    Long context activation
+148    Unspecified GPRS error
+149    PDP authentication failure
+150    Invalid mobile class
+151    GPRS disconnection TMR active
+256    Too many active calls
+257    Call rejected
+258    Unanswered call pending
+259    Unknown calling error
+260    No phone number recognized
+261    Call state not idle
+262    Call in progress
+263    Dial state error
+264    Unlock code required
+265    Network busy
+266    Invalid phone number
+267    Number entry already started
+268    Cancelled by user
+269    Number entry could not be started
+280    Data lost
+281    Invalid message body length
+282    Inactive socket
+283    Socket already open
+</pre>
+<p><br />
+</p>
+<a name="Troubleshooting" id="Troubleshooting"></a><h1> <span class="mw-headline"> Troubleshooting </span></h1>
+<p>In this section, errors and their most common solutions are presented.
+</p>
+<a name="Error_during_installation_of_kernel_module" id="Error_during_installation_of_kernel_module"></a><h2> <span class="mw-headline"> Error during installation of kernel module </span></h2>
+<p>During installation of the <i>Endpoint</i>of Khomp may occur the following messages:
+<!-- NEED 3 -->
+</p>
+<pre>K3L: WARNING: Unable to find a module for [...]
+</pre>
+<p>or
+<!-- NEED 8 --> 
+</p>
+<pre>install: ******  THE KERNEL MODULE HAS NOT BEEN INSTALLED: *******
+install: 
+install: ** Please, untar the file kpdriver*.tar.gz located in: **
+install: **                 '/usr/src/khomp/'                   **
+install: **             then check the README.txt               **
+install: **  for knowing how to proceed with the installation.  **
+</pre>
+<p>In this case, you must compile the drivers manually to your system. Proceed to the item below for more information.
+<br />
+</p>
+<a name="Compiling_the_drivers_and_starting_the_services" id="Compiling_the_drivers_and_starting_the_services"></a><h3> <span class="mw-headline"> Compiling the drivers and starting the services </span></h3>
+<p>Just follow to the directory <b>/usr/src/khomp</b>, unpack the file "kpdriver_2.0.0<b>XX</b>.tar.gz", and follow procedures described in the file <b>README_en.txt</b>.
+</p><p>After performing compilation and installation of the module, just load it into the system, configuring the boards and start the server processes Khomp.
+</p><p>To load the kernel driver, you must run the following command:
+<!-- NEED 3 --> 
+</p>
+<pre># /etc/init.d/khompdrv start
+</pre>
+<p>To set up the boards, in turn, must run the command:
+<!-- NEED 3 --> 
+</p>
+<pre># khompwizard
+</pre>
+<p>This will run a setup wizard that will ask the signaling used in the system, as well as other parameters of use of the boards.
+</p><p>If necessary configure other additional parameters you can use the following command:
+<!-- NEED 3 --> 
+</p>
+<pre># k3lconfig
+</pre>
+<p>This configurator, in turn, shows all possible options for card configuration. The parameters that are not configured automatically assume the default values, and are compatible with most systems. More details about this program can be obtained from the section number '2 '.
+</p>
+<ul><li> <b>ATTENTION'<i>: To start FreeSWITCH&reg;, it is necessary that the board is configured Khomp and all modules are running (as shown above). </i></b><i>If the card is not configured, FreeSWITCH will not start<b>.<br /> <br /> If you want to run the system without the board Khomp, you need to configure FreeSWITCH for it does not load the module Khomp. To do this, open the "</b></i><b>/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml</b> and comment the line:<br />
+</li></ul>
+<pre> 
+&lt;!-- &lt;load module=&quot;mod_khomp&quot; /&gt; --&gt;
+</pre><br /> 
+<p>When the board Khomp is properly configured and loaded modules khomp (explained above), remember to uncomment this line in the file.
+</p><p>Finally, to load the server process, simply run the following command:
+<!-- NEED 3 -->
+</p>
+<pre># kserver start
+</pre>
+<p>After performing these procedures, the Endpoint is already operational, and FreeSWITCH can now be loaded.
+<br />
+</p>
+<a name="Setting_up_special_parameters_for_audio_or_signaling" id="Setting_up_special_parameters_for_audio_or_signaling"></a><h2> <span class="mw-headline"> Setting up special parameters for audio or signaling </span></h2>
+<p>To set specific parameters of timing and/or signaling, you can use the program "k3lconfig": simply select the card you want, and options of the boards will be presented, divided into sections and subsections for easy access. It is not necessary to effect the configuration of all parameters: default values are assumed, if not configured.
+</p><p>To adjust the signaling link, simply - after selecting the card - enter the "Options signaling, and then in" Signs of the line. " To choose a particular signaling, just use the direction keys (arrows) to select it, press 'space', and confirm the option by pressing 'Enter' on the "Confirm" button.
+</p><p>Finally, to save the modified settings, just exit the program: it will display a window with options to save the changes made or not.
+</p><p>Please not that <b>the following options are required to be unchanged from the defaults</b>:
+</p>
+<ul><li> Automatic echo cancellation;
+</li><li> DTMF suppression;
+</li><li> Automatic Gain Control (AGC).
+</li></ul>
+<p>These options are <b>controlled by Endpoint</b> and should be <b>disabled</b> in 'k3lconfig' (the default configuration).
+<br />
+</p>
+<a name="Automatic_load_of_services_and_kernel_modules" id="Automatic_load_of_services_and_kernel_modules"></a><h2> <span class="mw-headline"> Automatic load of services and kernel modules </span></h2>
+<p>If the loading of <i>kernel</i> module or Khomp services startup is not performed automatically at startup, you can perform this installation manually, creating a <i>link</i> for the <i>scripts</i> <b>/etc/init.d/khompdrv</b> and <b>/etc/init.d/kserver</b> in the system startup directory.
+</p><p>In the case of <b>Debian</b>-based distributions the <i>script</i> for loading <i>kernel</i> modules would be <i>linked</i> within the directory <i>/etc/rcS.d</i>, while the services loader would be <i>linked</i> within the directories <i>/etc/rc2.d</i>, <i>/etc/rc3.d</i>, <i>/etc/rc4.d</i>, <i>/etc/rc5.d</i> as follows:
+</p><p><!-- NEED 6 -->
+</p>
+<pre># ln -s /etc/init.d/khompdrv  /etc/rcS.d/S19khompdrv
+# ln -s /etc/init.d/kserver   /etc/rc2.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc3.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc4.d/S20kserver
+# ln -s /etc/init.d/kserver   /etc/rc5.d/S20kserver
+</pre>
+<p>Please check the rules of your distribution to initialize the services in accordance with what is expected by the start of it.
+<br />
+</p>
+<a name="Ap.C3.AAndice" id="Ap.C3.AAndice"></a><h1> <span class="mw-headline"> Apêndice </span></h1>
+<p>Nesta seção, encontram-se informações úteis sobre o Endpoint e componentes relacionados.
+</p>
+<a name="Arrangement_of_installed_files" id="Arrangement_of_installed_files"></a><h2> <span class="mw-headline"> Arrangement of installed files </span></h2>
+<p>The directories created/modified in this facility are:
+<!-- NEED 20 -->
+</p>
+<pre>/etc/init.d/                -- Startup scripts;
+
+/etc/khomp/                 -- Firmware files and settings;
+
+/usr/local/freeswitch/conf/ -- Settings for FreeSWITCH and Endpoint;
+
+/usr/doc/khomp/             -- Docs for the boards, Channel, and utilities;
+
+/usr/sbin/                  -- Utilities and server processes;
+
+/usr/lib/                   -- Shared libraries;
+
+/usr/local/freeswitch/mod/  -- Endpoint module;
+/var/log/khomp2.1/          -- Log directory for K3L and Endpoint;
+</pre>
+<p>The script <b>/etc/init.d/khompdrv</b> is responsible for loading modules <b>kpci9030.ko</b> and <b>kpex8311.ko</b> in the kernel, which should be carried out automatically at system startup. In case of problems, check the <a href="#Troubleshooting" title="">Troubleshooting</a> section. 
+</p><p><br />
+</p><p><br />
+</p></body></html>
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_khomp/docs/User_Guide.pdf b/src/mod/endpoints/mod_khomp/docs/User_Guide.pdf
new file mode 100644 (file)
index 0000000..2f8c874
Binary files /dev/null and b/src/mod/endpoints/mod_khomp/docs/User_Guide.pdf differ
diff --git a/src/mod/endpoints/mod_khomp/include/applications.h b/src/mod/endpoints/mod_khomp/include/applications.h
new file mode 100644 (file)
index 0000000..75f55ec
--- /dev/null
@@ -0,0 +1,962 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _APPLICATIONS_H_
+#define _APPLICATIONS_H_
+
+#include "lock.h"
+#include "khomp_pvt.h"
+
+struct Application 
+{
+    Application(Board::KhompPvt * pvt) : _pvt(pvt) {}
+    ~Application() {}
+
+    Statistics * statistics() { return _app_statistics; }
+
+    template <typename T>
+    T* statistics() { return static_cast<T*>(_app_statistics); }
+
+    Board::KhompPvt *_pvt;
+    Statistics      *_app_statistics;
+};
+
+/*************************** FAX **********************************************/
+struct Fax
+{
+    Fax(Board::KhompPvt * pvt) : _pvt(pvt) {}
+
+    /*
+    bool clear(Board::KhompPvt * pvt)
+    {
+        _pvt = pvt;
+        return true;
+    }
+    */
+
+    bool adjustForFax();    
+
+    bool sendFax(switch_core_session_t * session, const char *data);
+    bool receiveFax(switch_core_session_t * session, const char *data);
+
+    bool onFaxChannelRelease(K3L_EVENT *e);
+
+    bool startFaxTX(const char * orig_addr = NULL);
+    bool stopFaxTX();
+    bool startFaxRX(const char * filename, const char * orig_addr = NULL);
+    bool stopFaxRX();
+    bool addFaxFile(const char * filename, bool last = true);
+
+
+    Board::KhompPvt *_pvt;
+
+    /* used by app FAX */
+    SavedCondition _fax_cond;
+    KFaxResult     _fax_result;
+
+};
+
+/*************************** TRANSFER *****************************************/
+template <typename T, bool flash = true>
+struct Transfer
+{
+    Transfer(Board::KhompPvt * pvt) : _pvt(pvt), _is_ok(false) {}
+    
+    bool clear()
+    {
+        if(!_is_ok)
+        {
+            _call = dynamic_cast<T *>(_pvt->call());
+
+            _is_ok = true;
+
+            if(!_call)
+            {
+                DBG(FUNC, D("Error in cast"));
+                _is_ok = false;
+            }
+        }
+
+        _call->_flags.clear(Kflags::XFER_DIALING);
+
+        return true;
+    }
+
+    bool userTransfer(switch_core_session_t * session, const char *data)
+    {
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
+
+        std::string dest("");
+        std::string opts("");
+
+        try
+        {
+            Strings::vector_type params;
+
+            Strings::tokenize((const char *)data, params, "|,", 2);
+
+            dest = params[0];
+
+            if (params.size() > 1)
+            {
+                // other options go here...
+            }
+            
+            ScopedPvtLock lock(_pvt);
+
+            int timeout = 5;
+
+            if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
+                return false;
+
+            DBG(FUNC, PVT_FMT(_pvt->target(), "flashing channel!"));
+
+            _pvt->command(KHOMP_LOG, CM_FLASH);
+
+            lock.unlock();
+
+            timeout = 15; // 15 * 200000 = 3s
+
+            do
+            {
+                usleep(200000);
+                timeout--;
+
+                ScopedPvtLock lock2(_pvt);
+
+                if(!_pvt->call()->_flags.check(Kflags::IS_INCOMING) && !_pvt->call()->_flags.check(Kflags::IS_OUTGOING))
+                {
+                    DBG(FUNC, PVT_FMT(_pvt->target(), "unable to do a user transfer, channel disconnected"));
+                    return false;
+                }
+
+            }
+            while(timeout);
+
+            ScopedPvtLock lock3(_pvt);
+
+            _pvt->command(KHOMP_LOG, CM_DIAL_DTMF, dest.c_str());
+
+            _pvt->call()->_flags.set(Kflags::WAIT_SEND_DTMF);
+
+            lock3.unlock();
+
+            timeout = 300; // 300 * 200000 = 60s
+
+            do
+            {
+                usleep(200000);
+                timeout--;
+
+                ScopedPvtLock lock4(_pvt);
+
+                if(!_pvt->call()->_flags.check(Kflags::WAIT_SEND_DTMF))
+                    break;
+            }
+            while(timeout);
+
+        }
+        catch (ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
+            return false;
+        }
+
+
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
+        return true;
+    }
+
+    /* User transfer functions */
+    bool doUserXferUnlocked()
+    {
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c (flashing channel!)"));
+
+        bool ret = false;
+
+        ret = _pvt->command(KHOMP_LOG, CM_FLASH);
+
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r (%s)") % (ret ? "true" : "false"));
+        return ret;
+    }
+
+    bool checkUserXferUnlocked(std::string digit)
+    { 
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c (CM_FLASH)"));
+
+
+        if (_call->_user_xfer_digits.empty())
+        {
+            _call->_digits_buffer += digit;
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (disabled)"));
+            return false;
+        }
+
+        _call->_user_xfer_buffer += digit;
+
+        /* temporary buffer */
+        std::string tmp = _call->_user_xfer_buffer;
+
+        unsigned int amount = tmp.size();
+        
+        try
+        {
+
+        if (amount == _call->_user_xfer_digits.size())
+        {
+            if (tmp == _call->_user_xfer_digits)
+            {
+                bool ret = doUserXferUnlocked();
+
+                _call->_user_xfer_buffer.clear();
+                _call->_digits_buffer.clear();
+
+                Board::board(_pvt->target().device)->_timers.del(_idx_xfer_dial);
+
+                DBG(FUNC, PVT_FMT(_pvt->target(), "r (ret=%s, done xfer)") % (ret ? "true" : "false"));
+                return ret;
+            }
+
+            _call->_digits_buffer += tmp[0];
+            _call->_user_xfer_buffer.erase(0, 1);
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, no xfer)"));
+            return false;
+        }
+
+        if (tmp == _call->_user_xfer_digits.substr(0,amount))
+        {
+            if (!(_call->_flags.check(Kflags::XFER_DIALING)))
+            {
+                _call->_flags.set(Kflags::XFER_DIALING);
+                _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_transferdigittimeout, &userXferTimer, _pvt, TM_VAL_CALL);
+            }
+            else
+            {
+                Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
+            }
+
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, buffering)"));
+            return true;
+        }
+
+        }
+        catch (K3LAPI::invalid_device & err)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device);
+        }
+
+        _call->_digits_buffer += tmp[0];
+        _call->_user_xfer_buffer.erase(0, 1);
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, buffering)"));
+
+        return false;
+
+    }
+
+    static void userXferTimer(Board::KhompPvt * pvt)
+    {
+        DBG(FUNC, PVT_FMT(pvt->target(), "c"));
+        
+        T * call = static_cast<T *>(pvt->call());
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            if (!call->_user_xfer_buffer.empty())
+            {
+                pvt->command(KHOMP_LOG, CM_DIAL_DTMF, call->_user_xfer_buffer.c_str());
+
+                /* clear the buffer that has been send */
+                call->_user_xfer_buffer.clear();
+            }
+
+            call->_flags.clear(Kflags::XFER_DIALING);
+        }
+        catch (ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
+            return;
+        }
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "r"));
+    }
+
+    bool                    _is_ok;
+    T *                     _call;
+    Board::KhompPvt *       _pvt;
+    Board::ChanTimer::Index _idx_xfer_dial;
+};
+
+template<typename T> 
+struct Transfer<T, false>
+{
+    Transfer(Board::KhompPvt * pvt) : _pvt(pvt), _is_ok(false) {}
+
+    bool clear()
+    {
+        if(!_is_ok)
+        {
+            _call = dynamic_cast<T *>(_pvt->call());
+
+            _is_ok = true;
+
+            if(!_call)
+            {
+                DBG(FUNC, D("Error in cast"));
+                _is_ok = false;
+            }
+        }
+
+        _call->_flags.clear(Kflags::XFER_DIALING);
+        _call->_flags.clear(Kflags::XFER_QSIG_DIALING);
+
+        return true;
+    }
+    
+    bool userTransfer(switch_core_session_t * session, const char *data)
+    {
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
+
+        std::string dest("");
+
+        bool opt_nowait = false;
+
+        try
+        {
+            Strings::vector_type params;
+
+            Strings::tokenize((const char *)data, params, "|,", 2);
+
+            dest = params[0];
+
+            if (params.size() > 1)
+            {
+                opt_nowait = (params[1].find('n') != std::string::npos);
+
+                // other options go here...
+            }
+            
+            ScopedPvtLock lock(_pvt);
+
+            int timeout = 5;
+            
+            if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
+                return false;
+
+            DBG(FUNC, PVT_FMT(_pvt->target(), "ss_transfer on channel!"));
+
+            _pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
+                    STG(FMT("transferred_to=\"%s\" await_connect=\"%d\"")
+                    % dest % (opt_nowait ? 0 : 1)).c_str());
+
+        }
+        catch (ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
+            return false;
+        }
+
+
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
+        return true;
+    }
+
+    /* User transfer functions */
+    bool doUserXferUnlocked(void)
+    {
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
+
+        bool ret = false;
+
+        if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
+        {
+            DBG(FUNC, PVT_FMT(_pvt->target(), "ss_transfer on channel!"));
+
+            _call->_flags.clear(Kflags::XFER_DIALING);
+            _call->_flags.clear(Kflags::XFER_QSIG_DIALING);
+
+            ret = _pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
+                    STG(FMT("transferred_to=\"%s\" await_connect=\"1\"") % _call->_qsig_number).c_str());
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(_pvt->target(), "starting to store digits for ss_transfer..."));
+            _call->_flags.set(Kflags::XFER_QSIG_DIALING);
+
+            _xfer_thread = threadCreate(Transfer<T, false>::userXferPlayback,(void*) _pvt);
+            _xfer_thread->start();
+
+            ret = true;
+        }
+
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r (%s)") % (ret ? "true" : "false"));
+        return ret;
+
+    }
+
+    bool checkUserXferUnlocked(std::string digit) 
+    { 
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c (CM_SS_TRANSFER)"));
+
+
+        if (_call->_user_xfer_digits.empty())
+        {
+            _call->_digits_buffer += digit;
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (disabled)"));
+            return false;
+        }
+
+        _call->_user_xfer_buffer += digit;
+
+        DBG(FUNC, PVT_FMT(_pvt->target(), "c digits=[%s] buffer=[%s]") % _call->_user_xfer_digits % _call->_user_xfer_buffer );
+
+        /* temporary buffer */
+        std::string tmp = _call->_user_xfer_buffer;
+
+        unsigned int amount = tmp.size();
+        
+        try
+        {
+
+        if (amount == _call->_user_xfer_digits.size())
+        {
+            if (tmp == _call->_user_xfer_digits)
+            {
+                bool ret = doUserXferUnlocked();
+
+                _call->_user_xfer_buffer.clear();
+                _call->_qsig_number.clear();
+                _call->_digits_buffer.clear();
+
+                if(!_call->_flags.check(Kflags::XFER_QSIG_DIALING))
+                {
+                    Board::board(_pvt->target().device)->_timers.del(_idx_xfer_dial);
+
+                    DBG(FUNC, PVT_FMT(_pvt->target(), "r (ret=%s, done xfer)") % (ret ? "true" : "false"));
+                }
+                else
+                {
+                    Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
+                    DBG(FUNC, PVT_FMT(_pvt->target(), "r (waiting digits for transfer)"));
+                }
+                return ret;
+            }
+
+            if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
+            {
+                DBG(FUNC, PVT_FMT(_pvt->target(), "putting digits ('%s') on transfer-to number!") % tmp);
+
+                _call->_qsig_number += tmp[0];
+                _call->_user_xfer_buffer.erase(0, 1);
+                Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
+
+                DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, qsig transfer)"));
+                return true;
+            }
+
+            _call->_digits_buffer += tmp[0];
+            _call->_user_xfer_buffer.erase(0, 1);
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, no qsig)"));
+            return false;
+        }
+
+        if (tmp == _call->_user_xfer_digits.substr(0,amount))
+        {
+            if (!(_call->_flags.check(Kflags::XFER_DIALING) || _call->_flags.check(Kflags::XFER_QSIG_DIALING)))
+            {
+                _call->_flags.set(Kflags::XFER_DIALING);
+                _idx_xfer_dial = Board::board(_pvt->target().device)->_timers.add(Opt::_transferdigittimeout, &userXferTimer, _pvt, TM_VAL_CALL);
+            }
+            else
+            {
+                Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
+            }
+
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, buffering)"));
+            return true;
+        }
+
+        if (_call->_flags.check(Kflags::XFER_QSIG_DIALING))
+        {
+            DBG(FUNC, PVT_FMT(_pvt->target(), "putting digits ('%s') on transfer-to number!") % tmp);
+
+            _call->_qsig_number += tmp[0];
+            _call->_user_xfer_buffer.erase(0, 1);
+
+            Board::board(_pvt->target().device)->_timers.restart(_idx_xfer_dial);
+            DBG(FUNC, PVT_FMT(_pvt->target(), "r (true, qsig buffering)"));
+            return true;
+        }
+        
+        }
+        catch (K3LAPI::invalid_device & err)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "Unable to get device: %d!") % err.device);
+        }
+
+        _call->_digits_buffer += tmp[0];
+        _call->_user_xfer_buffer.erase(0, 1);
+        DBG(FUNC, PVT_FMT(_pvt->target(), "r (false, buffering)"));
+
+        return false;
+    }
+
+    static void userXferTimer(Board::KhompPvt * pvt)
+    {
+        DBG(FUNC, PVT_FMT(pvt->target(), "c"));
+
+        T * call = static_cast<T *>(pvt->call());
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            if (!call->_user_xfer_buffer.empty())
+            {
+                pvt->command(KHOMP_LOG, CM_DIAL_DTMF, call->_user_xfer_buffer.c_str());
+
+                /* clear the buffer that has been send */
+                call->_user_xfer_buffer.clear();
+            }
+
+            if (!call->_qsig_number.empty())
+            {
+                pvt->command(KHOMP_LOG, CM_SS_TRANSFER,
+                        STG(FMT("transferred_to=\"%s\" await_connect=\"1\"") % call->_qsig_number).c_str());
+
+                /* clear the buffer that has been send */
+                call->_qsig_number.clear();
+            }
+
+            call->_flags.clear(Kflags::XFER_DIALING);
+            call->_flags.clear(Kflags::XFER_QSIG_DIALING);
+        }
+        catch (ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
+            return;
+        }
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "r"));
+    }
+
+    static switch_status_t dtmfCallback(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
+    {
+        char sbuf[3];
+
+        if(!session)
+        {
+            DBG(FUNC,D("session is NULL"))
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_channel_t * chan = switch_core_session_get_channel(session);
+
+        if(!chan)
+        {
+            DBG(FUNC,D("channel is NULL"))
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_core_session_t *peer_session = switch_core_session_locate(switch_channel_get_variable(chan,SWITCH_SIGNAL_BOND_VARIABLE));
+
+        if(!peer_session)
+        {
+            DBG(FUNC,D("session is NULL"))
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch (itype) 
+        {
+            case SWITCH_INPUT_TYPE_DTMF:
+            {
+                switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
+
+                Board::KhompPvt * tech_pvt = static_cast< Board::KhompPvt* >(switch_core_session_get_private(peer_session));
+                if(!tech_pvt)
+                {
+                    DBG(FUNC,D("Init: pvt is NULL"))
+                    switch_core_session_rwunlock(peer_session);
+                    return SWITCH_STATUS_FALSE;
+                }
+
+                char s[] = { dtmf->digit, '\0' };
+                tech_pvt->sendDtmf(s); 
+
+                break;
+            }        
+            default: 
+                break;
+        }        
+
+        switch_core_session_rwunlock(peer_session);
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+
+    static int userXferPlayback(void * pvt_ptr)
+    {
+        /* get pointer... */
+        Board::KhompPvt * pvt = static_cast < Board::KhompPvt * > (pvt_ptr);
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "c"));
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            /* get the owner */
+            switch_channel_t * chan = pvt->getFSChannel();
+
+            /* get other side of the bridge */
+            switch_core_session_t * peer_session = NULL;
+            switch_core_session_get_partner(pvt->session(),&peer_session);
+
+            if(!peer_session)
+            {
+                DBG(FUNC, PVT_FMT(pvt->target(), "r (session is null)"));
+                return NULL;
+            }
+
+            switch_channel_t * peer = switch_core_session_get_channel(peer_session);
+
+            /* put the channel in hold */
+            //switch_core_session_t *session = switch_core_session_locate(switch_channel_get_variable(chan,SWITCH_SIGNAL_BOND_VARIABLE));
+            //switch_channel_t *chan_core = switch_core_session_get_channel(session);
+
+            const char *stream;
+
+            if (!(stream = switch_channel_get_variable(chan, SWITCH_HOLD_MUSIC_VARIABLE)))
+            {
+                stream = "silence";
+            }
+
+            DBG(FUNC, PVT_FMT(pvt->target(), "stream=%s") % stream);
+
+            if (stream && strcasecmp(stream, "silence"))
+            {
+                /* Freeswitch not get/put frames */
+                //switch_channel_set_flag(channel, CF_HOLD);
+                switch_ivr_broadcast(switch_core_session_get_uuid(pvt->session()),stream, SMF_ECHO_ALEG | SMF_LOOP | SMF_PRIORITY);
+            }
+
+            switch_core_session_rwunlock(peer_session);
+            lock.unlock();
+
+            /* kickstart my heart */
+            switch_input_args_t args = {0};
+            args.input_callback = dtmfCallback;
+
+            /* wait while xfering... */
+            while (true)
+            {
+                switch_ivr_collect_digits_callback(peer_session,&args,1000,0);
+                ScopedPvtLock lock2(pvt);
+
+                if (!pvt->call()->_flags.check(Kflags::XFER_QSIG_DIALING))
+                {
+                    break;
+                }
+
+                lock2.unlock();
+            }
+
+            //switch_channel_clear_flag(channel, CF_HOLD);
+
+            switch_channel_stop_broadcast(chan);
+            switch_channel_wait_for_flag(chan, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
+            switch_core_session_rwunlock(pvt->session());
+            switch_core_session_rwunlock(peer_session);
+
+            //switch_ivr_unhold_uuid(switch_channel_get_variable(chan,SWITCH_SIGNAL_BOND_VARIABLE));
+        }
+        catch (ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(),"r (unable to lock %s!)") % err._msg.c_str() );
+            return NULL;
+        }
+        catch (Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(), "r (%s)") % err._msg.c_str() );
+            return NULL;
+        }
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "r"));
+
+        return NULL;
+    }
+
+    bool                    _is_ok;
+    T *                     _call;
+    Board::KhompPvt *       _pvt;
+    Thread *                _xfer_thread;
+    Board::ChanTimer::Index _idx_xfer_dial;
+};
+
+/*************************** SMS **********************************************/
+struct SMS : public Application
+{
+    typedef std::list< switch_core_session_t *> OwnersList;
+
+    struct SMSStatistics : public Statistics
+    {
+        SMSStatistics():
+            _sms_number_incoming(0),
+            _sms_number_outgoing(0),
+            _sms_number_confirm(0),
+            _sms_number_broadcast(0) {};
+
+        void incrementIncoming()
+        {
+            _sms_number_incoming++;
+        }
+
+        void incrementOutgoing()
+        {
+            _sms_number_outgoing++;
+        }
+
+        void incrementConfirm()
+        {
+            _sms_number_confirm++;
+        }
+
+        void incrementBroadcast()
+        {
+            _sms_number_broadcast++;
+        }
+        
+        std::string getDetailed()
+        {
+            std::string tmpBuffer;
+
+            tmpBuffer.append(STG(FMT("Number of incoming SMS: \t%d\n")  % _sms_number_incoming));
+            tmpBuffer.append(STG(FMT("Number of outgoing SMS: \t%d\n")  % _sms_number_outgoing));
+            tmpBuffer.append(STG(FMT("Number of broadcast SMS: \t%d\n") % _sms_number_broadcast));
+            tmpBuffer.append(STG(FMT("Number of confirm SMS:  \t%d\n")  % _sms_number_confirm));
+
+            return tmpBuffer;
+        }
+
+        void clear()
+        {
+            _sms_number_incoming  = 0;
+            _sms_number_outgoing  = 0;
+            _sms_number_confirm   = 0;
+            _sms_number_broadcast = 0;
+        }
+
+        unsigned int _sms_number_incoming;
+        unsigned int _sms_number_outgoing;
+        unsigned int _sms_number_confirm;
+        unsigned int _sms_number_broadcast;
+    };
+
+    SMS(Board::KhompPvt * pvt) : 
+    Application(pvt),
+    _thread(NULL),
+    _shutdown(false),
+    _can_receive(false),
+    _can_send(false),
+    _result(0),
+    _mutex(Globals::module_pool),
+    _cond(Globals::module_pool),
+    _buffer(8)
+    {
+        _cond.reset();
+        _app_statistics = new SMSStatistics();
+    }
+
+    ~SMS()
+    {
+        stop();
+        delete _app_statistics;
+    }
+
+    struct ReceiveData
+    {
+        ReceiveData() {};
+
+        ReceiveData(const ReceiveData & o)
+        {
+            _type    = o._type;
+            _from    = o._from;
+            _date    = o._date;
+            _size    = o._size;
+            _coding  = o._coding;
+            _serial  = o._serial;
+            _id      = o._id;
+            _page    = o._page;
+            _pages   = o._pages;
+            _sc_date = o._sc_date;
+            _status  = o._status;
+            _body    = o._body;
+        };
+
+        void clear(void)
+        {
+            /* reset data stuff */
+            _type.clear();
+            _from.clear();
+            _date.clear();
+            _size.clear();
+            _coding.clear();
+            _serial.clear();
+            _id.clear();
+            _page.clear();
+            _pages.clear();
+            _sc_date.clear();
+            _status.clear();
+            _body.clear();
+        };
+
+        std::string _type;
+        std::string _from;
+        std::string _date;
+        std::string _size;
+        std::string _coding;
+        std::string _serial;
+        std::string _id;
+        std::string _page;
+        std::string _pages;
+        std::string _sc_date;
+        std::string _status;
+        std::string _body;
+    };
+
+    struct SendData
+    {
+        SendData(): _conf(false) {};
+
+        SendData(const SendData & o)
+        {
+            _dest    = o._dest;
+            _body    = o._body;
+            _conf    = o._conf;
+        };
+
+        void clear(void)
+        {
+            /* reset data stuff */
+            _dest.clear();
+            _body.clear();
+            _conf = false;
+        };
+
+        std::string _dest;
+        std::string _body;
+        bool        _conf;
+    };
+
+    struct Request
+    {
+        /* "empty" constructor */
+        Request(): _finished(NULL), _cause(NULL) {};
+
+        /* "real" constructor */
+        Request(SendData & send_sms, volatile bool * finished, volatile KGsmCallCause * cause)
+            : _send_sms(send_sms), _finished(finished), _cause(cause)
+        {};
+
+        SendData _send_sms;
+
+        volatile bool          * _finished;
+        volatile KGsmCallCause * _cause;
+    };
+
+    bool start()
+    {
+        _pvt->call()->_flags.clear(Kflags::SMS_DOING_UPLOAD);
+
+        _thread = threadCreate(&smsThread, (void*) this);
+        _thread->start();
+    }
+
+    bool stop()
+    {
+        if(!_thread)
+        {
+            return false;
+        }
+
+        _shutdown = true;
+        _cond.signal();
+        _thread->join();
+        delete _thread;
+        _thread = NULL;
+
+        return true;
+    }
+
+    bool justAlloc(unsigned int count = 0);
+    bool justStart();
+
+    bool sendSMS(switch_core_session_t * session, const char *data);
+    
+
+    bool onNewSMS(K3L_EVENT *e);
+    bool onSMSInfo(K3L_EVENT *e);
+    bool onSMSData(K3L_EVENT *e);
+    bool onSMSSendResult(K3L_EVENT *e);
+   
+    Thread                                             *_thread;
+    bool                                                _shutdown;
+    bool                                                _can_receive;
+    bool                                                _can_send;
+    ReceiveData                                         _got_sms;
+    SendData                                            _send_sms;
+    int                                                 _result;
+    SavedCondition                                      _cond;
+    Globals::Mutex                                      _mutex;
+    Ringbuffer < SMS::Request >                         _buffer;
+    OwnersList                                          _owners;
+
+    static int smsThread(void * sms_ptr);
+};
+
+/******************************************************************************/
+
+
+#endif /* _APPLICATIONS_H_ */
+
diff --git a/src/mod/endpoints/mod_khomp/include/cli.h b/src/mod/endpoints/mod_khomp/include/cli.h
new file mode 100644 (file)
index 0000000..214e2aa
--- /dev/null
@@ -0,0 +1,1143 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _CLI_H_
+#define _CLI_H_
+
+#include "globals.h"
+#include "logger.h"
+
+struct Command 
+{
+    /* print in client the usage */
+    void printUsage(switch_stream_handle_t *stream)
+    { 
+        if(stream)
+        {
+            printBrief(stream);
+            K::Logger::Logg2(C_CLI,stream, 
+"------------------------------ Description --------------------------------"); 
+            K::Logger::Logg2(C_CLI,stream, 
+"---------------------------------------------------------------------------"); 
+            K::Logger::Logg2(C_CLI,stream,(char*) usage.c_str()); 
+            K::Logger::Logg2(C_CLI,stream, 
+"---------------------------------------------------------------------------"); 
+        }
+        else
+        {
+            LOG(ERROR,FMT("Invalid stream for commmand: %s") % complete_name);
+        }
+    }
+
+    /* print in client the brief */
+    void printBrief(switch_stream_handle_t *stream)
+    {
+        if(stream)
+        {
+            K::Logger::Logg2(C_CLI,stream, 
+"---------------------------------------------------------------------------"); 
+            K::Logger::Logg2(C_CLI,stream, 
+"-------------------------------- Brief ------------------------------------"); 
+            K::Logger::Logg2(C_CLI,stream, 
+"---------------------------------------------------------------------------"); 
+            K::Logger::Logg2(C_CLI,stream,(char*) brief.c_str()); 
+            K::Logger::Logg2(C_CLI,stream, 
+"---------------------------------------------------------------------------"); 
+        }
+        else
+        {
+            LOG(ERROR,FMT("Invalid stream for commmand: %s") % complete_name);
+        }
+    }
+
+    /* pure virtual */
+    virtual bool execute(int argc, char *argv[]) = 0;
+
+    std::string complete_name;         /* specify the command in console */
+    std::vector<std::string> options;  /* extra options for command */
+    std::string brief;                 /* brief of the command, a path */
+    std::string usage;                 /* usage of the command, a help */
+};
+
+struct Cli 
+{
+    /* Useful definitions --------------------------------------------------- */
+    typedef switch_status_t (APIFunc)(const char*, switch_core_session_t*, switch_stream_handle_t*);
+    typedef std::vector<Command*> Commands;
+
+    /* register our commands, but you must create the command function */
+    static void registerCommands(APIFunc func,switch_loadable_module_interface_t **mod_int);
+    
+    /* delete the commands */
+    static void unregisterCommands()
+    {
+        switch_console_set_complete("del khomp");
+    }
+
+    /* stream is very useful */
+    static void setStream(switch_stream_handle_t *s)
+    {
+        if(!s)
+        {
+            LOG(ERROR,"Invalid stream passed");
+            return;
+        }
+
+        stream = s;
+    }
+
+    /* gets the khomp usage */
+    static void printKhompUsage()
+    {
+        if(stream)
+        {
+            K::Logger::Logg2(C_CLI,stream,(char*) _khomp_usage.c_str());
+        }
+        else
+        {
+            LOG(ERROR,"Invalid stream for command: printKhompUsage");
+        }
+    }
+
+    /* is responsible for parse and execute all commands */
+    static bool parseCommands(int argc, char *argv[]);
+
+    /* The Commands --------------------------------------------------------- */
+
+    /* khomp summary */
+    static struct _KhompSummary : public Command
+    {
+        _KhompSummary(bool on_cli_term = true):
+        _on_cli_term(on_cli_term)
+        {
+            complete_name = "summary";
+
+            options.push_back("verbose");
+            options.push_back("concise");
+
+            brief = "Print system info.";                                            
+            usage =                                                            \
+"Prints detailed info about the system like API version and \n"                \
+"boards characteristics like DSPs version.\n\n"                                \
+"Usage: khomp summary [concise]";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+        bool _on_cli_term; /* indicates if message is sent to fs_cli */
+    } KhompSummary;
+
+    /* khomp show calls */
+    static struct _KhompShowCalls : public Command
+    {
+        _KhompShowCalls()
+        {
+            complete_name = "show calls";
+            brief  =                                                           \
+"Show each Khomp channel which have more than one call state associated.";
+
+            usage =                                                            \
+"Show each Khomp channel which have more than one call state associated.\n\n"  \
+"Usage: khomp show calls [<board> [<channel>]]";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+
+        /* support function for _KhompShowCalls */
+        void showCalls(unsigned int device, unsigned int object, std::string &buffer);
+    } KhompShowCalls;
+
+    /* khomp channels disconnect */
+    static struct _KhompChannelsDisconnect : public Command
+    {
+        _KhompChannelsDisconnect()
+        {
+            complete_name = "channels disconnect";
+            brief = "Disconnect a(ll) channel(s).";                                                              
+            usage =                                                            \
+"Disconnects channels in boards, or specific board/channel if parameter \n"    \
+"is supplied.\n\n"                                                             \
+"Usage: khomp channels disconnect {all | <board> all | <board> <channel>}\n"   \
+"\tboard   -- Number of the board (start from 0).\n"                           \
+"\tchannel -- Number of the channel (start from 0).\n"                         \
+"e.g. khomp channels disconnect all - Disconnect all channels of all boards.\n"\
+"e.g. khomp channels disconnect 0 5 - Disconnect channel 5 of board 0.";              
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+
+        /* support function for _KhompChannelsDisconnect */
+        bool forceDisconnect(unsigned int device, unsigned int channel);
+    } KhompChannelsDisconnect;
+
+    /* khomp channels unblock */
+    static struct _KhompChannelsUnblock : public Command
+    {   
+        _KhompChannelsUnblock()
+        {
+            complete_name = "channels unblock";
+            brief = "Unblock a(ll) channel(s).";
+
+            usage =                                                            \
+"The board will request to the PBX or network where it is connected to \n"     \
+"unblock the channel if its blocked.\n\n"                                      \
+"Usage: khomp channels unblock {all | <board> all | <board> <channel>}\n"      \
+"\tboard   -- Number of the board (start from 0).\n"                           \
+"\tchannel -- Number of the channel (start from 0).\n"                         \
+"e.g. khomp channels unblock all   - Unblock all channels of all boards.\n"    \
+"e.g. khomp channels unblock 0 all - Unblock all channels of board 0.\n"       \
+"e.g. khomp channels unblock 1 20  - Unblock channel 20 of board 1.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompChannelsUnblock;
+
+    /* khomp show statistics */
+    static struct _KhompShowStatistics : public Command 
+    {
+        _KhompShowStatistics()
+        {
+            complete_name = "show statistics";
+
+            options.push_back("verbose");
+            options.push_back("detailed");
+
+            brief = "Shows statistics of the channels.";
+
+            usage =                                                            \
+"Shows statistics of the channels, like number of calls incoming \n"           \
+"and outgoing, status, status time.\n\n"                                       \
+"Usage: khomp show statistics [{verbose [<board> [<channel>]]} | \n"           \
+"                              {detailed <board> <channel>}]\n"                \
+"\tboard   -- Number of the board (start from 0).\n"                           \
+"\tchannel -- Number of the channel (start from 0).\n"                         \
+"e.g. khomp channels statistics              - Shows general statistics \n"    \
+"                                              of all boards.\n"               \
+"e.g. khomp channels statistics 0            - Shows general statistics \n"    \
+"                                              of board 0.\n"                  \
+"e.g. khomp channels statistics verbose      - Shows general statistics \n"    \
+"                                              of all boards.\n"               \
+"e.g. khomp channels statistics verbose  0   - Shows general statistics \n"    \
+"                                              of board 0.\n"                  \
+"e.g. khomp channels statistics detailed 0 2 - Shows detailed statistics \n"   \
+"                                              of channel 2 on board 0.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+
+        /* support functions */
+        void cliStatistics(unsigned int device);
+        void cliDetailedStatistics(unsigned int device, unsigned int channel);
+
+    } KhompShowStatistics;
+
+    /* khomp show channels */
+    static struct _KhompShowChannels: public Command
+    {
+        _KhompShowChannels()
+        {
+            complete_name = "show channels";
+
+            options.push_back("verbose");
+            options.push_back("concise");
+
+            brief = "Show all channels status.";                                                                               
+            usage =                                                            \
+"List the status of each channel, both on asterisk point of view and on \n"    \
+"khomp API point of view.\n\n"                                                 \
+"Usage: \n"                                                                    \
+"khomp show channels [{<board> [<channel>]} | \n"                              \
+                              "{{concise|verbose} [<board> [<channel>]]}]\n"   \
+"\tboard -- Number of the board (start from 0).\n"                             \
+"e.g. khomp show channels - List status of all channels of all boards.\n"      \
+"e.g. khomp show channels concise 0 - List status of all channels of \n"       \
+"                                     board 0 in a concise way.";
+
+            _commands.push_back(this);
+        };
+
+        /* support function for _KhompShowChannels */
+        void showChannel(unsigned int device, bool concise, unsigned int channel);
+        void showChannels(unsigned int device, bool concise);
+
+        bool execute(int argc, char *argv[]);
+    } KhompShowChannels;
+    
+    /* khomp show links */
+    static struct _KhompShowLinks: public Command
+    {
+        _KhompShowLinks()
+        {
+            complete_name = "show links";
+
+            options.push_back("verbose");
+            options.push_back("concise");
+            options.push_back("errors");
+            options.push_back("errors verbose");
+            options.push_back("errors concise");
+
+            brief = "Show E1 link(s) status/errors counters in a concise \n"   \
+            "way or not.";
+
+            usage =                                                            \
+"Prints information about the signaling, syncronization and general \n"        \
+"status/the error counters of each link on the board. It prints in \n"         \
+"a concise way for parsing facilities.\n\n"                                    \
+"Usage: \n"                                                                    \
+"khomp show links [[errors] [{<board>} | {{concise|verbose} [<board>]}]]\n"    \
+"e.g. khomp show links          - Show all links of all boards.\n"             \
+"e.g. khomp show links errors   - Show error counters of all links of \n"      \
+"                                 all boards.\n"                               \
+"e.g. khomp show links errors 0 - Show error counters of all links of \n"      \
+"                                 board 0.";
+
+            _commands.push_back(this);
+        };
+
+        /* support function for _KhompShowLinks */
+        void showLinks(unsigned int device, bool concise);
+        void showErrors(unsigned int device, bool concise);
+
+        bool execute(int argc, char *argv[]);
+    } KhompShowLinks;
+
+    /* khomp clear links */
+    static struct _KhompClearLinks: public Command
+    {
+        _KhompClearLinks()
+        {
+            complete_name = "clear links";
+    
+            brief = "Clear the error counters of the links.";
+
+            usage =                                                            \
+"Clear the error counters of the links.\n\n"                                   \
+"Usage: khomp clear links [<board> [<link>]]\n"                                \
+"\tboard -- Number of the board (start from 0).\n"                             \
+"\tlink  -- Number of the link (start from 0).\n"                              \
+"e.g. khomp clear links 0 -- Clear error counters of all links of board 0.";
+
+            _commands.push_back(this);
+        };
+
+        /* support function for _KhompClearLinks */
+        void clearLink(unsigned int device, unsigned int link);
+
+        bool execute(int argc, char *argv[]);
+    } KhompClearLinks;
+
+    /* khomp clear statistics */
+    static struct _KhompClearStatistics: public Command
+    {
+        _KhompClearStatistics()
+        {
+            complete_name = "clear statistics";
+    
+            brief = "Clear statistics of the channels.";
+
+            usage =                                                            \
+"Clear statistics of the channels, like number of calls incoming \n"           \
+"and outgoing, status, status time.\n\n"                                       \
+"Usage: khomp clear statistics [<board> [<channel>]]\n"                        \
+"\tboard   -- Number of the board (start from 0).\n"                           \
+"\tchannel -- Number of the channel (start from 0).\n"                         \
+"e.g. khomp clear statistics 0 -- Clear statistics of board 0."; 
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompClearStatistics;
+
+
+    /* khomp reset links */
+    static struct _KhompResetLinks: public Command
+    {
+        _KhompResetLinks()
+        {
+            complete_name = "reset links";
+    
+            brief = "Reset the specified link.";
+
+            usage =                                                            \
+"Reset the specified link.\n\n"                                                \
+"Usage: khomp reset links [<board> [<link>]]\n"                                \
+"\tboard -- Number of the board (start from 0).\n"                             \
+"\tlink  -- Number of the link (start from 0).\n"                              \
+"e.g. khomp reset links 0 1 -- Reset link 1 of board 0.";
+
+            _commands.push_back(this);
+        };
+
+        /* support function for _KhompResetLinks */
+        void resetLink(unsigned int device, unsigned int link);
+
+        bool execute(int argc, char *argv[]);
+    } KhompResetLinks;
+   
+    /* khomp sms */
+    static struct _KhompSMS : public Command
+    {
+        _KhompSMS()
+        {
+            complete_name = "sms";
+            brief = "Send an SMS message using a Khomp KGSM board.";
+
+            usage =                                                            \
+"Send an SMS message using a Khomp KGSM board.\n\n"                            \
+"Usage: khomp sms <device> <destination> <message..>\n"                        \
+"\tdevice      -- Device to use (same string used in Dial for \n"              \
+"\t               channel allocation).\n"                                      \
+"\tdestination -- Phone number of the destination.\n"                          \
+"\tmessage     -- Message to send.\n"                                          \
+"e.g. khomp sms b0 99887766 Oi, tudo bem?";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompSMS;
+
+    /* khomp log console */
+    static struct _KhompLogConsole : public Command
+    {
+        _KhompLogConsole()
+        {
+            complete_name = "log console";
+
+            options.push_back("errors");
+            options.push_back("warnings");
+            options.push_back("messages");
+            options.push_back("events");
+            options.push_back("commands");
+            options.push_back("audio");
+            options.push_back("modem");
+            options.push_back("link");
+            options.push_back("cas");
+            options.push_back("standard");
+            options.push_back("all");
+            options.push_back("no");
+            options.push_back("just");
+
+            brief = "Enables/disables showing console messages for the channel.";
+            usage =                                                            \
+"Enables/disables showing channel messages, where <options> can be:\n"         \
+"\terrors    -- Error messages, when something goes really \n"                 \
+"\t             wrong. Enabled by default.\n"                                  \
+"\twarnings  -- Warnings, used when something might not be \n"                 \
+"\t             going as expected. Enabled by default.\n"                      \
+"\tmessages  -- Generic messages, used to indicate some \n"                    \
+"\t             information. Enabled by default.\n"                            \
+"\tevents    -- Show received K3L events as console \n"                        \
+"\t             messages. Disabled by default.\n"                              \
+"\tcommands  -- Show sent K3L commands as console \n"                          \
+"\t             messages. Disabled by default.\n"                              \
+"\taudio     -- Enable messages for K3L audio events. \n"                      \
+"\t             Disabled by default (very verbose!).\n"                        \
+"\tmodem     -- Enable messages for data received from \n"                     \
+"\t             KGSM modems. Disabled by default.\n"                           \
+"\tlink      -- Enable logging of link status changes. \n"                     \
+"\t             Enabled by default.\n"                                         \
+"\tcas       -- Enable logging of MFCs and line state \n"                      \
+"\t             changes in KPR board. Disabled by default.\n"                  \
+"\tstandard  -- Special identifier, enable default \n"                         \
+"\t             console messages.\n"                                           \
+"\tall       -- Special identifier, enable ALL console \n"                     \
+"\t             messages (should not be used naively).\n\n"                    \
+"Usage: khomp log console <options>\n"                                         \
+"e.g. khomp log console standard";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogConsole;
+
+    /* khomp log disk */
+    static struct _KhompLogDisk : public Command
+    {
+        _KhompLogDisk()
+        {
+            complete_name = "log disk";
+
+            options.push_back("errors");
+            options.push_back("warnings");
+            options.push_back("messages");
+            options.push_back("events");
+            options.push_back("commands");
+            options.push_back("audio");
+            options.push_back("modem");
+            options.push_back("link");
+            options.push_back("cas");
+            options.push_back("functions");
+            options.push_back("threads");
+            options.push_back("locks");
+            options.push_back("streams");
+            options.push_back("standard");
+            options.push_back("debugging");
+            options.push_back("all");
+            options.push_back("no");
+            options.push_back("just");
+
+            brief = "Enables/disables logging to file messages for the channel.";
+            usage =                                                            \
+"Enables/disables the logging of channel messages to disk, where <options> \n" \
+"can be:\n"                                                                    \
+"\terrors    -- Error messages, when something goes really \n"                 \
+"\t             wrong. Enabled by default.\n"                                  \
+"\twarnings  -- Warnings, used when something might not be \n"                 \
+"\t             going as expected. Enabled by default.\n"                      \
+"\tmessages  -- Generic messages, used to indicate some \n"                    \
+"\t             information. Enabled by default.\n"                            \
+"\tevents    -- Record received K3L events as log messages. \n"                \
+"\t             Disabled by default.\n"                                        \
+"\tcommands  -- Record sent K3L commands as log messages. \n"                  \
+"\t             Disabled by default.\n"                                        \
+"\taudio     -- Enable messages for K3L audio events. \n"                      \
+"\t             Disabled by default (very verbose!).\n"                        \
+"\tmodem     -- Enable messages for data received from \n"                     \
+"\t             KGSM modems. Disabled by default.\n"                           \
+"\tlink      -- Enable logging of link status changes. \n"                     \
+"\t             Enabled by default.\n"                                         \
+"\tcas       -- Enable logging of MFCs and line state \n"                      \
+"\t             changes in KPR board. Disabled by default.\n"                  \
+"\tfunctions -- Enable debugging for functions. Disabled \n"                   \
+"\t             by default (should not be used naively!).\n"                   \
+"\tthreads   -- Enable debugging for threads. Disabled by \n"                  \
+"\t             default (should not be used naively!).\n"                      \
+"\tlocks     -- Enable debugging for locks. Disabled by \n"                    \
+"\t             default (should not be used naively!).\n"                      \
+"\tstreams   -- Enable debugging for streams. Disabled by \n"                  \
+"\t             default (should not be used naively!).\n"                      \
+"\tstandard  -- Special identifier, enable default messages.\n"                \
+"\tdebugging -- Special identifier, enable debugging messages \n"              \
+"\t             (should not be used naively).\n"                               \
+"\tall       -- Special identifier, enable ALL disk \n"                        \
+"\t             messages (DO NOT USE THIS!).\n\n"                              \
+"Usage: khomp log disk <options>\n"                                            \
+"e.g. khomp log disk <options>";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogDisk;
+
+    /* khomp log trace k3l */
+    static struct _KhompLogTraceK3L : public Command
+    {
+        _KhompLogTraceK3L()
+        {
+            complete_name = "log trace k3l";
+
+            options.push_back("on");
+            options.push_back("off");
+
+            brief = "Set K3L tracing (debug) option.";
+
+            usage =                                                            \
+"Sets the low-level log for K3L API. Should not be set for long time \n"       \
+"periods.\n\n"                                                                 \
+"Usage: khomp log trace k3l {on|off}\n"                                        \
+"e.g. khomp log trace k3l on";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogTraceK3L;
+
+    /* khomp log trace ISDN */
+    static struct _KhompLogTraceISDN : public Command
+    {
+        _KhompLogTraceISDN()
+        {
+            complete_name = "log trace isdn";
+
+            options.push_back("q931");
+            options.push_back("lapd");
+            options.push_back("system");
+            options.push_back("off");
+
+            brief = "Set ISDN signaling trace.";
+
+            usage =                                                            \
+"Sets the low-level log for ISDN signalling. Should not be set for \n"         \
+"long time periods.\n\n"                                                       \
+"Usage: khomp log trace isdn <what>[,<what2>[,..]]\n"                          \
+"\twhat -- \"q931\", \"lapd\", \"system\" or \"off\" \n"                       \
+"\t        (comma-separated values).\n"                                        \
+"e.g. khomp log trace isdn q931,system";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogTraceISDN;
+
+    /* khomp log trace R2 */
+    static struct _KhompLogTraceR2 : public Command
+    {
+        _KhompLogTraceR2()
+        {
+            complete_name = "log trace r2";
+
+            options.push_back("on");
+            options.push_back("off");
+
+            brief = "Set R2 signaling trace.";
+
+            usage =                                                            \
+"Sets the low-level log monitor for R2 digital signalling. Should not \n"      \
+"be set for long time periods.\n\n"                                            \
+"Usage: khomp log trace r2 {on|off}\n"                                         \
+"e.g. khomp log trace r2 on";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogTraceR2;
+
+    /* khomp get */
+    static struct _KhompGet : public Command
+    {
+        _KhompGet()
+        {
+            complete_name = "get";
+
+            options.push_back("echo-canceller");
+            options.push_back("out-of-band-dtmfs");
+            options.push_back("auto-fax-adjustment");
+            options.push_back("pulse-forwarding");
+            options.push_back("r2-strict-behaviour");
+            options.push_back("r2-preconnect-wait");
+            options.push_back("native-bridge");
+            options.push_back("suppression-delay");
+            options.push_back("context-fxo");
+            options.push_back("context-fxo-alt");
+            options.push_back("context-fxs");
+            options.push_back("context-fxs-alt");
+            options.push_back("context-gsm-call");
+            options.push_back("context-gsm-call-alt");
+            options.push_back("context-gsm-sms");
+            options.push_back("context-digital");
+            options.push_back("output-volume");
+            options.push_back("input-volume");
+
+            brief = "Get configuration options in the Khomp channel.";
+
+            usage =                                                            \
+"Usage: khomp get <option>\n"                                                  \
+"<option>  -- Shown below, with a short description each.\n\n"                 \
+"Option               Description\n"                                           \
+"echo-canceller       Gets the echo cancellation procedures if they are \n"    \
+"                     avaliable.\n"                                            \
+"out-of-band-dtmfs    Gets DTMFs to be sent out-of-band (using ast_frames) \n" \
+"                     instead of in-band (audio).\n"                           \
+"auto-fax-adjustment  Gets the automatic adjustment for FAX (mainly, \n"       \
+"                     disables the echo canceller).\n"                         \
+"pulse-forwarding     Gets the forwarding of detected pulses as DTMF tones.\n" \
+"r2-strict-behaviour  Gets the R2 protocol behavior while answering lines.\n"  \
+"r2-preconnect-wait   Sets the R2 protocol delay to pre-connect after \n"      \
+"                     sending ringback signal.\n"                              \
+"native-bridge        Enable/disable the native bridge mode for the channel.\n"\
+"suppression-delay    Enable/disable the internal buffer for DTMF \n"          \
+"                     suppression.\n"                                          \
+"context-fxo          Context (may be a template) for receiving FXO calls.\n"  \
+"context-fxo-alt      Alternative context (may be a template) for \n"          \
+"                     receiving FXO calls.\n"                                  \
+"context-fxs          Context (may be a template) for receiving FXS calls.\n"  \
+"context-fxs-alt      Alternative context (may be a template) for \n"          \
+"                     receiving FXS calls.\n"                                  \
+"context-gsm-call     Context (may be a template) for receiving GSM calls.\n"  \
+"context-gsm-call-alt Alternative context (may be a template) for \n"          \
+"                     receiving GSM calls.\n"                                  \
+"context-gsm-sms      Context (may be a template) for receiving GSM \n"        \
+"                     messages.\n"                                             \
+"context-digital      Context (may be a template) for receiving digital \n"    \
+"                     (E1) calls.\n"                                           \
+"output-volume        Gets the volume multiplier to be applied by the \n"      \
+"                     board over the output audio.\n"                          \
+"input-volume         Gets the volume multiplier to be applied by the \n"      \
+"                     board over the input audio.\n\n"                         \
+"FOR ALL COMMANDS, CHECK THE DOCUMENTATION.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompGet;
+
+    /* khomp set */
+    static struct _KhompSet : public Command
+    {
+        _KhompSet()
+        {
+            complete_name = "set";
+
+            options.push_back("echo-canceller");
+            options.push_back("out-of-band-dtmfs");
+            options.push_back("auto-fax-adjustment");
+            options.push_back("pulse-forwarding");
+            options.push_back("r2-strict-behaviour");
+            options.push_back("r2-preconnect-wait");
+            options.push_back("native-bridge");
+            options.push_back("suppression-delay");
+            options.push_back("context-fxo");
+            options.push_back("context-fxo-alt");
+            options.push_back("context-fxs");
+            options.push_back("context-fxs-alt");
+            options.push_back("context-gsm-call");
+            options.push_back("context-gsm-call-alt");
+            options.push_back("context-gsm-sms");
+            options.push_back("context-digital");
+            options.push_back("output-volume");
+            options.push_back("input-volume");
+            brief = "Ajust configuration options in the Khomp channel.";
+
+            usage =                                                            \
+"Usage: khomp set <option> <value>\n"                                          \
+"\t<option>  -- Shown below, with a short description each.\n"                 \
+"\t<value>   -- Depends on the option. Check the documentation for \n"         \
+"\t             more info.\n\n"                                                \
+"Option               Description\n"                                           \
+"echo-canceller       Sets the echo cancellation procedures if they are \n"    \
+"                     avaliable.\n"                                            \
+"out-of-band-dtmfs    Sets DTMFs to be sent out-of-band (using ast_frames) \n" \
+"                     instead of in-band (audio).\n"                           \
+"auto-fax-adjustment  Sets the automatic adjustment for FAX (mainly, \n"       \
+"                     disables the echo canceller).\n"                         \
+"pulse-forwarding     Sets the forwarding of detected pulses as DTMF tones.\n" \
+"r2-strict-behaviour  Sets the R2 protocol behavior while answering lines.\n"  \
+"r2-preconnect-wait   Sets the R2 protocol delay to pre-connect after \n"      \
+"                     sending ringback signal.\n"                              \
+"native-bridge        Enable/disable the native bridge mode for the channel.\n"\
+"suppression-delay    Enable/disable the internal buffer for DTMF \n"          \
+"                     suppression.\n"                                          \
+"context-fxo          Context (may be a template) for receiving FXO calls.\n"  \
+"context-fxo-alt      Alternative context (may be a template) for \n"          \
+"                     receiving FXO calls.\n"                                  \
+"context-fxs          Context (may be a template) for receiving FXS calls.\n"  \
+"context-fxs-alt      Alternative context (may be a template) for \n"          \
+"                     receiving FXS calls.\n"                                  \
+"context-gsm-call     Context (may be a template) for receiving GSM calls.\n"  \
+"context-gsm-call-alt Alternative context (may be a template) for \n"          \
+"                     receiving GSM calls.\n"                                  \
+"context-gsm-sms      Context (may be a template) for receiving GSM \n"        \
+"                     messages.\n"                                             \
+"context-digital      Context (may be a template) for receiving digital \n"    \
+"                     (E1) calls.\n"                                           \
+"output-volume        Sets the volume multiplier to be applied by the \n"      \
+"                     board over the output audio.\n"                          \
+"input-volume         Sets the volume multiplier to be applied by the \n"      \
+"                     board over the input audio.\n\n"                         \
+"FOR ALL COMMANDS, CHECK THE DOCUMENTATION.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompSet;
+
+    /* khomp log rotate */
+    static struct _KhompLogRotate : public Command 
+    {
+        _KhompLogRotate()
+        {
+            complete_name = "log rotate";
+            brief = "Rotate the files where the messages are being logged.";
+
+            usage =                                                            \
+"Rotate the files where the messages are being logged.\n\n"                    \
+"Usage: khomp log rotate";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogRotate;
+
+    /* khomp log status */
+    static struct _KhompLogStatus : public Command
+    {
+        _KhompLogStatus()
+        {
+            complete_name = "log status";
+            brief = "Show the status of the messages.";
+
+            usage =                                                            \
+"Show the status of the message system (enabled/disabled messages).\n\n"       \
+"Usage: khomp log status";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompLogStatus;
+
+    /* khomp revision */
+    static struct _KhompRevision : public Command
+    {
+        _KhompRevision()
+        {
+            complete_name = "revision";
+            brief = "Show revision number.";
+
+            usage =                                                            \
+"Show the internal revision number for this channel.\n\n"                      \
+"Usage: khomp revision";
+
+            _commands.push_back(this);
+        }
+
+        bool execute(int argc, char *argv[]);
+    } KhompRevision;
+
+    /* khomp send command */
+    static struct _KhompSendCommand : public Command
+    {
+        _KhompSendCommand()
+        {
+            complete_name = "send command";
+            brief = "Send an K3L API command directly to the board.";
+
+            usage =                                                            \
+"Send an K3L API command directly to the board.\n"                             \
+"WARNING: This command is for debugging only - just use if you know \n"        \
+"what you are doing!\n\n"                                                      \
+"Usage: khomp send command <board> <channel> <command> [argument]\n"           \
+"\tboard    -- Number of the board (start from 0).\n"                          \
+"\tchannel  -- Number of the channel (start from 0).\n"                        \
+"\tcommand  -- Number of API command (should be consulted in separate docs).\n"\
+"\targument -- Optimal string to use as parameter for the command.\n"          \
+"e.g. khomp send command 0 1 4 123456 - Send DTMFs 123456 throught \n"         \
+"                                       channel 1 on board 0.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompSendCommand;
+
+    /* khomp send raw */
+    static struct _KhompSendRawCommand : public Command 
+    {
+        _KhompSendRawCommand()
+        {
+            complete_name = "send raw command";
+            brief = "Send an command directly to a DSP at the board.";
+
+            usage =                                                            \
+"Send an command directly to some DSP at the board.\n"                         \
+"WARNING: This command is for debugging only - just use if you know \n"        \
+"what you are doing!\n\n"                                                      \
+"Usage: khomp send raw command <board> <dsp> <c0> <c1> [...]\n"                \
+"\tboard       -- Number of the board (start from 0).\n"                       \
+"\tchannel     -- Number of the channel (start from 0).\n"                     \
+"\tdsp         -- Number of the DSP.\n"                                        \
+"\tc0, c1, ... -- Hexadecimal numbers for the command.\n"                      \
+"e.g. khomp send raw command 0 1 0x4a 0x00 0x00 - Disables the internal \n"    \
+"                                                 audio delay on board 0.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompSendRawCommand;
+    
+    /* khomp select sim */
+    static struct _KhompSelectSim : public Command
+    {
+        _KhompSelectSim()
+        {
+            complete_name = "select sim";
+
+            brief = "Select SIM card, available to Khomp KGSM boards.";
+
+            usage =                                                            \
+"Select SIM card, available to Khomp KGSM boards.\n\n"                         \
+"Usage: khomp select sim <board> <channel> <sim_card>\n"                       \
+"\tboard    -- Number of the board (start from 0).\n"                          \
+"\tchannel  -- Number of the channel (start from 0), identifies \n"            \
+"\t            the modem inside the board.\n"                                  \
+"\tsim_card -- Number for the SIM card to select.\n"                           \
+"e.g. khomp select sim 0 0 2";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompSelectSim;
+
+    /* khomp kommuter */
+    static struct _KhompKommuterOnOff : public Command
+    {
+        _KhompKommuterOnOff()
+        {
+            complete_name = "kommuter";
+
+            options.push_back("on");
+            options.push_back("off");
+
+            brief = "Activate and deactives the Kommuter devices.";
+
+            usage =                                                            \
+"Manually activates or deactivates all kommuters connected to this machine.\n" \
+"This command will only be sent if kommuter-activation variable in \n"         \
+"khomp.conf is set to manual. All kommuter devices will be configure with \n"  \
+"the timeout defined in kommuter-timeout.\n\n"                                 \
+"Usage: khomp kommuter {on|off}\n"                                             \
+"\ton     -- Turn ON kommuter devices on this machine.\n"                      \
+"\toff    -- Turn OFF kommuter devices on this machine.";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompKommuterOnOff;
+    
+    /* khomp kommuter count */
+    static struct _KhompKommuterCount : public Command
+    {
+        _KhompKommuterCount()
+        {
+            complete_name = "kommuter count";
+
+            brief = "Prints the number of Kommuter devices.";
+
+            usage =                                                            \
+"Prints the number of Kommuter devices connected to this machine.\n\n"         \
+"Usage: khomp kommuter count";
+
+            _commands.push_back(this);
+        };
+
+        bool execute(int argc, char *argv[]);
+    } KhompKommuterCount;
+
+protected:
+    static switch_stream_handle_t* stream;
+    static switch_loadable_module_interface_t **module_interface;
+    static Commands _commands;
+    static std::string _khomp_usage;
+};
+
+/******************************************************************************/
+/******************************* Command Tree *********************************
+
+This tree is a overview for all commands in our module,
+when a command is added, deleted or modified, please, update our tree.
+
++ khomp 
+|
++ ---- channels 
+|    |
+-    + ---- disconnect
+|    |
+-    + ---- unblock
+|
++ ---- show
+|    | 
+-    + ---- calls
+|    |
+-    + ---- channels
+|    |    | 
+-    -    + ---- verbose
+|    |    |
+-    -    + ---- concise
+|    |
+-    + ---- statistics
+|    |    |  
+-    -    + ---- detailed
+|    |    |  
+-    -    + ---- verbose 
+|    |   
+-    + ---- links
+|         |
+-         + ---- errors
+|         |
+-         + ---- verbose
+|         |
+-         + ---- concise
+|    
++ ---- reset
+|    | 
+-    + ---- links
+|
++ ---- clear
+|    | 
+-    + ---- links
+|         |
+-         + ---- errors
+|         |
+-         + ---- statistics
+|
++ ---- log
+|    |
+-    + ---- console
+|    |    |
+-    -    + ---- errors
+|    |    |
+-    -    + ---- warnings
+|    |    |
+-    -    + ---- messages
+|    |    |
+-    -    + ---- events
+|    |    |
+-    -    + ---- commands
+|    |    |
+-    -    + ---- audio
+|    |    |
+-    -    + ---- link
+|    |    |
+-    -    + ---- cas
+|    |    |
+-    -    + ---- standard
+|    |    |
+-    -    + ---- all
+|    |
+-    + ---- disk
+|    |    |
+-    -    + ---- errors
+|    |    |
+-    -    + ---- warnings
+|    |    |
+-    -    + ---- messages
+|    |    |
+-    -    + ---- events
+|    |    |
+-    -    + ---- commands
+|    |    |
+-    -    + ---- audio
+|    |    |
+-    -    + ---- modem
+|    |    |
+-    -    + ---- link
+|    |    |
+-    -    + ---- cas
+|    |    |
+-    -    + ---- functions
+|    |    |
+-    -    + ---- threads
+|    |    |
+-    -    + ---- locks
+|    |    |
+-    -    + ---- streams
+|    |    |
+-    -    + ---- standard
+|    |    |
+-    -    + ---- debugging
+|    |    |
+-    -    + ---- all
+|    |     
+-    + ---- rotate
+|    |
+-    + ---- status
+|    |
+-    + ---- trace
+|         |
+-         + ---- isdn 
+|         |    |
+-         -    + ---- q931
+|         |    |
+-         -    + ---- lapd
+|         |    |
+-         -    + ---- system
+|         |    |
+-         -    + ---- off
+|         |
+-         + ---- k3l 
+|         |    |
+-         -    + ---- on
+|         |    |
+-         -    + ---- off
+|         |
+-         + ---- r2 
+|              |
+-              + ---- on
+|              |
+-              + ---- off
+|
++ ---- send
+|    |
+-    + ---- command
+|    |
+-    + ---- raw
+|
++ ---- get
+|
++ ---- set
+|
++ ---- select
+|    |
+-    + ---- sim
+|
++ ---- sms
+|
++ ---- summary
+|    |
+-    + ---- concise
+|    |
+-    + ---- verbose
+|
++ ---- revision
+|
++ ---- kommuter
+     |
+     + ---- on
+     |
+     + ---- off
+
+ ******************************************************************************/
+/******************************************************************************/
+
+#endif 
+
diff --git a/src/mod/endpoints/mod_khomp/include/defs.h b/src/mod/endpoints/mod_khomp/include/defs.h
new file mode 100644 (file)
index 0000000..f296882
--- /dev/null
@@ -0,0 +1,211 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _DEFS_H_
+#define _DEFS_H_
+
+/* formatation macros */
+#include "switch_version.h"
+#include "revision.h"
+
+#define KHOMP_LOG __FILE__, __SWITCH_FUNC__, __LINE__
+#define KHOMP_EVENT_MAINT "khomp::maintenance"
+
+#define OBJ_FMT(dev,obj,msg) \
+    FMT("%s (d=%02d,c=%03d) " msg) % __SWITCH_FUNC__ % dev % obj
+
+#define OBJ_MSG(dev,obj,msg) \
+    "%s (d=%02d,c=%03d) " msg, __SWITCH_FUNC__, dev, obj
+
+#define PVT_FMT(tgt,msg) \
+    FMT("%s (d=%02hu,c=%03hu) " msg) % __SWITCH_FUNC__ % tgt.device % tgt.object
+
+#define PVT_MSG(tgt,msg) \
+    "%s (d=%02hu,c=%03hu) " msg, __SWITCH_FUNC__, tgt.device, tgt.object
+
+#define D(x) ( FMT( "%s: " x ) % __func__ )
+
+#define STR(fmt) \
+    STG(fmt).c_str()
+
+/* version controller macro */
+#define SWITCH_LESS_THAN(x,y,z)                                                           \
+   (FS_VERSION_MICRO != -1) &&                                                            \
+   (((FS_VERSION_MAJOR == x)  && (FS_VERSION_MINOR == y)  &&  (FS_VERSION_MICRO <= z)) || \
+   ((FS_VERSION_MAJOR == x)  && (FS_VERSION_MINOR < y)) || (FS_VERSION_MAJOR < x))
+
+/* signalling groups macro */
+#define CASE_R2_SIG         \
+    case ksigR2Digital:     \
+    case ksigContinuousEM:  \
+    case ksigPulsedEM:      \
+    case ksigUserR2Digital: \
+    case ksigOpenCAS:       \
+    case ksigOpenR2
+/*
+    case ksigLineSide:      \
+    case ksigCAS_EL7:       \
+    case ksigE1LC
+*/
+
+#define CASE_RDSI_SIG       \
+    case ksigPRI_EndPoint:  \
+    case ksigPRI_Network:   \
+    case ksigPRI_Passive:   \
+    case ksigOpenCCS
+
+#define CASE_FLASH_GRP          \
+    case ksigLineSide:          \
+    case ksigCAS_EL7:           \
+    case ksigE1LC
+
+/******************************************************************************/
+
+/* Buffering size constants */
+
+#define SILENCE_PACKS               2
+
+#define KHOMP_READ_PACKET_TIME     16                            // board sample (ms)
+
+#define KHOMP_READ_PACKET_SIZE    (KHOMP_READ_PACKET_TIME *   8) // asterisk sample size (bytes)
+
+#define KHOMP_MIN_READ_PACKET_SIZE (10 * 8)                      // min size to return on khomp_read
+#define KHOMP_MAX_READ_PACKET_SIZE (30 * 8)                      // max size to return on khomp_read
+
+#define KHOMP_AUDIO_BUFFER_SIZE   (KHOMP_READ_PACKET_SIZE  *  8) // buffer size (bytes)
+
+/* debug and log macros */
+#define DBG(x,y) \
+    { \
+        if (K::Logger::Logg.classe( C_DBG_##x ).enabled()) \
+                K::Logger::Logg( C_DBG_##x , y ); \
+    }
+
+#define LOG(x,y) \
+    { \
+        K::Logger::Logg( C_##x , y ); \
+    }
+
+#define LOGC(x,y) \
+    { \
+        if (K::Logger::Logg.classe( C_##x ).enabled()) \
+            LOG( x , y ); \
+    }
+
+/* useful to debug arguments */
+#define DEBUG_CLI_CMD() \
+{ \
+    K::Logger::Logg2(C_CLI,stream,FMT("argc: %d ") % argc); \
+    for(int i = 0;i< argc;i++)                              \
+        K::Logger::Logg2(C_CLI,stream,FMT("argv[%d]:%s ") % i % argv[i]); \
+}
+
+/* macros to cli commands */
+#define ARG_CMP(a,b) (argv[a] && !strncasecmp(argv[a],b,sizeof(b))) 
+#define EXEC_CLI_CMD(command) Cli::command.execute(argc,argv)
+
+/* macro to string treats */
+#define SAFE_sprintf(a, ...)    snprintf(a,sizeof(a), __VA_ARGS__)
+#define SAFE_strcasecmp(a,b)    strncasecmp(a, b, sizeof(b))
+
+/* tags for timers */
+#define TM_VAL_CALL    (unsigned int)0x01
+#define TM_VAL_CHANNEL (unsigned int)0x02
+
+/* macro to creating contexts */
+#define BEGIN_CONTEXT do
+#define END_CONTEXT while(false);
+
+/* Define log type */
+typedef enum
+{
+    C_CLI,      /* cli msgs    */
+
+    C_ERROR,    /* errors      */
+    C_WARNING,  /* warnings    */
+    C_MESSAGE,  /* normal msgs */
+
+    C_EVENT,    /* k3l events   */
+    C_COMMAND,  /* k3l commands */
+
+    C_AUDIO_EV, /* k3l audio events */
+    C_MODEM_EV, /* gsm modem events */
+    C_LINK_STT, /* link status msgs */
+    C_CAS_MSGS, /* cas events msgs  */
+
+    C_DBG_FUNC,
+    C_DBG_LOCK,
+    C_DBG_THRD,
+    C_DBG_STRM,
+    
+    C_DBG_CONF,
+}
+class_type;
+
+typedef enum
+{
+    O_CONSOLE,
+    O_GENERIC,
+    O_R2TRACE,
+}
+output_type;
+
+typedef enum
+{
+    SCE_SHOW_WARNING,
+    SCE_SHOW_DEBUG,
+    SCE_SHOW_SAME,
+    SCE_HIDE
+}
+send_cmd_error_type;
+
+typedef enum 
+{
+    T_UNKNOWN = 2,
+    T_TRUE = 1,
+    T_FALSE = 0,
+}
+TriState;
+    
+
+#endif
diff --git a/src/mod/endpoints/mod_khomp/include/frame.h b/src/mod/endpoints/mod_khomp/include/frame.h
new file mode 100644 (file)
index 0000000..87b968b
--- /dev/null
@@ -0,0 +1,160 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _FRAME_HPP_
+#define _FRAME_HPP_
+
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include <ringbuffer.hpp>
+
+#include "globals.h"
+
+struct FrameStorage
+{
+    static const unsigned int frame_count = 24;//6;
+    static const unsigned int audio_count = 24;//4;
+
+    FrameStorage(switch_codec_t * codec, int packet_size);
+    virtual ~FrameStorage();
+
+    inline switch_frame_t * next_frame(void)
+    {
+        return &(_frames[next_index()]);
+    }
+
+    inline unsigned int next_index()
+    {
+        unsigned int tmp = _index;
+
+        if (++_index >= frame_count)
+            _index = 0;
+
+        return tmp;
+    }
+
+    inline switch_frame_t * cng_frame(void)
+    {
+        return &_cng_frame;
+    }
+
+    char * audio_buffer()
+    {
+        return _buffer;
+    };
+
+ private:
+    switch_frame_t   _cng_frame;
+
+    switch_frame_t * _frames;
+    char           * _buffer;
+
+    unsigned int     _index;
+};
+
+/* Internal frame array structure. */
+template < int S >
+struct FrameManager: protected FrameStorage
+{
+    typedef char Packet[ S ];
+
+    typedef Ringbuffer < Packet >  AudioBuffer;
+
+    FrameManager(switch_codec_t * codec)
+    : FrameStorage(codec, S),
+      _audio(audio_count, (Packet*)audio_buffer())
+    {};
+
+//    ~FrameManager();
+
+    // may throw Ringbuffer::BufferEmpty
+    switch_frame_t * pick(void)
+    {
+        try
+        {
+            /* try to consume from buffer.. */
+            Packet & a = _audio.consumer_start();
+
+            switch_frame * f = next_frame();
+
+            /* adjust pointer */
+            f->data = (char *)(&a);
+
+            /* advance now */
+            _audio.consumer_commit();
+            return f;
+        }
+        catch (...) // AudioBuffer::BufferEmpty & e)
+        {
+            return NULL;
+        }
+    }
+
+    // may throw Ringbuffer::BufferFull
+    bool give(const char * buf, unsigned int size)
+    {
+        return _audio.provider_partial(buf, size);
+    }
+
+    switch_frame_t * cng(void)
+    {
+        return cng_frame();
+    }
+
+    void clear()
+    {
+        _audio.clear();
+    }
+
+ protected:
+    AudioBuffer      _audio;
+
+    unsigned int     _index;
+};
+
+typedef FrameManager < Globals::switch_packet_size > FrameSwitchManager;
+typedef FrameManager < Globals::boards_packet_size > FrameBoardsManager;
+
+#endif /* _FRAME_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/include/globals.h b/src/mod/endpoints/mod_khomp/include/globals.h
new file mode 100644 (file)
index 0000000..f212d63
--- /dev/null
@@ -0,0 +1,119 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _GLOBALS_H_
+#define _GLOBALS_H_
+#include "k3lapi.hpp"
+
+#include <config_options.hpp>
+#include <k3lutil.hpp>
+#include <verbose.hpp>
+#include <regex.hpp>
+#include <timer.hpp>
+
+#include <vector>
+#include <string>
+#include <fstream>
+
+#include <simple_lock.hpp>
+
+extern "C"
+{
+    #include <switch.h>
+}
+
+/* As this is a static-variable-only struct, member variable *
+ * names need not to get "_" in front of the name            */
+
+struct Globals
+{
+    typedef void * global_timer_data;
+    typedef void (global_timer_func)(global_timer_data);
+    typedef TimerTemplate < global_timer_func, global_timer_data > GlobalTimer;
+    
+    typedef SimpleNonBlockLock<25,100> Mutex;
+    
+    /* FreeSWITCH variables for packets and buffer */
+    // in ms
+    static const unsigned int switch_packet_duration  = 30;
+    static const unsigned int boards_packet_duration  = 24;
+    // in bytes
+    static const unsigned int switch_packet_size = switch_packet_duration *  8;
+    static const unsigned int boards_packet_size = boards_packet_duration *  8;
+    static const unsigned int    cng_buffer_size = (switch_packet_size > boards_packet_size ? switch_packet_size : boards_packet_size);    
+
+    /* Father */
+    static K3LAPI                            k3lapi;
+
+    /* Son */
+    static K3LUtil                           k3lutil;
+
+    /* Holy Spirit */
+    static Verbose                           verbose;
+
+    /* Global timer */ 
+    static  GlobalTimer                    * global_timer;
+
+    /* Mutex to KhompPvt allocation */
+    static Mutex                             khomp_alloc_mutex;
+
+    /* Config options class */
+    static ConfigOptions                     options;
+
+    /* FreeSWITCH Articular Ligaments */ 
+    static switch_endpoint_interface_t     * khomp_endpoint_interface;
+    static switch_endpoint_interface_t     * khomp_sms_endpoint_interface;
+    static switch_endpoint_interface_t     * khomp_pr_endpoint_interface;
+    static switch_application_interface_t  * khomp_app_inteface;
+    static switch_api_interface_t          * api_interface;
+    static switch_memory_pool_t            * module_pool;
+    
+    /* Still a nice workaround */ 
+    volatile static bool                     logs_being_rotated;
+
+    /* Trace flags */
+    static bool                              flag_trace_rdsi;
+};
+
+#endif /* _GLOBALS_H_ */
+
diff --git a/src/mod/endpoints/mod_khomp/include/k3l.h b/src/mod/endpoints/mod_khomp/include/k3l.h
new file mode 100644 (file)
index 0000000..046bd66
--- /dev/null
@@ -0,0 +1,1996 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License
+  Version 1.1 (the "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file
+  under the MPL, indicate your decision by deleting the provisions above and
+  replace them with the notice and other provisions required by the LGPL
+  License. If you do not delete the provisions above, a recipient may use your
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation,
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _GENERATED_K3L_H_
+#define _GENERATED_K3L_H_
+#if !defined KLTYPEDEFS_H
+#define KLTYPEDEFS_H
+#if defined( _WINDOWS ) || defined( _Windows ) || defined( _WIN32 )
+       #ifndef KWIN32
+       #define KWIN32 1
+       #endif
+#endif
+
+#ifdef KWIN32
+       typedef __int64                         int64;
+       typedef unsigned __int64        uint64;
+       #define Kstdcall __stdcall
+#else
+       typedef long long                               int64;
+       typedef unsigned long long              uint64;
+       #define Kstdcall 
+#endif
+typedef int                                    int32;
+typedef unsigned int           uint32;
+typedef uint64                     intptr;
+typedef intptr              stackint;
+typedef short int                      int16;
+typedef unsigned short int     uint16;
+typedef char                           int8;
+typedef unsigned char          uint8;
+typedef unsigned char          byte;
+typedef char                           sbyte;
+typedef double                         float64;
+typedef float                          float32;
+typedef int32                          stt_code;
+
+enum KLibraryStatus 
+{
+       ksSuccess =                     0,
+       ksFail =                        1,
+       ksTimeOut =                     2,
+       ksBusy =                        3,
+       ksLocked =                      4,
+       ksInvalidParams =       5,
+       ksEndOfFile =           6,
+       ksInvalidState =        7,
+       ksServerCommFail =      8,
+       ksOverflow =            9,
+    ksUnderrun =        10,
+       ksNotFound =            11,
+    ksNotAvailable =    12
+};     
+enum KTxRx
+{
+       kNoTxRx = 0x0,
+       kTx             = 0x1,
+       kRx             = 0x2,
+       kBoth   = 0x3
+}; 
+
+#define KMAX_SERIAL_NUMBER                     12 
+#define KMAX_E1_CHANNELS                       30
+#define KMAX_DIAL_NUMBER               20
+#define KMAX_ADDRESS                           60
+#define KMAX_DSP_NAME                  8
+#define KMAX_STR_VERSION               80
+#define KMAX_BUFFER_ADDRESSES          16
+#define KMAX_LOG                    1024
+#define KMAX_SIP_DATA               248
+#define KMAX_GSM_CALLS              6
+#define KMAX_GSM_OPER_NAME          32
+#define KMAX_GSM_IMEI_SIZE          16
+#endif
+#if !defined KVOIPDEFS_H
+#define KVOIPDEFS_H
+enum KRejectReason
+{
+       UserBusy = 0,
+       UserNotFound,
+       NoAnswer,
+       Decline,
+       ServiceUnavailable,
+       ServerInternalError,
+       UnknownRejectReason
+};
+enum KSIP_Failures
+{
+       kveResponse_200_OK_Success                      = 200,
+    kveRedirection_300_MultipleChoices                 = 300,
+       kveRedirection_301_MovedPermanently                     = 301,
+       kveRedirection_302_MovedTemporarily                     = 302,
+       kveRedirection_305_UseProxy                                     = 305,
+       kveRedirection_380_AlternativeService           = 380,
+       kveFailure_400_BadRequest                                       = 400,
+       kveFailure_401_Unauthorized                                     = 401,
+       kveFailure_402_PaymentRequired                          = 402,
+       kveFailure_403_Forbidden                                        = 403,
+       kveFailure_404_NotFound                                         = 404,
+       kveFailure_405_MethodNotAllowed                         = 405,
+       kveFailure_406_NotAcceptable                            = 406,
+       kveFailure_407_ProxyAuthenticationRequired      = 407,
+       kveFailure_408_RequestTimeout                           = 408,
+       kveFailure_410_Gone                                                     = 410,
+       kveFailure_413_RequestEntityTooLarge            = 413,
+       kveFailure_414_RequestURI_TooLong                       = 414,
+       kveFailure_415_UnsupportedMediaType                     = 415,
+       kveFailure_416_UnsupportedURI_Scheme            = 416,
+       kveFailure_420_BadExtension                                     = 420,
+       kveFailure_421_ExtensionRequired                        = 421,
+       kveFailure_423_IntervalTooBrief                         = 423,
+       kveFailure_480_TemporarilyUnavailable           = 480,
+       kveFailure_481_CallDoesNotExist                         = 481,
+       kveFailure_482_LoopDetected                                     = 482,
+       kveFailure_483_TooManyHops                                      = 483,
+       kveFailure_484_AddressIncomplete                        = 484,
+       kveFailure_485_Ambiguous                                        = 485,
+       kveFailure_486_BusyHere                                         = 486,
+       kveFailure_487_RequestTerminated                        = 487,
+       kveFailure_488_NotAcceptableHere                        = 488,
+       kveFailure_491_RequestPending                           = 491,
+       kveFailure_493_Undecipherable                           = 493,
+       kveServer_500_InternalError                                     = 500,
+       kveServer_501_NotImplemented                            = 501,
+       kveServer_502_BadGateway                                        = 502,
+       kveServer_503_ServiceUnavailable                        = 503,
+       kveServer_504_TimeOut                                           = 504,
+       kveServer_505_VersionNotSupported                       = 505,
+       kveServer_513_MessageTooLarge                           = 513,
+       kveGlobalFailure_600_BusyEverywhere                     = 600,
+       kveGlobalFailure_603_Decline                            = 603,
+       kveGlobalFailure_604_DoesNotExistAnywhere       = 604,
+       kveGlobalFailure_606_NotAcceptable                      = 606
+};
+enum KVoIPRegTypes
+{
+   kvrtRegister    =   0,
+   kvrtUnregister  =   1
+};
+
+struct KVoIPCallParams
+{
+       sbyte ToUser[ KMAX_ADDRESS + 1 ];
+       sbyte FromUser[ KMAX_ADDRESS + 1 ];
+    sbyte FromUserIP[ KMAX_ADDRESS + 1 ];
+};
+struct KVoIPEvRegisterParams
+{
+    KVoIPRegTypes Register;
+       sbyte User[ KMAX_ADDRESS + 1 ];
+       sbyte ProxyIP[ KMAX_ADDRESS + 1 ];
+};
+struct KVoIPSeize 
+{
+       sbyte FromUser[ KMAX_ADDRESS + 1 ];
+       sbyte ToUser[ KMAX_ADDRESS + 1 ];
+    sbyte ProxyIP[ KMAX_ADDRESS + 1 ];
+};
+#endif
+#if !defined KLDEFS_H
+#define KLDEFS_H
+
+
+
+#define CM_SEIZE                                       0x01
+     
+#define CM_SYNC_SEIZE                          0x02
+
+#define CM_SIP_REGISTER             0x03
+
+#define CM_DIAL_DTMF                           0x04
+
+#define CM_DISCONNECT                          0x05
+
+#define CM_CONNECT                                     0x06
+
+#define CM_PRE_CONNECT                         0x07
+
+#define CM_CAS_CHANGE_LINE_STT         0x08
+
+#define CM_CAS_SEND_MFC                                0x09
+
+#define CM_SET_FORWARD_CHANNEL         0x0A
+
+#define CM_CAS_SET_MFC_DETECT_MODE     0x0B
+
+#define CM_DROP_COLLECT_CALL           0x0C
+
+#define CM_MAKE_CALL                           0x0D
+
+#define CM_RINGBACK                            0x0E
+
+#define CM_USER_INFORMATION         0x0F
+
+#define CM_VOIP_SEIZE                          0x23
+
+
+#define        CM_LOCK_INCOMING                        0x10
+
+#define CM_UNLOCK_INCOMING                     0x11
+
+#define CM_LOCK_OUTGOING                       0x12
+
+#define CM_UNLOCK_OUTGOING                     0x13
+
+#define CM_START_SEND_FAIL                     0x14
+
+#define CM_STOP_SEND_FAIL                      0x15
+
+#define CM_END_OF_NUMBER            0x16
+
+#define CM_SEND_SIP_DATA                       0x17
+
+#define CM_SS_TRANSFER              0x18
+
+#define CM_GET_SMS                  0x19
+
+#define CM_PREPARE_SMS              0x1A
+
+#define CM_SEND_SMS                 0x1B
+
+#define CM_SEND_TO_MODEM            0x1C
+
+#define CM_CHECK_NEW_SMS            0x1D
+
+#define CM_ISDN_SEND_SUBADDRESSES   0x1E
+
+#define CM_CT_TRANSFER              0x1F
+
+#define CM_ENABLE_DTMF_SUPPRESSION     0x30
+
+#define CM_DISABLE_DTMF_SUPPRESSION    0x31
+
+#define CM_ENABLE_AUDIO_EVENTS         0x32
+
+#define CM_DISABLE_AUDIO_EVENTS                0x33
+
+#define CM_ENABLE_CALL_PROGRESS                0x34
+
+#define CM_DISABLE_CALL_PROGRESS       0x35
+
+#define CM_FLASH                                       0x36
+
+#define CM_ENABLE_PULSE_DETECTION      0x37
+
+#define CM_DISABLE_PULSE_DETECTION     0x38
+
+#define CM_ENABLE_ECHO_CANCELLER       0x39
+
+#define CM_DISABLE_ECHO_CANCELLER      0x3A
+
+#define CM_ENABLE_AGC                          0x3B
+
+#define CM_DISABLE_AGC                         0x3C
+
+#define CM_ENABLE_HIGH_IMP_EVENTS      0x3D
+
+#define CM_DISABLE_HIGH_IMP_EVENTS     0x3E
+
+#define CM_ENABLE_CALL_ANSWER_INFO  0x40
+
+#define CM_DISABLE_CALL_ANSWER_INFO 0x41
+
+#define CM_START_WATCHDOG           0x45
+
+#define CM_STOP_WATCHDOG            0x46
+
+#define CM_NOTIFY_WATCHDOG          0x47
+
+#define CM_WATCHDOG_COUNT           0x48
+
+#define CM_HOLD_SWITCH             0x4A
+
+#define CM_MPTY_CONF               0x4B
+
+#define CM_MPTY_SPLIT              0x4C
+
+#define CM_SIM_CARD_SELECT         0x4D
+
+#define CM_START_FAX_TX                                0x50
+
+#define CM_STOP_FAX_TX                 0x51
+
+#define CM_ADD_FAX_FILE                                0x52
+
+#define CM_ADD_FAX_PAGE_BREAK          0x53
+
+#define CM_START_FAX_RX                                0x54
+
+#define CM_STOP_FAX_RX                     0x55
+
+#define CM_RESET_LINK                          0xF1
+
+#define CM_CLEAR_LINK_ERROR_COUNTER 0xF2
+
+#define CM_SEND_DEVICE_SECURITY_KEY 0xF3
+
+#define CM_RESET_MODEM              0xF4
+
+#define CM_ISDN_DISABLE_LINK        0xF5
+
+#define CM_ISDN_ENABLE_LINK         0xF6
+
+
+#define EV_CHANNEL_FREE                                0x01
+
+#define EV_CONNECT                                     0x03
+
+#define EV_DISCONNECT                          0x04
+
+#define EV_CALL_SUCCESS                                0x05
+
+#define EV_CALL_FAIL                           0x06
+
+#define EV_NO_ANSWER                           0x07
+
+#define EV_BILLING_PULSE                       0x08
+
+#define EV_SEIZE_SUCCESS                       0x09
+
+#define EV_SEIZE_FAIL                          0x0A
+
+#define EV_SEIZURE_START                       0x0B
+
+#define EV_CAS_LINE_STT_CHANGED                0x0C
+
+#define EV_CAS_MFC_RECV                                0x0D
+
+#define EV_NEW_CALL                 0x0E
+
+#define EV_USER_INFORMATION         0x0F
+
+#define EV_DIALED_DIGIT             0x10
+
+#define EV_SIP_REGISTER_INFO        0x11
+
+#define EV_RING_DETECTED            0x12
+
+#define EV_ISDN_SUBADDRESSES        0x13
+
+#define EV_CALL_HOLD_START                     0x16
+
+#define EV_CALL_HOLD_STOP                      0x17
+
+#define EV_SS_TRANSFER_FAIL         0x18
+
+#define EV_FLASH                    0x19
+
+#define EV_ISDN_PROGRESS_INDICATOR     0x1A
+
+#define EV_CT_TRANSFER_SUCCESS      0x1B
+
+#define EV_CT_TRANSFER_FAIL         0x1C
+
+#define EV_DTMF_DETECTED                       0x20
+
+#define EV_DTMF_SEND_FINISH                    0x21
+
+#define EV_AUDIO_STATUS                                0x22
+
+#define EV_CADENCE_RECOGNIZED          0x23
+#define EV_CALL_PROGRESS                       EV_CADENCE_RECOGNIZED
+
+#define EV_END_OF_STREAM                       0x24
+
+#define EV_PULSE_DETECTED                      0x25
+
+#define EV_POLARITY_REVERSAL           0x26
+
+#define EV_CALL_ANSWER_INFO            0x27
+
+#define EV_COLLECT_CALL                0x28
+
+#define EV_SIP_DTMF_DETECTED        0x29
+
+#define EV_SIP_DATA                            0x2A
+
+#define EV_RECV_FROM_MODEM                     0x42
+
+#define EV_NEW_SMS                  0x43
+
+#define EV_SMS_INFO                 0x44
+
+#define EV_SMS_DATA                 0x45
+
+#define EV_SMS_SEND_RESULT          0x46
+
+#define EV_CALL_MPTY_START                     0x47
+
+#define EV_CALL_MPTY_STOP                      0x48
+
+#define EV_GSM_COMMAND_STATUS          0x49
+
+#define EV_WATCHDOG_COUNT           0x60
+
+#define EV_CHANNEL_FAIL                                0x30
+
+#define EV_REFERENCE_FAIL                      0x31
+
+#define EV_INTERNAL_FAIL                       0x32
+
+#define EV_HARDWARE_FAIL                       0x33
+
+#define EV_LINK_STATUS                         0x34
+
+#define EV_PHYSICAL_LINK_UP                    0x35
+
+#define EV_PHYSICAL_LINK_DOWN          0x36
+
+#define EV_CLIENT_RECONNECT            0xF0
+
+#define EV_CLIENT_AUDIOLISTENER_TIMEOUT     0xF1
+
+#define EV_CLIENT_BUFFERED_AUDIOLISTENER_OVERFLOW   0xF2
+
+#define EV_REQUEST_DEVICE_SECURITY_KEY 0xF3
+
+#define EV_DISK_IS_FULL                0xF4
+
+
+#define CM_SEND_DTMF                           0xD1
+
+#define CM_STOP_AUDIO                          0xD2
+
+#define CM_HARD_RESET                          0xF0
+
+#define EV_VOIP_SEIZURE                                        0x40
+
+#define EV_SEIZURE                                     0x41
+
+#define EV_FAX_CHANNEL_FREE                    0x50
+
+#define EV_FAX_FILE_SENT                       0x51
+#define EV_FAX_FILE_FAIL                       0x52
+#define EV_FAX_MESSAGE_CONFIRMATION 0x53
+#define EV_FAX_TX_TIMEOUT                      0x54
+#define EV_FAX_PAGE_CONFIRMATION EV_FAX_MESSAGE_CONFIRMATION
+#define EV_FAX_REMOTE_INFO                     0x55
+
+#endif
+
+   #define FC_REMOTE_FAIL                      0x01
+   #define FC_LOCAL_FAIL                       0x02
+   #define FC_REMOTE_LOCK                      0x03
+  
+   #define FC_LINE_SIGNAL_FAIL         0x04
+   #define FC_ACOUSTIC_SIGNAL_FAIL     0x05
+
+enum KChannelFail
+{
+       kfcRemoteFail = FC_REMOTE_FAIL,
+       kfcLocalFail = FC_LOCAL_FAIL,
+       kfcRemoteLock = FC_REMOTE_LOCK,
+       kfcLineSignalFail = FC_LINE_SIGNAL_FAIL,
+       kfcAcousticSignalFail = FC_ACOUSTIC_SIGNAL_FAIL
+};
+
+   #define ER_INTERRUPT_CTRL           0x01
+   #define ER_COMMUNICATION_FAIL       0x02
+   #define ER_PROTOCOL_FAIL                    0x03
+   #define ER_INTERNAL_BUFFER          0x04
+       #define ER_MONITOR_BUFFER               0x05
+       #define ER_INITIALIZATION               0x06
+       #define ER_INTERFACE_FAIL               0x07
+       #define ER_CLIENT_COMM_FAIL             0x08
+       #define ER_POLL_CTRL                    0x09
+       #define ER_EVT_BUFFER_CTRL              0x0A
+
+       #define ER_INVALID_CONFIG_VALUE 0x0B
+
+       #define ER_INTERNAL_GENERIC_FAIL 0x0C
+
+enum KInternalFail
+{
+       kifInterruptCtrl = ER_INTERRUPT_CTRL,
+       kifCommunicationFail = ER_COMMUNICATION_FAIL,
+       kifProtocolFail = ER_PROTOCOL_FAIL,
+       kifInternalBuffer = ER_INTERNAL_BUFFER,
+       kifMonitorBuffer = ER_MONITOR_BUFFER,
+       kifInitialization = ER_INITIALIZATION,
+       kifInterfaceFail = ER_INTERFACE_FAIL,
+       kifClientCommFail = ER_CLIENT_COMM_FAIL
+};     
+
+   #define FS_CHANNEL_LOCKED           0x01
+   #define FS_INCOMING_CHANNEL         0x02
+   #define FS_CHANNEL_NOT_FREE         0x03
+   #define FS_DOUBLE_SEIZE                     0x04
+   #define FS_LOCAL_CONGESTION         0x06
+   #define FS_NO_DIAL_TONE                     0x07
+enum KSeizeFail
+{
+       ksfChannelLocked = FS_CHANNEL_LOCKED,
+       ksfIncomingChannel = FS_INCOMING_CHANNEL,
+       ksfChannelBusy = FS_CHANNEL_NOT_FREE,
+       ksfDoubleSeizure = FS_DOUBLE_SEIZE,
+       ksfCongestion = FS_LOCAL_CONGESTION,
+       ksfNoDialTone = FS_NO_DIAL_TONE
+};
+#if !defined KH100DEFS_H
+#define KH100DEFS_H
+
+#define CM_SEND_TO_CTBUS                       0x90
+
+#define CM_RECV_FROM_CTBUS                     0x91
+
+#define CM_SEND_RANGE_TO_CTBUS         0x92
+
+#define CM_SETUP_H100                          0x93
+
+enum KH100ConfigIndex
+{
+       khciDeviceMode = 0,
+       khciMasterGenClock = 1,
+       khciCTNetRefEnable = 4,
+       khciSCbusEnable = 6,
+       khciHMVipEnable = 7,
+       khciMVip90Enable = 8,
+       khciCTbusDataEnable = 9,
+       khciCTbusFreq03_00 = 10,
+       khciCTbusFreq07_04 = 11,
+       khciCTbusFreq11_08 = 12,
+       khciCTbusFreq15_12 = 13,
+       khciMax = 14,
+       khciMasterDevId = 20,
+       khciSecMasterDevId = 21,
+       khciCtNetrefDevId = 22,
+    khciMaxH100ConfigIndex
+};     
+
+enum KMasterPLLClockReference
+{
+    h100_Ref_FreeRun = 0,
+    h100_Ref_holdover = 1,
+       h100_Automatic = 2,
+    h100_Ref_ctnetref = 7,
+    h100_Ref_link0 = 8,
+    h100_Ref_link1 = 9
+};
+enum KSlavePLLClockReference
+{
+    h100_PllLoc_ClkA = 0,
+    h100_PllLoc_ClkB = 1,
+    h100_PllLoc_SCBus = 2,
+    h100_PllLoc_MVIP90 = 3,
+    h100_PllLoc_Link0 = 4,
+    h100_PllLoc_Link1 = 5,
+    h100_PllLoc_Error = 6
+};
+
+#define H100_DEVICE_MODE                               khciDeviceMode
+       enum KH100Mode
+       {
+               h100_Slave,
+               h100_Master,
+               h100_StandbyMaster,
+               h100_Diagnostic,
+               h100_NotConnected
+       };
+#define H100_MASTER_GEN_CLOCK                  khciMasterGenClock
+       enum KH100SelectCtbusClock
+       {
+               h100_scClockA,
+               h100_scClockB
+       };
+
+#define H100_CT_NETREF_ENABLE                  khciCTNetRefEnable
+       enum KH100CtNetref
+       {
+               h100_nrOff,
+               h100_nrEnable
+       };
+#define        H100_SCBUS_ENABLE                               khciSCbusEnable
+       enum KH100ScbusEnable
+       {
+               h100_seOff,
+               h100_seOn2Mhz,
+               h100_seOn4Mhz,
+               h100_seOn8Mhz
+       };
+#define H100_HMVIP_ENABLE                              khciHMVipEnable
+
+#define H100_MVIP90_ENABLE                             khciMVip90Enable
+
+#define H100_CTBUS_DATA_ENABLE                 khciCTbusDataEnable
+
+enum KH100Enable
+{
+       h100_On = 0x01,
+       h100_Off = 0x00
+};
+       
+#define H100_CTBUS_FREQ_03_00                  khciCTbusFreq03_00
+#define H100_CTBUS_FREQ_07_04                  khciCTbusFreq07_04
+#define H100_CTBUS_FREQ_11_08                  khciCTbusFreq11_08
+#define H100_CTBUS_FREQ_15_12                  khciCTbusFreq15_12
+
+enum KH100CtbusFreq
+{
+       h100_cf_2Mhz    =       0,
+       h100_cf_4Mhz    =       1,
+       h100_cf_8Mhz    =       2 
+};
+
+#endif
+
+#define CM_MIXER                                       0x60
+
+#define CM_CLEAR_MIXER                         0x61
+
+#define CM_PLAY_FROM_FILE                      0x62
+
+#define CM_RECORD_TO_FILE                      0x63
+       
+#define CM_PLAY_FROM_STREAM                    0x64 
+
+#define CM_INTERNAL_PLAY                       0x65 
+
+#define CM_STOP_PLAY                           0x66
+
+#define CM_STOP_RECORD                         0x67
+
+#define CM_PAUSE_PLAY                          0x68
+
+#define CM_PAUSE_RECORD                                0x69
+
+#define CM_RESUME_PLAY                         0x6A
+
+#define CM_RESUME_RECORD                       0x6B
+
+#define CM_INCREASE_VOLUME                     0x6C
+
+#define CM_DECREASE_VOLUME                     0x6D
+
+#define CM_LISTEN                                      0x6E
+
+#define CM_STOP_LISTEN                         0x6F
+
+#define CM_PREPARE_FOR_LISTEN          0x70
+
+#define CM_PLAY_SOUND_CARD                     0x71
+
+#define CM_STOP_SOUND_CARD                     0x72
+
+#define CM_MIXER_CTBUS                         0x73
+
+#define CM_PLAY_FROM_STREAM_EX                 0x74 
+
+#define CM_INTERNAL_PLAY_EX                    0x75 
+
+#define CM_ENABLE_PLAYER_AGC           0x76
+
+#define CM_DISABLE_PLAYER_AGC          0x77
+
+#define CM_START_STREAM_BUFFER         0x78
+
+#define CM_ADD_STREAM_BUFFER           0x79
+
+#define CM_STOP_STREAM_BUFFER          0x7A
+
+#define CM_SEND_BEEP                           0x7B
+
+#define CM_SEND_BEEP_CONF                      0x7C
+
+#define CM_ADD_TO_CONF                         0x7D
+
+#define CM_REMOVE_FROM_CONF                    0x7E
+
+#define CM_RECORD_TO_FILE_EX           0x7F
+
+#define CM_SET_VOLUME                          0xA0
+
+#define CM_START_CADENCE                       0xA1
+
+#define CM_STOP_CADENCE                                0xA2
+#if !defined KR2D_H
+#define KR2D_H
+
+#define CM_SET_LINE_CONDITION          0x80
+
+#define CM_SEND_LINE_CONDITION         0x81
+
+#define CM_SET_CALLER_CATEGORY         0x82
+      
+       
+#define CM_DIAL_MFC                                    0x83
+
+
+
+enum KSignGroupII_Brazil
+{
+       kg2BrOrdinary                   = 0x01,     
+       kg2BrPriority                   = 0x02,     
+       kg2BrMaintenance                = 0x03,     
+       kg2BrLocalPayPhone              = 0x04,     
+       kg2BrTrunkOperator              = 0x05,     
+       kg2BrDataTrans              = 0x06,     
+       kg2BrNonLocalPayPhone       = 0x07,     
+       kg2BrCollectCall                = 0x08,     
+       kg2BrOrdinaryInter              = 0x09,     
+       kg2BrTransfered                 = 0x0B,     
+};
+
+enum KSignGroupB_Brazil
+{
+       kgbBrLineFreeCharged            = 0x01,     
+       kgbBrBusy                                       = 0x02,     
+       kgbBrNumberChanged                      = 0x03,     
+       kgbBrCongestion                         = 0x04,     
+       kgbBrLineFreeNotCharged         = 0x05,     
+       kgbBrLineFreeChargedLPR         = 0x06,     
+       kgbBrInvalidNumber                      = 0x07,     
+       kgbBrLineOutOfOrder                     = 0x08,     
+       kgbBrNone                                       = 0xFF      
+};
+
+
+enum KSignGroupII_Argentina
+{
+       kg2ArOrdinary                   = 0x01,     
+       kg2ArPriority                   = 0x02,     
+       kg2ArMaintenance                = 0x03,     
+       kg2ArLocalPayPhone              = 0x04,     
+       kg2ArTrunkOperator              = 0x05,     
+       kg2ArDataTrans              = 0x06,     
+    kg2ArCPTP                   = 0x0B,     
+    kg2ArSpecialLine            = 0x0C,     
+    kg2ArMobileUser             = 0x0D,     
+    kg2ArPrivateRedLine         = 0x0E,     
+    kg2ArSpecialPayPhoneLine    = 0x0F,     
+};
+
+enum KSignGroupB_Argentina
+{
+       kgbArNumberChanged                      = 0x02,     
+       kgbArBusy                                       = 0x03,     
+       kgbArCongestion                         = 0x04,     
+       kgbArInvalidNumber                      = 0x05,     
+       kgbArLineFreeCharged            = 0x06,     
+       kgbArLineFreeNotCharged         = 0x07,     
+       kgbArLineOutOfOrder                     = 0x08,     
+       kgbArNone                                       = 0xFF      
+};
+
+
+enum KSignGroupII_Chile
+{
+    kg2ClOrdinary                      = 0x01,     
+       kg2ClPriority                   = 0x02,     
+       kg2ClMaintenance                = 0x03,     
+       kg2ClTrunkOperator              = 0x05,     
+       kg2ClDataTrans              = 0x06,     
+    kg2ClUnidentifiedSubscriber = 0x0B,     
+};
+
+enum KSignGroupB_Chile
+{
+       kgbClNumberChanged                      = 0x02,     
+       kgbClBusy                                       = 0x03,     
+       kgbClCongestion                         = 0x04,     
+       kgbClInvalidNumber                      = 0x05,     
+       kgbClLineFreeCharged            = 0x06,     
+       kgbClLineFreeNotCharged         = 0x07,     
+       kgbClLineOutOfOrder                     = 0x08,     
+       kgbClNone                                       = 0xFF      
+};
+
+
+enum KSignGroupII_Mexico
+{
+       kg2MxTrunkOperator              = 0x01,     
+       kg2MxOrdinary                   = 0x02,     
+       kg2MxMaintenance                = 0x06,     
+};
+
+enum KSignGroupB_Mexico
+{
+       kgbMxLineFreeCharged            = 0x01,     
+       kgbMxBusy                                       = 0x02,     
+       kgbMxLineFreeNotCharged         = 0x05,     
+       kgbMxNone                                   = 0xFF      
+};
+
+
+enum KSignGroupII_Uruguay
+{
+       kg2UyOrdinary                   = 0x01,     
+       kg2UyPriority                   = 0x02,     
+       kg2UyMaintenance                = 0x03,     
+       kg2UyLocalPayPhone              = 0x04,     
+       kg2UyTrunkOperator              = 0x05,     
+       kg2UyDataTrans              = 0x06,     
+    kg2UyInternSubscriber       = 0x07,     
+};
+
+enum KSignGroupB_Uruguay
+{
+       kgbUyNumberChanged                      = 0x02,     
+       kgbUyBusy                                       = 0x03,     
+       kgbUyCongestion                         = 0x04,     
+       kgbUyInvalidNumber                      = 0x05,     
+       kgbUyLineFreeCharged            = 0x06,     
+       kgbUyLineFreeNotCharged         = 0x07,     
+       kgbUyLineOutOfOrder                     = 0x08,     
+       kgbUyNone                                       = 0xFF      
+};
+
+
+enum KSignGroupII_Venezuela
+{
+       kg2VeOrdinary                   = 0x01,     
+       kg2VePriority                   = 0x02,     
+       kg2VeMaintenance                = 0x03,     
+       kg2VeLocalPayPhone              = 0x04,     
+       kg2VeTrunkOperator              = 0x05,     
+       kg2VeDataTrans              = 0x06,     
+    kg2VeNoTransferFacility     = 0x07,     
+};
+
+enum KSignGroupB_Venezuela
+{
+       kgbVeLineFreeChargedLPR         = 0x01,     
+       kgbVeNumberChanged                      = 0x02,     
+       kgbVeBusy                                       = 0x03,     
+       kgbVeCongestion                         = 0x04,     
+       kgbVeInformationTone            = 0x05,     
+       kgbVeLineFreeCharged            = 0x06,     
+       kgbVeLineFreeNotCharged         = 0x07,     
+    kgbVeLineBlocked            = 0x08,     
+    kgbVeIntercepted            = 0x09,     
+    kgbVeDataTrans              = 0x0A,     
+       kgbVeNone                                       = 0xFF      
+};
+
+
+
+
+
+enum KSignGroupB
+{
+       kgbLineFreeCharged                      = 0x01,
+       kgbLineFreeNotCharged           = 0x05,
+       kgbLineFreeChargedLPR           = 0x06,
+       kgbBusy                                         = 0x02,
+       kgbNumberChanged                        = 0x03,
+       kgbCongestion                           = 0x04,
+       kgbInvalidNumber                        = 0x07,
+       kgbLineOutOfOrder                       = 0x08,
+       kgbNone                                         = 0xFF
+};
+#define STT_GB_LINEFREE_CHARGED                                0x01
+#define STT_GB_LINEFREE_NOTCHARGED                     0x05
+#define STT_GB_LINEFREE_CHARGED_LPR                    0x06
+#define        STT_GB_BUSY                                                     0x02
+#define STT_GB_NUMBER_CHANGED                          0x03
+#define STT_GB_CONGESTION                                      0x04
+#define STT_GB_UNALLOCATED_NUMBER                      0x07
+#define STT_GB_LINE_OUT_OF_ORDER                       0x08
+#define STT_GB_NONE                                                    0xFF
+
+enum KSignGroupII
+{
+       kg2Ordinary                     = 0x01,
+       kg2Priority                     = 0x02,
+       kg2Maintenance          = 0x03,
+       kg2LocalPayPhone        = 0x04,
+       kg2TrunkOperator        = 0x05,
+       kg2DataTrans            = 0x06,
+       kg2NonLocalPayPhone = 0x07,
+       kg2CollectCall          = 0x08,
+       kg2OrdinaryInter        = 0x09,
+       kg2Transfered           = 0x0B,
+};
+#define STT_GII_ORDINARY                                       0x01
+#define STT_GII_PRIORITY                                       0x02
+#define STT_GII_MAINTENANCE                                    0x03
+#define STT_GII_LOCAL_PAY_PHONE                                0x04
+#define STT_GII_TRUNK_OPERATOR                         0x05
+#define STT_GII_DATA_TRANS                                     0x06
+#define STT_GII_NON_LOCAL_PAY_PHONE                    0x07            
+#define STT_GII_COLLECT_CALL                           0x08
+#define STT_GII_ORDINARY_INTERNATIONAL         0x09
+#define STT_GII_TRANSFERED                                     0x0B
+#endif
+#ifndef _KISDN_H_
+#define _KISDN_H_
+#define KMAX_USER_USER_LEN              32
+#define KMAX_SUBADRESS_INFORMATION_LEN  20 
+
+enum KQ931Cause
+{
+    kq931cNone                                         = 0,
+    kq931cUnallocatedNumber                            = 1,
+    kq931cNoRouteToTransitNet                          = 2,
+    kq931cNoRouteToDest                                = 3,
+       kq931cSendSpecialInfoTone                               = 4,
+       kq931cMisdialedTrunkPrefix                              = 5,
+    kq931cChannelUnacceptable                          = 6,
+    kq931cCallAwarded                                  = 7,
+       kq931cPreemption                                                = 8,
+       kq931cPreemptionCircuitReuse                    = 9,
+       kq931cQoR_PortedNumber                                  = 14,
+    kq931cNormalCallClear                              = 16,
+    kq931cUserBusy                                     = 17,
+    kq931cNoUserResponding                             = 18,
+    kq931cNoAnswerFromUser                             = 19,
+       kq931cSubscriberAbsent                                  = 20,
+    kq931cCallRejected                                 = 21,
+    kq931cNumberChanged                                = 22,
+       kq931cRedirectionToNewDest                              = 23,
+       kq931cCallRejectedFeatureDest                   = 24,
+       kq931cExchangeRoutingError                              = 25,
+    kq931cNonSelectedUserClear                         = 26,
+    kq931cDestinationOutOfOrder                        = 27,
+    kq931cInvalidNumberFormat                          = 28,
+    kq931cFacilityRejected                             = 29,
+    kq931cRespStatusEnquiry                            = 30,
+    kq931cNormalUnspecified                            = 31,
+    kq931cNoCircuitChannelAvail                        = 34,
+    kq931cNetworkOutOfOrder                            = 38,
+       kq931cPermanentFrameConnOutOfService    = 39,
+       kq931cPermanentFrameConnOperational             = 40,
+    kq931cTemporaryFailure                     = 41,
+    kq931cSwitchCongestion                     = 42,
+    kq931cAccessInfoDiscarded                  = 43,
+    kq931cRequestedChannelUnav                 = 44,
+       kq931cPrecedenceCallBlocked                             = 46,
+    kq931cResourceUnavailable                  = 47,
+    kq931cQosUnavailable                       = 49,
+    kq931cReqFacilityNotSubsc                  = 50,
+       kq931cOutCallsBarredWithinCUG                   = 53,
+       kq931cInCallsBarredWithinCUG                    = 55,
+    kq931cBearerCapabNotAuthor                 = 57,
+    kq931cBearerCapabNotAvail                  = 58,
+       kq931cInconsistency                                             = 62,
+    kq931cServiceNotAvailable                  = 63,
+    kq931cBcNotImplemented                     = 65,
+    kq931cChannelTypeNotImplem                 = 66,
+    kq931cReqFacilityNotImplem                 = 69,
+    kq931cOnlyRestrictedBcAvail                = 70,
+    kq931cServiceNotImplemented                = 79,
+    kq931cInvalidCrv                           = 81,
+    kq931cChannelDoesNotExist                  = 82,
+    kq931cCallIdDoesNotExist                   = 83,
+    kq931cCallIdInUse                          = 84,
+    kq931cNoCallSuspended                      = 85,
+    kq931cCallIdCleared                        = 86,
+       kq931cUserNotMemberofCUG                                = 87,
+    kq931cIncompatibleDestination              = 88,
+    kq931cInvalidTransitNetSel                 = 91,
+    kq931cInvalidMessage                       = 95,
+    kq931cMissingMandatoryIe                   = 96,
+    kq931cMsgTypeNotImplemented                = 97,
+    kq931cMsgIncompatWithState                 = 98,
+    kq931cIeNotImplemented                     = 99,
+    kq931cInvalidIe                            = 100,
+    kq931cMsgIncompatWithState2                = 101,
+    kq931cRecoveryOnTimerExpiry                = 102,
+    kq931cProtocolError                        = 103,
+       kq931cMessageWithUnrecognizedParam              = 110,
+       kq931cProtocolErrorUnspecified                  = 111,
+    kq931cInterworking                         = 127,
+    kq931cCallConnected                        = 128,
+    kq931cCallTimedOut                         = 129,
+    kq931cCallNotFound                         = 130,
+    kq931cCantReleaseCall                      = 131,
+    kq931cNetworkFailure                       = 132,
+    kq931cNetworkRestart                       = 133,
+    kq931cLastValidCause                       = kq931cNetworkRestart,
+};
+
+enum KQ931ProgressIndication
+{
+    kq931pTonesMaybeAvailable       = 1,
+    kq931pDestinationIsNonIsdn      = 2,
+    kq931pOriginationIsNonIsdn      = 3,
+    kq931pCallReturnedToIsdn        = 4,
+    kq931pTonesAvailable            = 8,
+};
+
+enum KQ931Hlc
+{
+    kq931hTelefony                  = 0x81,
+    k1931hFaxGroup23                = 0x84,
+    k1931hFaxGroup4                 = 0xa1,
+    kq931hTeletexF184               = 0xa4,
+    kq931hTeletexF220               = 0xa8,
+    kq931hTeletexf200               = 0xb1,
+    kq931hVideotex                  = 0xb2,
+    kq931hTelexF60                  = 0xb5,
+    kq931hMhs                       = 0xb8,
+    kq931hOsiApp                    = 0xc1,
+    kq931hMaintenance               = 0xde,
+    kq931hManagement                = 0xdf,
+};
+
+enum KQ931BearerCapability
+{
+    kq931bSpeech                    = 0x00,
+    kq931bUnrestrictedDigital       = 0x08,
+    kq931bAudio31kHz                = 0x10,
+    kq931bAudio7kHz                 = 0x11,
+    kq931bVideo                     = 0x18,
+};
+
+enum KQ931TypeOfNumber
+{
+    kq931tUnknownNumber             = 0x00,
+    kq931tInternationalNumber       = 0x10,
+    kq931tNationalNumber            = 0x20,
+    kq931tNetworkSpecificNumber     = 0x30,
+    kq931tSubscriberNumber          = 0x40,
+    kq931tAbbreviatedNumber         = 0x60,
+    kq931tReservedNumber            = 0x70,
+    kq931tDefaultNumber             = kq931tUnknownNumber,
+};
+
+enum KQ931NumberingPlan
+{
+    kq931pUnknownPlan               = 0x00,
+    kq931pIsdnPlan                  = 0x01,
+    kq931pDataPlan                  = 0x03,
+    kq931pTelexPlan                 = 0x04,
+    kq931pNationalPlan              = 0x08,
+    kq931pPrivatePlan               = 0x09,
+    kq931pReservedPlan              = 0x0F,
+    kq931pDefaultPlan               = kq931pUnknownPlan,
+};
+
+enum KQ931UserInfoProtocolDescriptor
+{
+    kq931uuUserSpecific             = 0x00,
+    kq931uuOSI_HighLayer            = 0x01,
+    kq931uuX244                     = 0x02,
+    kq931uuIA5_Chars                = 0x04,
+    kq931uuX208_X209                = 0x05,
+    kq931uuV120                     = 0x07,
+    kq931uuQ931_CallControl         = 0x08,
+    kq931uuNational                 = 0x40 
+};
+enum KQ931PresentationIndicator
+{
+       kq931piPresentationAllowed                                      = 0x00,
+       kq931piPresentationRestricted                           = 0x01,
+       kq931piNumberNotAvailableDueToInterworking      = 0x02,
+};
+enum KQ931ScreeningIndicator
+{
+       kq931siUserProvidedNotScreened                          = 0x00,
+       kq931siUserProvidedVerifiedAndPassed            = 0x01,
+       kq931siUserProvidedVerifiedAndFailed            = 0x02,
+       kq931siNetworkProvided                                          = 0x03,
+};
+enum KQ931TypeOfSubaddress
+{
+    kq931tsNSAP                                 = 0x00,
+    kq931tsUserSpecified                        = 0x01,
+};
+#endif 
+#ifndef KGSM_H
+#define KGSM_H
+
+enum KGsmCallCause
+{
+    kgccNone                      = 0,
+    kgccUnallocatedNumber         = 1,
+    kgccNoRouteToDest             = 3,
+    kgccChannelUnacceptable       = 6,
+    kgccOperatorDeterminedBarring = 8,
+    kgccNormalCallClear           = 16,
+    kgccUserBusy                  = 17,
+    kgccNoUserResponding          = 18,
+    kgccNoAnswerFromUser          = 19,
+    kgccCallRejected              = 21,
+    kgccNumberChanged             = 22,
+    kgccNonSelectedUserClear      = 26,
+    kgccDestinationOutOfOrder     = 27,
+    kgccInvalidNumberFormat       = 28,
+    kgccFacilityRejected          = 29,
+    kgccRespStatusEnquiry         = 30,
+    kgccNormalUnspecified         = 31,
+    kgccNoCircuitChannelAvail     = 34,
+    kgccNetworkOutOfOrder         = 38,
+    kgccTemporaryFailure          = 41,
+    kgccSwitchCongestion          = 42,
+    kgccAccessInfoDiscarded       = 43,
+    kgccRequestedChannelUnav      = 44,
+    kgccResourceUnavailable       = 47,
+    kgccQosUnavailable            = 49,
+    kgccReqFacilityNotSubsc       = 50,
+    kgccCallBarredWitchCUG        = 55,
+    kgccBearerCapabNotAuthor      = 57,
+    kgccBearerCapabNotAvail       = 58,
+    kgccServiceNotAvailable       = 63,
+    kgccBcNotImplemented          = 65,
+    kgccReqFacilityNotImplem      = 69,
+    kgccOnlyRestrictedBcAvail     = 70,
+    kgccServiceNotImplemented     = 79,
+    kgccInvalidCrv                = 81,
+    kgccUserNotMemberOfCUG        = 82,
+    kgccIncompatibleDestination   = 88,
+    kgccInvalidTransitNetSel      = 91,
+    kgccInvalidMessage            = 95,
+    kgccMissingMandatoryIe        = 96,
+    kgccMsgTypeNotImplemented     = 97,
+    kgccMsgIncompatWithState      = 98,
+    kgccIeNotImplemented          = 99,
+    kgccInvalidIe                 = 100,
+    kgccMsgIncompatWithState2     = 101,
+    kgccRecoveryOnTimerExpiry     = 102,
+    kgccProtocolError             = 111,
+    kgccInterworking              = 127,
+};
+
+enum KGsmMobileCause
+{
+    kgmcPhoneFailure                = 0,
+    kgmcNoConnectionToPhone         = 1,
+    kgmcPhoneAdaptorLinkReserved    = 2,
+    kgmcOperationNotAllowed         = 3,
+    kgmcOperationNotSupported       = 4,
+    kgmcPH_SIMPINRequired           = 5,
+    kgmcPH_FSIMPINRequired          = 6,
+    kgmcPH_FSIMPUKRequired          = 7,
+    kgmcSIMNotInserted              = 10,
+    kgmcSIMPINRequired              = 11,
+    kgmcSIMPUKRequired              = 12,
+    kgmcSIMFailure                  = 13,
+    kgmcSIMBusy                     = 14,
+    kgmcSIMWrong                    = 15,
+    kgmcIncorrectPassword           = 16,
+    kgmcSIMPIN2Required             = 17,
+    kgmcSIMPUK2Required             = 18,
+    kgmcMemoryFull                  = 20,
+    kgmcInvalidIndex                = 21,
+    kgmcNotFound                    = 22,
+    kgmcMemoryFailure               = 23,
+    kgmcTextStringTooLong           = 24,
+    kgmcInvalidCharInTextString     = 25,
+    kgmcDialStringTooLong           = 26,
+    kgmcInvalidCharInDialString     = 27,
+    kgmcNoNetworkService            = 30,  
+    kgmcNetworkTimeout              = 31,  
+    kgmcNetworkNotAllowed           = 32,
+    kgmcCommandAborted              = 33,
+    kgmcNumParamInsteadTextParam    = 34,
+    kgmcTextParamInsteadNumParam    = 35,
+    kgmcNumericParamOutOfBounds     = 36,
+    kgmcTextStringTooShort          = 37,
+    kgmcNetworkPINRequired          = 40,
+    kgmcNetworkPUKRequired          = 41,
+    kgmcNetworkSubsetPINRequired    = 42,
+    kgmcNetworkSubnetPUKRequired    = 43,
+    kgmcServiceProviderPINRequired  = 44,
+    kgmcServiceProviderPUKRequired  = 45,
+    kgmcCorporatePINRequired        = 46,
+    kgmcCorporatePUKRequired        = 47,
+    kgmcSIMServiceOptNotSupported   = 60,
+    kgmcUnknown                     = 100,
+    kgmcIllegalMS_N3                = 103,
+    kgmcIllegalME_N6                = 106,
+    kgmcGPRSServicesNotAllowed_N7   = 107,
+    kgmcPLMNNotAllowed_No11         = 111,
+    kgmcLocationAreaNotAllowed_N12  = 112,
+    kgmcRoamingNotAllowed_N13       = 113,
+    kgmcServiceOptNotSupported_N32  = 132,
+    kgmcReqServOptNotSubscribed_N33 = 133,
+    kgmcServOptTempOutOfOrder_N34   = 134,
+    kgmcLongContextActivation       = 147,
+    kgmcUnspecifiedGPRSError        = 148,
+    kgmcPDPAuthenticationFailure    = 149,
+    kgmcInvalidMobileClass          = 150,
+    kgmcGPRSDisconnectionTmrActive  = 151,
+    kgmcTooManyActiveCalls          = 256,
+    kgmcCallRejected                = 257,
+    kgmcUnansweredCallPending       = 258,
+    kgmcUnknownCallingError         = 259,
+    kgmcNoPhoneNumRecognized        = 260,
+    kgmcCallStateNotIdle            = 261,
+    kgmcCallInProgress              = 262,
+    kgmcDialStateError              = 263,
+    kgmcUnlockCodeRequired          = 264,
+    kgmcNetworkBusy                 = 265,
+    kgmcInvalidPhoneNumber          = 266,
+    kgmcNumberEntryAlreadyStarted   = 267,
+    kgmcCancelledByUser             = 268,
+    kgmcNumEntryCouldNotBeStarted   = 269,
+    kgmcDataLost                    = 280,
+    kgmcInvalidBessageBodyLength    = 281,
+    kgmcInactiveSocket              = 282,
+    kgmcSocketAlreadyOpen           = 283,
+    
+    kgmcSuccess                     = 0x7fff
+};
+
+enum KGsmSmsCause
+{
+    kgscNone                        = 0,
+    kgscUnassigned                  = 1,
+    kgscOperatorDeterminedBarring   = 8,
+    kgscCallBarred                  = 10,
+    kgscSMSTransferRejected         = 21,
+    kgscDestinationOutOfService     = 27,
+    kgscUnidentifiedSubscriber      = 28,
+    kgscFacilityRejected            = 29,
+    kgscUnknownSubscriber           = 30,
+    kgscNetworkOutOfOrder           = 38,
+    kgscTemporaryFailure            = 41,
+    kgscCongestion                  = 42,
+    kgscResourcesUnavailable        = 47,
+    kgscFacilityNotSubscribed       = 50,
+    kgscFacilityNotImplemented      = 69,
+    kgscInvalidSMSTransferRefValue  = 81,
+    kgscInvalidMessage              = 95,
+    kgscInvalidMandatoryInformation = 96,
+    kgscMessageTypeNonExistent      = 97,
+    kgscMsgNotCompatWithSMProtState = 98,
+    kgscInformationElementNonExiste = 99,
+    kgscProtocolError               = 111,
+    kgscInterworking                = 127,
+    kgscTelematicInterworkingNotSup = 128,
+    kgscSMSTypeZeroNotSupported     = 129,
+    kgscCannotReplaceSMS            = 130,
+    kgscUnspecifiedTPPIDError       = 143,
+    kgscAlphabetNotSupported        = 144,
+    kgscMessageClassNotSupported    = 145,
+    kgscUnspecifiedTPDCSError       = 159,
+    kgscCommandCannotBeActioned     = 160,
+    kgscCommandUnsupported          = 161,
+    kgscUnspecifiedTPCommandError   = 175,
+    kgscTPDUNotSupported            = 176,
+    kgscSCBusy                      = 192,
+    kgscNoSCSubscription            = 193,
+    kgscSCSystemFailure             = 194,
+    kgscInvalidSMEAddress           = 195,
+    kgscDestinationSMEBarred        = 196,
+    kgscSMRejectedDuplicateSM       = 197,
+    kgscTPVPFNotSupported           = 198,
+    kgscTPVPNotSupported            = 199,
+    kgscSIMSMSStorageFull           = 208,
+    kgscNoSMSStorageCapabilityInSIM = 209,
+    kgscErrorInMS                   = 210,
+    kgscMemoryCapacityExceeded      = 211,
+    kgscSIMDataDownloadError        = 213,
+    kgscUnspecifiedError            = 255,
+    kgscPhoneFailure                = 300,
+    kgscSmsServiceReserved          = 301,
+    kgscOperationNotAllowed         = 302,
+    kgscOperationNotSupported       = 303,
+    kgscInvalidPDUModeParameter     = 304,
+    kgscInvalidTextModeParameter    = 305,
+    kgscSIMNotInserted              = 310,
+    kgscSIMPINNecessary             = 311,
+    kgscPH_SIMPINNecessary          = 312,
+    kgscSIMFailure                  = 313,
+    kgscSIMBusy                     = 314,
+    kgscSIMWrong                    = 315,
+    kgscMemoryFailure               = 320,
+    kgscInvalidMemoryIndex          = 321,
+    kgscMemoryFull                  = 322,
+    kgscSMSCAddressUnknown          = 330,
+    kgscNoNetworkService            = 331,
+    kgscNetworkTimeout              = 332,
+    kgscUnknownError                = 500,
+    kgscNetworkBusy                 = 512,
+    kgscInvalidDestinationAddress   = 513,
+    kgscInvalidMessageBodyLength    = 514,
+    kgscPhoneIsNotInService         = 515,
+    kgscInvalidPreferredMemStorage  = 516,
+    kgscUserTerminated              = 517
+};
+
+enum KGsmRegistryStatus
+{
+       kgrsNotRegistered = 0x00,
+       kgrsRegistered    = 0x01,
+       kgrsSearching     = 0x02,
+       kgrsDenied        = 0x03,
+       kgrsUnknown       = 0x04,
+       kgrsRoaming       = 0x05,
+       kgrsInitializing  = 0xff,
+};
+enum KGsmCallStatus
+{
+       kgcstActive   = 0x0,
+       kgcstHeld     = 0x1,
+       kgcstDialing  = 0x2,
+       kgcstAlerting = 0x3,
+       kgcstIncoming = 0x4,
+       kgcstWaiting  = 0x5,
+       kgcstReleased = 0x6,
+};
+enum KGsmCallMode
+{
+       kgcmVoice   = 0x0,
+       kgcmData    = 0x1,
+       kgcmFax     = 0x2,
+       kgcmUnknown = 0x3
+};
+enum KGsmCallFlags
+{
+       kgcflMultiparty           = 0x01,
+       kgcflInternationalNumber  = 0x02,
+       kgcflMobileTerminatedCall = 0x04,
+};
+enum KGsmChannelFeatures
+{
+       kgcfMultiparty  = 0x01,
+       kgcfCallForward = 0x02, 
+};
+#endif
+#ifndef K3L_STATS_H
+#define K3L_STATS_H
+
+enum KGeneralCallStatIndex
+{
+    kcsiInbound,            
+    kcsiOutbound,           
+    kcsiOutCompleted,       
+    kcsiOutFailed,          
+    kcsiRemoteDisc,         
+    kcsiLocalDisc,          
+    kcsiLastGeneralCallStat
+};
+
+enum KFailedCallStatIndex
+{
+    kcsiFailedBusy = kcsiLastGeneralCallStat,
+    kcsiFailedNoAnswer,
+    kcsiFailedRejected,
+    kcsiFailedAddrChanged,
+    kcsiFailedInvalidAddr,
+    kcsiFailedOutOfService,
+    kcsiFailedCongestion,
+    kcsiFailedNetworkFailure,
+    kcsiFailedOther,
+    kcsiLastFailedCallStat
+};
+const uint32 kcsiMaxCallStats = kcsiLastFailedCallStat;
+typedef uint32 KStatIndex;
+
+#endif
+#ifndef k3lVersion_h
+#define k3lVersion_h
+#define k3lApiMajorVersion     2
+#define k3lApiMinorVersion     1
+#define k3lApiBuildVersion     0
+#endif
+#if !defined K3L_H
+#define K3L_H
+
+enum KDeviceType
+{
+       kdtE1           = 0,
+       kdtFXO          = 1,
+       kdtConf         = 2,
+       kdtPR           = 3,
+       kdtE1GW         = 4,
+       kdtFXOVoIP      = 5,
+       kdtE1IP         = 6,
+       kdtE1Spx        = 7,
+    kdtGWIP         = 8,
+    kdtFXS          = 9,
+    kdtFXSSpx       = 10,
+    kdtGSM          = 11,
+    kdtGSMSpx       = 12,
+       kdtReserved1    = 13,
+    kdtGSMUSB       = 14,
+    kdtGSMUSBSpx    = 15,
+    kdtE1FXSSpx        = 16,
+       kdtDevTypeCount
+};
+enum KSignaling
+{
+       ksigInactive            = 0,
+       ksigR2Digital           = 1,
+       ksigContinuousEM        = 2,
+       ksigPulsedEM            = 3,
+       ksigUserR2Digital       = 4,
+       ksigAnalog                      = 5,
+       ksigOpenCAS                     = 6,
+       ksigOpenR2                      = 7,
+       ksigSIP                         = 8,
+    ksigOpenCCS         = 9,
+    ksigPRI_EndPoint    = 10,
+    ksigAnalogTerminal  = 11,
+    ksigPRI_Network     = 12,
+    ksigPRI_Passive     = 13,
+       ksigLineSide            = 14,
+       ksigCAS_EL7                     = 15,
+    ksigGSM             = 16,
+       ksigE1LC                        = 17,
+       ksigISUP                        = 18,
+       ksigFax                         = 19,
+};
+enum KE1DeviceModel
+{
+       kdmE1600        = 0,
+       kdmE1600E       = 1,
+       kdmE1600EX  = 2
+};
+enum KE1GWDeviceModel 
+{
+       kdmE1GW640   = 1,
+    kdmE1GW640EX = 2
+};
+enum KE1IPDeviceModel 
+{
+       kdmE1IP   = 1,
+    kdmE1IPEX = 2
+};
+enum KGWIPDeviceModel 
+{
+       kdmGWIP   = 1,
+       kdmGWIPEX = 2
+};
+enum KFXODeviceModel
+{
+       kdmFXO80    = 0,
+       kdmFXOHI    = 1,
+       kdmFXO160HI = 2,
+    kdmFXO240HI = 3
+};
+enum KFXOVoIPDeviceModel 
+{
+       kdmFXGW180 = kdmFXO80
+};
+enum KConfDeviceModel
+{
+       kdmConf240   = 0,
+       kdmConf120   = 1,
+       kdmConf240EX = 2,
+       kdmConf120EX = 3
+};
+enum KPRDeviceModel
+{
+       kdmPR300v1         = 0,
+    kdmPR300           = 1,
+       kdmPR300SpxBased   = 2,
+    kdmPR300EX         = 3
+};
+enum KFXSDeviceModel
+{
+    kdmFXS300   = 1,
+    kdmFXS300EX = 2
+};
+enum KFXSSpxDeviceModel
+{
+    kdmFXSSpx300      = 0,
+    kdmFXSSpx2E1Based = 1,
+    kdmFXSSpx300EX    = 2
+};
+enum KE1SpxDeviceModel
+{
+       kdmE1Spx    = 0,
+       kdm2E1Based = 1,
+    kdmE1SpxEX  = 2
+};
+enum KGSMDeviceModel
+{
+    kdmGSM      = 0,
+    kdmGSMEX    = 1
+};
+enum KGSMSpxDeviceModel
+{
+    kdmGSMSpx   = 0,
+    kdmGSMSpxEX = 1
+};
+enum KGSMUSBDeviceModel
+{
+    kdmGSMUSB      = 0
+};
+enum KGSMUSBSpxDeviceModel
+{
+    kdmGSMUSBSpx   = 0
+};
+enum KE1FXSDeviceModel
+{
+    kdmE1FXSSpx     = 0,
+    kdmE1FXSSpxEX   = 1
+};
+enum KSystemObject
+{
+       ksoLink       = 0x00,   
+       ksoLinkMon    = 0x20,   
+       ksoFirmware   = 0x80,   
+       ksoDevice     = 0x100,  
+       ksoAPI        = 0x150,  
+       ksoH100       = 0x200,  
+       ksoChannel        = 0x1000,     
+       ksoGsmChannel = 0x2000, 
+};
+enum KFirmwareId
+{
+       kfiE1600A,                              
+       kfiE1600B,                              
+       kfiFXO80,                               
+    kfiGSM40,               
+    kfiGSMUSB
+};
+enum KE1Status
+{
+       kesOk                                   = 0x00,         
+       kesSignalLost                   = 0x01,         
+       kesNetworkAlarm                 = 0x02,         
+       kesFrameSyncLost                = 0x04,         
+       kesMultiframeSyncLost   = 0x08,         
+       kesRemoteAlarm                  = 0x10,         
+       kesHighErrorRate                = 0x20,         
+       kesUnknownAlarm                 = 0x40,         
+       kesE1Error                              = 0x80,         
+    kesNotInitialized       = 0xFF      
+};
+enum KE1ChannelStatus
+{
+       kecsFree                        = 0x00,                 
+       kecsBusy                        = 0x01,                 
+       kecsOutgoing            = 0x02,                 
+       kecsIncoming            = 0x04,                 
+       kecsLocked                      = 0x06,                 
+       kecsOutgoingLock        = 0x10,                 
+       kecsLocalFail           = 0x20,                 
+       kecsIncomingLock        = 0x40,                 
+       kecsRemoteLock          = 0x80                  
+};
+enum KVoIPChannelStatus
+{
+       kipcsFree                       = kecsFree,             
+       kipcsOutgoingLock       = kecsOutgoingLock,
+       kipcsIncomingLock       = kecsIncomingLock
+};
+enum KFXOChannelStatus
+{
+       kfcsDisabled    = 0x00,         
+       kfcsEnabled             = 0x01          
+};
+enum KFXSChannelStatus
+{
+    kfxsOnHook,
+    kfxsOffHook,
+    kfxsRinging,
+    kfxsFail
+};
+enum KGsmChannelStatus
+{
+    kgsmIdle,
+    kgsmCallInProgress,
+    kgsmSMSInProgress,
+    kgsmModemError,
+    kgsmSIMCardError,
+    kgsmNetworkError,
+    kgsmNotReady
+};
+enum KCallStatus
+{
+       kcsFree         = 0x00,                         
+       kcsIncoming = 0x01,                             
+       kcsOutgoing = 0x02,                             
+       kcsFail         = 0x04                          
+};
+enum KCallStartInfo
+{
+    kcsiHumanAnswer,
+    kcsiAnsweringMachine,
+    kcsiCellPhoneMessageBox,
+    kcsiUnknown,
+    kcsiCarrierMessage
+};
+enum KChannelFeatures
+{
+       kcfDtmfSuppression      = 0x0001,
+       kcfCallProgress         = 0x0002,
+       kcfPulseDetection       = 0x0004,
+       kcfAudioNotification= 0x0008,
+       kcfEchoCanceller        = 0x0010,
+       kcfAutoGainControl      = 0x0020,
+       kcfHighImpEvents        = 0x0080,
+    kcfCallAnswerInfo   = 0x0100,
+    kcfOutputVolume     = 0x0200,
+    kcfPlayerAGC        = 0x0400
+};
+enum KMixerSource
+{
+       kmsChannel,
+       kmsPlay,
+       kmsGenerator,
+       kmsCTbus,
+    kmsNoDelayChannel
+};
+struct KMixerCommand
+{
+    int32 Track;
+    int32 Source;        
+    int32 SourceIndex;
+};
+struct KPlayFromStreamCommand
+{
+       void *Buffer;
+       uint32 BufferSize;
+       int32 CodecIndex;
+};
+struct KBufferParam
+{
+       void *Buffer;
+       uint32 BufferSize;
+};
+enum KMixerTone
+{
+       kmtSilence      = 0x00, 
+       kmtDial         = 0x01, 
+       kmtBusy         = 0x02, 
+       kmtFax          = 0x03, 
+       kmtVoice        = 0x04, 
+       kmtEndOf425 = 0x05,     
+    kmtCollect  = 0x06, 
+    kmtEndOfDtmf= 0x07, 
+};
+struct K3L_CHANNEL_STATUS
+{
+       KCallStatus CallStatus;
+       KMixerTone AudioStatus;
+       int32 AddInfo;                  
+       int32 EnabledFeatures;  
+};
+struct K3L_GSM_CALL_STATUS
+{
+       KGsmCallStatus Status;
+       KGsmCallMode Mode;
+       char Number[ KMAX_DIAL_NUMBER ];
+       int32 Flags; 
+};
+struct K3L_GSM_CHANNEL_STATUS
+{
+       uint8 SignalStrength; 
+       uint8 ErrorRate;      
+       KGsmRegistryStatus RegistryStatus;
+       char OperName[ KMAX_GSM_OPER_NAME ];
+       K3L_GSM_CALL_STATUS CallStatus[ KMAX_GSM_CALLS ];
+       int32 UnreadSmsCount;  
+       int32 EnabledFeatures; 
+    char IMEI[ KMAX_GSM_IMEI_SIZE ];
+    unsigned char SIM; 
+    unsigned char Reserved[15]; 
+};
+struct K3L_LINK_STATUS
+{
+       int16 E1; 
+       byte Channels[ KMAX_E1_CHANNELS ];      
+};
+enum KPllErrors
+{
+       kpeClockAError    = 0x01,
+       kpeClockBError    = 0x02,
+       kpeSCbusError     = 0x04,
+       kpeMVIPError      = 0x08,
+       kpeMasterPllError = 0x10,
+       kpeModeError      = 0x20,
+       kpeLocalRefError  = 0x40,
+       kpeInternalError  = 0x80
+};
+struct K3L_H100_STATUS
+{
+       int32 Mode;
+       int32 MasterClock;
+       int32 Enable;
+       int32 Reference;
+       int32 SCbus;
+       int32 HMVIP;
+       int32 MVIP90;
+       int32 CT_NETREF;
+       int32 PllLocalRef;
+       int32 PllErrors;                
+};
+enum KEchoLocation
+{
+       kelNetwork      = 0x0,
+       kelCtBus        = 0x1
+};
+enum KCodecIndex
+{
+       kci8kHzALAW     = 0x00,
+       kci8kHzPCM      = 0x01,  
+       kci11kHzPCM     = 0x02,  
+       kci8kHzGSM      = 0x03, 
+       kci8kHzADPCM= 0x04, 
+       kci8kHzULAW     = 0x05,
+       kciLastCodecEntryMark
+};
+enum KEchoCancellerConfig
+{
+    keccNotPresent,
+    keccOneSingleBank,
+    keccOneDoubleBank,
+    keccTwoSingleBank,
+    keccTwoDoubleBank,
+    keccFail
+};
+struct K3L_DEVICE_CONFIG
+{
+       int32 LinkCount;
+       int32 ChannelCount;
+       int32 EnabledChannelCount;
+       int32 MixerCount;
+       int32 MixerCapacity;
+       int32 WorkStatus;
+       int32 DeviceModel;              
+       int32 H100_Mode;                
+       int32 PciBus;
+       int32 PciSlot;
+       int32 PlayerCount;
+       int32 VoIPChannelCount;
+    int32 CTbusCount;
+    KEchoCancellerConfig EchoConfig;
+    KEchoLocation EchoLocation;
+       sbyte SerialNumber[ KMAX_SERIAL_NUMBER ];
+};
+
+typedef K3L_DEVICE_CONFIG K3L_E1_DEVICE_CONFIG;
+typedef K3L_DEVICE_CONFIG K3L_FX_DEVICE_CONFIG;
+struct K3L_API_CONFIG
+{
+       int32 MajorVersion;
+       int32 MinorVersion;
+       int32 BuildVersion;
+    int32 SvnRevision;
+       int32 RawCmdLogging;
+       int32 VpdVersionNeeded;
+       sbyte StrVersion[ KMAX_STR_VERSION ];
+};
+struct K3L_LINK_CONFIG
+{
+       KSignaling Signaling;
+       int32 IncomingDigitsRequest;
+       int32 IdentificationRequestPos;
+       int32 ChannelCount;
+       int32 ReceivingClock;
+       sbyte NumberA[ KMAX_DIAL_NUMBER + 1 + 3 ]; 
+};
+struct K3L_CHANNEL_CONFIG
+{
+       KSignaling Signaling;
+    int32 AutoEnableFeatures;   
+    int32 CapableFeatures;      
+};
+struct K3L_E1600A_FW_CONFIG
+{
+       int32 MfcExchangersCount;
+       int32 MonitorBufferSize;
+       sbyte FwVersion[ KMAX_STR_VERSION ];
+       sbyte DspVersion[ KMAX_DSP_NAME ];
+};
+struct K3L_E1600B_FW_CONFIG
+{
+       int32 AudioBufferSize;
+       int32 FilterCount;
+       int32 MixerCount;
+       int32 MixerCapacity;
+       sbyte FwVersion[ KMAX_STR_VERSION ];
+       sbyte DspVersion[ KMAX_DSP_NAME ];
+};
+typedef K3L_E1600B_FW_CONFIG K3L_GSM40_FW_CONFIG;
+typedef K3L_E1600B_FW_CONFIG K3L_FXO80_FW_CONFIG;
+typedef K3L_E1600B_FW_CONFIG K3L_GSMUSB_FW_CONFIG;
+struct K3L_COMMAND
+{
+       int32 Object;                   
+       int32 Cmd;                              
+       byte *Params;                   
+};
+
+enum KEventObjectId
+{
+       koiDevice               = 0x00,
+       koiChannel              = 0x01,
+       koiPlayer               = 0x02,
+       koiLink                 = 0x03,
+    koiSystem       = 0x04
+};
+
+struct K3L_EVENT
+{
+       int32 Code;                             
+       int32 AddInfo;                  
+       int32 DeviceId;                 
+       int32 ObjectInfo;               
+       void *Params;                   
+       int32 ParamSize;                
+       int32 ObjectId;                 
+};
+struct KIncomingSeizeParams
+{
+       sbyte NumberB[ KMAX_DIAL_NUMBER + 1 ];
+       sbyte NumberA[ KMAX_DIAL_NUMBER + 1 ];
+       sbyte Padding[2];  
+};
+struct KCtbusCommand
+{
+       int32 Stream;
+       int32 TimeSlot;
+       int32 Enable;
+};
+struct KUserInformation
+{
+    int32 ProtocolDescriptor;
+    int32 UserInfoLength;
+    byte  UserInfo[ KMAX_USER_USER_LEN ];
+};
+struct KISDNSubaddressInformation
+{
+    KQ931TypeOfSubaddress TypeOfSubaddress;
+    bool  OddNumberOfSignals;
+    int32 InformationLength;
+    byte  Information[ KMAX_SUBADRESS_INFORMATION_LEN ];
+};
+struct KISDNSubaddresses
+{
+    KISDNSubaddressInformation Called;
+    KISDNSubaddressInformation Calling;
+};
+enum KCTTransferResult
+{
+    TransferByJoin          = 0,
+    TransferByRerouteing    = 1
+};
+enum KLinkErrorCounter
+{
+       klecChangesToLock               =  0,
+       klecLostOfSignal                =  1,
+       klecAlarmNotification   =  2,
+       klecLostOfFrame         =  3,
+       klecLostOfMultiframe    =  4,
+       klecRemoteAlarm                 =  5,
+    klecSlipAlarm           =  6,
+       klecUnknowAlarm                 =  klecSlipAlarm,
+       klecPRBS                                =  7,
+       klecWrogrBits                   =  8,
+       klecJitterVariation             =  9,
+       klecFramesWithoutSync   = 10,
+       klecMultiframeSignal    = 11,
+       klecFrameError                  = 12,
+       klecBipolarViolation    = 13,
+       klecCRC4                                = 14,
+       klecCount                               = 15
+};
+struct K3L_LINK_ERROR_COUNTER
+{
+       int32 ErrorCounters[ klecCount ];
+};
+struct KSipData
+{
+    int32 DataLength;
+    byte  Data[ KMAX_SIP_DATA ];
+};
+
+enum KLibParams
+{
+       klpDebugFirmware,           
+    klpResetFwOnStartup,               
+    klpResetFwOnShutdown,       
+    klpSeizureEventCompat,      
+    klpDisableTDMBufferWarnings,
+    klpDisableInternalVoIP,     
+    klpLogCallControl,          
+    klpDoNotLogApiInterface,    
+       klpMaxParams
+};
+
+enum KFaxChannelStatus
+{
+       kfaxcsFree,
+       kfaxcsWaitingForFaxSignal,
+       kfaxcsSendingFax,
+       kfaxcsReceivingFax,
+       kfaxcsFail
+};
+enum KFaxResult
+{
+       kfaxrEndOfTransmission,
+       kfaxrStoppedByCommand,
+       kfaxrProtocolTimeout,
+       kfaxrProtocolError,
+       kfaxrRemoteDisconnection,
+       kfaxrFileError,
+       kfaxrUnknown,
+    kfaxrEndOfReception,
+       kfaxrCompatibilityError,
+       kfaxrQualityError,
+       kfaxrChannelReleased
+};
+enum KFaxFileErrorCause
+{
+       kfaxfecTransmissionStopped,
+       kfaxfecTransmissionError,
+       kfaxfecListCleared,
+       kfaxfecCouldNotOpen,    
+       kfaxfecInvalidHeader,
+       kfaxfecDataNotFound,
+       kfaxfecInvalidHeight,
+       kfaxfecUnsupportedWidth,
+       kfaxfecUnsupportedCompression,
+       kfaxfecUnsupportedRowsPerStrip,
+       kfaxfecUnknown
+};
+
+typedef stt_code ( Kstdcall K3L_CALLBACK )();
+typedef stt_code ( Kstdcall K3L_MONITOR_CALLBACK )( byte *, byte );
+typedef stt_code ( Kstdcall K3L_EVENT_CALLBACK )( int32 Object, K3L_EVENT * );
+typedef stt_code ( Kstdcall *K3L_THREAD_CALLBACK )( void * );
+typedef void    ( Kstdcall K3L_AUDIO_CALLBACK )( int32 DevId, int32 Channel, byte *Buffer, int32 Size );
+#if __GNUC__ >= 4
+#pragma GCC visibility push(default)
+#endif
+extern "C"
+{
+sbyte *Kstdcall k3lStart( int32 Major, int32 Minor, int32 Build );
+void Kstdcall k3lStop();
+void Kstdcall k3lRegisterEventHandler( K3L_EVENT_CALLBACK *Function );
+void Kstdcall k3lRegisterAudioListener( K3L_AUDIO_CALLBACK *Player, K3L_AUDIO_CALLBACK *Recorder );
+int32 Kstdcall k3lSendCommand( int32 DeviceId, K3L_COMMAND *Cmd );
+int32 Kstdcall k3lSendRawCommand( int32 DeviceId, int32 IntfId, void *Command, int32 CmdSize );
+int32 Kstdcall k3lRegisterMonitor( K3L_MONITOR_CALLBACK *EventMonitor, K3L_MONITOR_CALLBACK *CommandMonitor, K3L_MONITOR_CALLBACK *BufferMonitor );
+int32 Kstdcall k3lGetDeviceConfig( int32 DeviceId, int32 Object, void *Data, int32 DataSize );
+int32 Kstdcall k3lGetDeviceStatus( int32 DeviceId, int32 Object, void *Data, int32 DataSize );
+int32 Kstdcall k3lGetDeviceCount();
+int32 Kstdcall k3lGetDeviceType( int32 DeviceId );
+int32 Kstdcall k3lGetEventParam( K3L_EVENT *Evt, const sbyte *Name, sbyte *Buffer, int32 BufferSize );
+int32 Kstdcall k3lSetGlobalParam( int32 ParamIndex, int32 ParamValue );
+int32 Kstdcall k3lGetChannelStats( int32 DevId, int32 Channel, KStatIndex si, uint32 *StatData );
+}
+#if __GNUC__ >= 4
+#pragma GCC visibility pop
+#endif
+#endif
+
+
+enum KISDNDebugFlag
+{
+    kidfQ931                        = 0x01,
+    kidfLAPD                        = 0x02,
+    kidfSystem                      = 0x04,
+    kidfInvalid                     = 0x08,
+};
+
+#define CM_VOIP_START_DEBUG      0x20
+#define CM_VOIP_STOP_DEBUG       0x21
+#define CM_VOIP_DUMP_STAT        0x22
+
+#define CM_ISDN_DEBUG            0x24
+
+#define CM_PING     0x123456
+#define EV_PONG     0x654321
+
+#define CM_LOG_UPDATE            0x100 
+#define EV_LOG_UPDATE            0x100 
+
+#endif /* _GENERATED_K3L_H_ */
diff --git a/src/mod/endpoints/mod_khomp/include/khomp_pvt.h b/src/mod/endpoints/mod_khomp/include/khomp_pvt.h
new file mode 100644 (file)
index 0000000..5037492
--- /dev/null
@@ -0,0 +1,1289 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _KHOMP_PVT_H_
+#define _KHOMP_PVT_H_
+
+#include <timer.hpp>
+#include "globals.h"
+#include "frame.h"
+#include "opt.h"
+#include "logger.h"
+#include "defs.h"
+
+/*!
+ \brief Callback generated from K3L API for every new event on the board.
+ \param[in] obj Object ID (could be a channel or a board, depends on device type) which generated the event.
+ \param[in] e The event itself.
+ \return ksSuccess if the event was treated
+ \see K3L_EVENT Event specification
+ */
+extern "C" int32 Kstdcall khompEventCallback (int32, K3L_EVENT *);
+
+/*!
+ \brief Callback generated from K3L API everytime audio is available on the board.
+ @param[in] deviceid Board on which we get the event
+ @param[in] objectid The channel we are getting the audio from
+ @param[out] read_buffer The audio buffer itself (RAW)
+ @param[in] read_size The buffer size, meaning the amount of data to be read
+ \return ksSuccess if the event was treated
+ */
+extern "C" void Kstdcall khompAudioListener (int32, int32, byte *, int32);
+
+/******************************************************************************/
+/********************************* Board **************************************/
+/******************************************************************************/
+struct Board
+{
+    /* Timers */
+    struct KhompPvt;
+    typedef KhompPvt *     ChanTimerData;
+    typedef                void (ChanTimerFunc)(ChanTimerData);
+    typedef TimerTemplate < ChanTimerFunc, ChanTimerData > ChanTimer;
+
+/******************************************************************************/
+/******************************** Channel *************************************/
+struct KhompPvt
+{
+    // TODO: Here for while, put in right struct, when is ready
+    typedef std::vector<std::string> ContextListType;
+    typedef std::vector<std::string> ExtenListType;
+
+    typedef SimpleNonBlockLock<25,100>      ChanLockType;
+
+    typedef enum
+    {
+        CI_MESSAGE_BOX        = 0x01,
+        CI_HUMAN_ANSWER       = 0x02,
+        CI_ANSWERING_MACHINE  = 0x04,
+        CI_CARRIER_MESSAGE    = 0x08,
+        CI_UNKNOWN            = 0x10,
+        CI_FAX                = 0x20,
+    }
+    CallInfoType;
+    
+    struct InitFailure {};
+
+    struct InvalidSwitchChannel
+    {
+        typedef enum { NULL_SWITCH_CHANNEL, NULL_SWITCH_SESSION_PASSED, NULL_SWITCH_VALUE, FAILED } FailType;
+
+        InvalidSwitchChannel(FailType fail, std::string msg)
+            : _fail(fail),_msg(msg) {};
+
+        std::string _msg;
+        FailType _fail;
+    };
+
+    typedef enum
+    {
+        PLAY_NONE = 0,
+        PLAY_VM_TONE,
+        PLAY_PBX_TONE,
+        PLAY_PUB_TONE,
+        PLAY_RINGBACK,
+        PLAY_FASTBUSY,
+    }
+    CadencesType;
+
+    typedef enum
+    {
+        INDICA_NONE = 0,
+        INDICA_RING,
+        INDICA_BUSY,
+        INDICA_FAST_BUSY,
+    }
+    IndicationType;
+    
+    typedef enum
+    {
+        CLN_HARD,
+        CLN_SOFT,
+        CLN_FAIL,
+    }
+    CleanupType;
+
+/********************************** Call **************************************/
+    struct Call
+    {
+        struct CallStatistics : public Statistics
+        {
+            CallStatistics(Call *call):
+                _call(call),
+                _total_time_incoming(0),
+                _total_time_outgoing(0),
+                _total_idle_time(0),
+                _channel_fails(0)
+            {
+                time(&_base_idle_time);            
+                time(&_base_time);            
+            }
+
+            void idle()
+            {
+                if (_call->_flags.check(Kflags::IS_INCOMING) || 
+                    _call->_flags.check(Kflags::IS_OUTGOING) ||
+                    _call->_indication == INDICA_RING ||
+                    _call->_indication == INDICA_BUSY)
+                {   
+                    return;
+                }   
+
+                time_t tmp;
+                time (&tmp);
+
+                _total_idle_time += (tmp - _base_idle_time);
+                time (&_base_idle_time);
+            }
+
+            void incrementNewCall()
+            {
+                time (&_base_time);
+            }
+
+            void incrementHangup()
+            {
+                time_t tmp;
+                time (&tmp);
+
+                if (_call->_flags.check(Kflags::IS_OUTGOING))
+                {   
+                    _total_time_outgoing += (tmp - _base_time);
+                    time (&_base_time);
+                }   
+                else if (_call->_flags.check(Kflags::IS_INCOMING))
+                {   
+                    _total_time_incoming += (tmp - _base_time);
+                    time (&_base_time);
+                }   
+
+                time(&_base_idle_time);
+            }
+
+            void incrementChannelFail()
+            {
+                _channel_fails++;
+            }
+
+            std::string getDetailed() 
+            {
+                /* buffer our data to return at the end */
+                std::string strBuffer;
+
+                /* very very important yet! */
+                idle();
+
+                std::string str_incoming_time = timeToString(_total_time_incoming);
+                std::string str_outgoing_time = timeToString(_total_time_outgoing);
+                std::string str_idle_time     = timeToString(_total_idle_time);
+
+                strBuffer.append(STG(FMT("Total Incoming Time: \t%s\n") % str_incoming_time));
+                strBuffer.append(STG(FMT("Total Outgoing Time: \t%s\n") % str_outgoing_time));
+                strBuffer.append(STG(FMT("Total Idle Time: \t%s\n") % str_idle_time));
+                strBuffer.append(STG(FMT("Number of channel fails: \t%d\n") % _channel_fails));                
+
+                return strBuffer;
+            }
+
+            void clear()
+            {   
+                time(&_base_time);
+                time(&_base_idle_time);
+
+                _total_idle_time = 0;
+                _channel_fails = 0;
+
+                _total_time_incoming = 0;
+                _total_time_outgoing = 0;
+            }
+
+            time_t _base_time;
+            time_t _total_time_incoming;
+            time_t _total_time_outgoing;
+            time_t _total_idle_time;
+            time_t _base_idle_time;     /* base time for idle time refreshing */
+            unsigned int _channel_fails;/* number of channel fails*/
+
+        protected:        
+            Call *_call;  /* associate to call, useful */
+        };
+
+        Call() 
+        {
+            clear(); 
+            _call_statistics = new CallStatistics(this);
+        }
+
+        virtual ~Call() { delete _call_statistics; }
+
+        CallStatistics * statistics() { return _call_statistics; };
+
+        virtual bool process(std::string name, std::string value = "")
+        {
+            if (name == "pre_answer")
+            {
+                _pre_answer = true;
+            }
+            else if (name == "orig")
+            {
+                DBG(FUNC, FMT("orig addr adjusted (%s).") % value.c_str());
+                _orig_addr = value;
+            }
+            else if (name == "dest")
+            {
+                _dest_addr = value;
+            }
+
+            else if (name == "input_volume" || name == "output_volume")
+            {
+                try
+                {
+                    //std::string type((name == "input_volume")?"input":"output");
+
+                    int i = Strings::tolong(value);
+    
+                    if (i < -10 || i > 10)
+                    {
+                        LOG(ERROR, FMT("Could not set '%s': '%s' is not a valid number between -10 and 10.") % name % value);
+                    }
+                    else
+                    {
+                        DBG(FUNC, FMT("Changing '%s' volume to '%s'.") % name % value);
+                        if(name == "input_volume")
+                            _input_volume = i;
+                        else
+                            _output_volume = i;
+                    }
+                }
+                catch (Strings::invalid_value & e)
+                {
+                    LOG(ERROR, D("invalid numeric value: %s") % e.value());
+                }
+            }
+
+            else
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        virtual bool clear()
+        {
+
+            _orig_addr.clear();
+            _dest_addr.clear();
+            _incoming_context.clear();
+            _queued_digits_buffer.clear();
+            _pre_answer = false;
+            _is_progress_sent = false;
+            _collect_call = false;
+            _hangup_cause = 0;
+            _cleanup_upon_hangup = false;
+            _input_volume = 999;
+            _output_volume = 999;
+
+            _var_dtmf_state = T_UNKNOWN;
+            _var_echo_state = T_UNKNOWN;
+            _var_gain_state = T_UNKNOWN;            
+            
+            _flags.clearAll();
+
+            _cadence = PLAY_NONE;
+            _indication = INDICA_NONE;
+
+            return true;
+        }
+
+        /* used while answering calls */
+        std::string _orig_addr;
+        std::string _dest_addr;
+
+        std::string _incoming_context;
+
+        std::string _queued_digits_buffer;
+
+        /* should freeswitch answer before connect event?  */
+        bool _pre_answer;
+
+        bool _is_progress_sent;
+
+        /* is a collect call? */
+        bool _collect_call;
+
+        int _hangup_cause;
+
+        bool _cleanup_upon_hangup;
+
+        int _input_volume;
+        int _output_volume;
+
+        TriState _var_dtmf_state;
+        TriState _var_echo_state;
+        TriState _var_gain_state;        
+
+        Kflags _flags;
+
+        CadencesType _cadence;
+        IndicationType _indication;
+        
+        ChanTimer::Index _idx_co_ring;
+        ChanTimer::Index _idx_pbx_ring;
+
+        CallStatistics *_call_statistics;
+    };
+/******************************************************************************/
+public:
+
+    /* KhompPvt constructor */
+    KhompPvt(K3LAPI::target & target);
+
+    /* KhompPvt destructor */
+    virtual ~KhompPvt()
+    {
+        delete _pvt_statistics;
+        _session = NULL;
+    }
+   
+    struct PvtStatistics : public Statistics
+    {
+        PvtStatistics(KhompPvt * pvt):
+            _pvt(pvt) {}
+
+        std::string getDetailedRates();
+        std::string getDetailed();
+        std::string getRow();
+
+        void clear()
+        {
+            _pvt->call()->statistics()->clear();
+        }
+        
+        KhompPvt * _pvt;
+    };
+
+    /* Virtual Methods */
+
+    /*!
+     \defgroup KhompEvents
+                Callbacks that boards can implement to produce the expected
+                particular behaviour. Refer to Khomp documentation for a
+                detailed description of each method.
+     */
+    /*@{*/
+    virtual bool onChannelRelease(K3L_EVENT *);
+    virtual bool onNewCall(K3L_EVENT *);
+    virtual bool onCallSuccess(K3L_EVENT *);
+    virtual bool onCallFail(K3L_EVENT *);
+    virtual bool onConnect(K3L_EVENT *);
+    virtual bool onDisconnect(K3L_EVENT *);
+    virtual bool onAudioStatus(K3L_EVENT *);
+    virtual bool onCollectCall(K3L_EVENT *);
+    virtual bool onSeizureStart(K3L_EVENT *);
+    virtual bool onDtmfDetected(K3L_EVENT *);
+    virtual bool onNoAnswer(K3L_EVENT *);
+    virtual bool onDtmfSendFinish(K3L_EVENT *);
+    virtual bool onEvUntreated(K3L_EVENT *);
+    virtual bool eventHandler(K3L_EVENT *);
+    /*@}*/
+    
+    virtual bool doChannelAnswer(CommandRequest &);
+    virtual bool doChannelHangup(CommandRequest &);
+    bool commandHandler(CommandRequest &);
+    
+    virtual int makeCall(std::string params = "");
+    virtual bool setupConnection();
+
+    virtual int causeFromCallFail(int fail)  { return SWITCH_CAUSE_USER_BUSY; };
+    virtual int callFailFromCause(int cause) { return -1; };
+    virtual void reportFailToReceive(int fail_code) 
+    { 
+        call()->_indication = INDICA_FAST_BUSY; 
+    }
+    virtual bool setCollectCall();
+
+    virtual bool indicateBusyUnlocked(int cause, bool sent_signaling = false);
+
+    virtual bool cleanup(CleanupType type = CLN_HARD);
+
+    virtual RingbackDefs::RingbackStType sendRingBackStatus(int rb_value = RingbackDefs::RB_SEND_DEFAULT) 
+    { 
+        return RingbackDefs::RBST_UNSUPPORTED; 
+    }
+
+    virtual bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING) 
+    { 
+        if (rb_value != RingbackDefs::RB_SEND_NOTHING)
+        {
+            if(sendRingBackStatus(rb_value) == RingbackDefs::RBST_FAILURE)
+                return false;
+        }
+
+        return true;
+    }
+    
+    virtual bool isOK(void) { return false; }
+    virtual bool isPhysicalFree() { return false; }
+    virtual bool isFree(bool just_phy = false);
+
+    virtual bool hasNumberDial() { return true; }
+
+    virtual void getSpecialVariables()
+    {
+        try
+        {
+            const char * str_sup = getFSChannelVar("KDTMFSuppression");
+            const char * str_agc = getFSChannelVar("KAutoGainControl");
+            const char * str_eco = getFSChannelVar("KEchoCanceller");
+
+            call()->_var_dtmf_state = (str_sup ? ((!SAFE_strcasecmp(str_sup, "true") || !SAFE_strcasecmp(str_sup, "on"))? T_TRUE : T_FALSE) : T_UNKNOWN);
+            call()->_var_echo_state = (str_eco ? (!SAFE_strcasecmp(str_eco, "true") ? T_TRUE : T_FALSE) : T_UNKNOWN);
+            call()->_var_gain_state = (str_agc ? (!SAFE_strcasecmp(str_agc, "true") ? T_TRUE : T_FALSE) : T_UNKNOWN);
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "%s") % err._msg.c_str());
+        }
+
+        try
+        {
+            char * volume = (char*) getFSChannelVar("KSetVolume");
+            
+            if(!volume)
+            {
+                return;
+            }
+
+            std::string datastr(volume);
+
+            Strings::trim(datastr);
+
+            Strings::vector_type params;
+            Strings::tokenize(datastr, params, "|,", 2);
+
+            int inpvol = INT_MAX;
+            int outvol = INT_MAX;
+
+            /**/ if (params.size() == 1)
+            {    
+                int vol = (params[0] != "none" ? Strings::tolong(params[0]) : INT_MAX);
+
+                inpvol = vol; 
+                outvol = vol; 
+            }    
+            else if (params.size() == 2)
+            {    
+                inpvol = (params[0] != "none" ? Strings::tolong(params[0]) : INT_MAX);
+                outvol = (params[1] != "none" ? Strings::tolong(params[1]) : INT_MAX);
+            }    
+            else 
+            {    
+                LOG(ERROR, "invalid number of arguments for KSetVolume!");
+                return;
+            }    
+
+            if (inpvol != INT_MAX)
+            {
+                if(_call->_input_volume < -10 || _call->_input_volume > 10)
+                {
+                    _call->_input_volume = inpvol;
+                }
+            }
+
+            if (outvol != INT_MAX)
+            {
+                if(_call->_output_volume < -10 || _call->_output_volume > 10)
+                {
+                    _call->_output_volume = outvol;
+                }
+            }
+
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "%s") % err._msg.c_str());            
+        }
+        catch (Strings::invalid_value e)
+        {    
+            LOG(ERROR, FMT("invalid numeric value: %s") % e.value());
+        }    
+    }
+    
+    virtual void setSpecialVariables() {}
+
+    virtual bool application(ApplicationType type, switch_core_session_t * session, const char *data) 
+    {
+        switch(type)
+        {
+        case FAX_ADJUST:
+        case FAX_SEND:
+        case FAX_RECEIVE:
+            LOG(ERROR, PVT_FMT(_target, "not a digital and not "
+                    "a fxo Khomp channel, fax not supported"));
+            break;
+        default:
+            LOG(ERROR, PVT_FMT(_target, 
+                    "application not supported"));
+            break;
+        }
+
+        return false;
+    }
+
+    /* statistics functions */
+    virtual std::string getStatistics(Statistics::Type type);
+    virtual void clearStatistics()
+    {
+        _pvt_statistics->clear();   
+    }
+
+    virtual bool indicateRinging();
+    virtual bool sendDtmf(std::string digit);
+
+    /* Methods */
+
+    bool indicateProgress();
+
+    bool signalDTMF(char d);
+
+    bool loopWhileFlagTimed(Kflags::FlagType flag, int &timeout, bool clear = true)
+    {
+        bool pvt_locked = true;
+        bool quit       = false;
+
+        unsigned int sleeps = 0;
+
+        while ((timeout != 0) && !quit)
+        {
+            for (; (sleeps < 10) && !quit; sleeps++)
+            {
+                /* unlock our pvt struct */
+                if (pvt_locked)
+                {
+                    _mutex.unlock();
+                    pvt_locked = false;
+                }
+
+                /* wait a little while (100ms is good?) */
+                usleep (100000);
+                ++sleeps;
+
+                /* re-lock pvt struct */
+                switch (_mutex.lock())
+                {
+                    case SimpleLock::ISINUSE:
+                    case SimpleLock::FAILURE:
+                        LOG(ERROR, PVT_FMT(_target, "unable to lock pvt_mutex, trying again."));
+
+                        sched_yield();
+                        continue;
+
+                    default:
+                        break;
+                }
+
+                pvt_locked = true;
+
+                if(clear)
+                {
+                    if(!call()->_flags.check(flag))
+                    {
+                        quit = true;
+                        break;
+                    }
+                }
+                else
+                {
+                    if(call()->_flags.check(flag))
+                    {
+                        quit = true;
+                        break;
+                    }
+
+                }
+            }
+
+            /* decrement timeout, zero "sleeps". */
+            timeout = (timeout > 0) ? timeout - 1 : timeout;
+            sleeps = 0;
+        }
+
+        /* pvt should always be locked when retuning here. */
+        return pvt_locked;
+    }
+
+    K3LAPI::target & target()
+    {
+        return _target;
+    }
+
+    void session(switch_core_session_t * newSession)
+    {
+        _session = newSession;
+    }
+
+    switch_core_session_t * session()
+    {
+        return _session;
+    }
+
+    void owner(switch_core_session_t * owner) { _owner = owner; }
+
+    switch_core_session_t * owner() const { return _owner; }
+
+    /* 
+       Returns the FreeSWITCH channel (switch_channel_t) 
+       Can throw InvalidSwitchChannel, so must be carefull
+    */
+    switch_channel_t * getFSChannel()
+    {
+        if(!session()) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t");
+        switch_channel_t *c = switch_core_session_get_channel(session());
+        if(!c) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+        return c;       
+    }
+
+    /* 
+       Returns the FreeSWITCH channel (switch_channel_t) from given session 
+       Can throw InvalidSwitchChannel, so must be carefull
+    */
+    static switch_channel_t * getFSChannel(switch_core_session_t * s)
+    {
+        if(!s) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t passed");
+        switch_channel_t *c = switch_core_session_get_channel(s);
+        if(!c) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+        return c;       
+    }
+
+    /* 
+       Returns the FreeSWITCH partner session (switch_core_session_t) 
+       Can throw InvalidSwitchChannel, so must be carefull
+       Don't forget to unlock [unlockPartner(switch_core_session_t*)]
+    */
+    switch_core_session_t * getFSLockedPartnerSession()
+    {
+        if(!session()) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t");
+
+        switch_core_session_t * p_s = NULL;
+        switch_core_session_get_partner(session(), &p_s);
+
+        if(!p_s)
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t (partner)");
+        return p_s;
+    }
+
+    /* Unlock a partner session */
+    void unlockPartner(switch_core_session_t * s)
+    {
+        if(!s) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t passed");
+        switch_core_session_rwunlock(s);
+    }
+
+    /* Get the uuid of session */
+    char * getUUID()
+    {
+        if(!session()) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t");
+        return switch_core_session_get_uuid(session());        
+    }
+
+    /* Get the uuid of given session */
+    char * getUUID(switch_core_session_t * s)
+    {
+        if(!s)
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_SESSION_PASSED,"null switch_core_session_t passed");
+        return switch_core_session_get_uuid(s);        
+    }
+
+    /* 
+       Set a variable into a FS channel 
+       Can throw InvalidSwitchChannel, so must be carefull
+    */
+    void setFSChannelVar(const char * name, const char * value)
+    {
+        if(!name || !value)
+            return;
+
+        switch_channel_t *c = getFSChannel(_owner);
+        if(!c) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+        switch_channel_set_variable(c,name,value);
+    }    
+
+   /* 
+      Set a variable into a FS channel 
+      Can throw InvalidSwitchChannel, so must be carefull
+   */
+   void setFSChannelVar(switch_channel_t *c, const char * name, const char * value)
+   {
+       if(!c)
+           throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+      
+       if(!name || !value)
+           return;
+
+       switch_channel_set_variable(c,name,value);
+   }
+
+    /* 
+       Get a varibale from a FS channel
+       Can throw InvalidSwitchChannel, so must be carefull
+    */
+    const char * getFSChannelVar(const char * value)
+    {
+        if(!value)
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_VALUE, "value is null");
+
+        switch_channel_t *c = getFSChannel(_owner);
+        if(!c) 
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+        return switch_channel_get_variable(c,value);
+    }
+
+    /* 
+       Get a varibale from a FS from a given channel
+       Can throw InvalidSwitchChannel, so must be carefull
+    */
+    const char * getFSChannelVar(switch_channel_t *c, const char * value)
+    {
+        if(!c)
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_CHANNEL,"null switch_channel_t obtained");
+        if(!value)
+            throw InvalidSwitchChannel(InvalidSwitchChannel::NULL_SWITCH_VALUE, "value is null");
+        return switch_channel_get_variable(c,value);
+    }
+
+    /* Set a global variable  (without any throw) */
+    void setFSGlobalVar(const char * name, const char * value)
+    {
+        if(!name || !value)
+            return;
+
+        switch_core_set_variable(name,value);
+    }
+
+    /* Get a global variable (without any throw) */
+    const char * getFSGlobalVar(const char * name)
+    {
+        if(!name)
+            return NULL;
+
+        return switch_core_get_variable(name);
+    }
+
+    bool mixer(const char *file, const char *func, int line, 
+            byte track, KMixerSource src, int32 index)
+    {
+        KMixerCommand mix;
+
+        mix.Track = track;
+        mix.Source = src;
+        mix.SourceIndex = index;
+
+        return command(file, func, line, CM_MIXER, (const char *)&mix);
+    }
+
+    /* Error handling for send command */
+    bool command(const char *file, const char *func, int line, int code,
+            const char *params = NULL, bool log = true)
+    {
+        try
+        {
+            Globals::k3lapi.command(_target, code, params);
+        }
+        catch(K3LAPI::failed_command & e)
+        {
+            if(log)
+            {
+                DBG(FUNC, OBJ_FMT(e.dev,e.obj,"Command '%s' has failed with error '%s'")
+                   % Verbose::commandName(e.code).c_str()
+                   % Verbose::status((KLibraryStatus)e.rc).c_str());
+            }
+
+            return false;
+        }
+
+        return true;
+    }
+    
+    //TODO: Unir os dois metodos
+    int commandState(const char *file, const char *func, int line, int code,
+            const char *params = NULL)
+    {
+        try
+        {
+            Globals::k3lapi.command(_target, code, params);
+        }
+        catch(K3LAPI::failed_command & e)
+        {
+            LOG(ERROR,OBJ_FMT(e.dev,e.obj,"Command '%s' has failed with error '%s'")
+               % Verbose::commandName(e.code).c_str()
+               % Verbose::status((KLibraryStatus)e.rc).c_str());
+
+            return e.rc;
+        }
+
+        return ksSuccess;
+    }
+
+    /*!
+     \brief Will init part of our private structure and setup all the read/write
+     buffers along with the proper codecs. Right now, only PCMA.
+    */
+    switch_status_t justAlloc(bool is_answering = true, switch_memory_pool_t **pool = NULL);
+    switch_status_t justStart(switch_caller_profile_t *profile = NULL);
+
+    void destroy(switch_core_session_t * s = NULL);
+    void destroyAll();
+
+    void doHangup();
+
+    void setHangupCause(int cause, bool set_now = false)
+    {
+        if(_call->_hangup_cause) 
+        { 
+
+            DBG(FUNC,PVT_FMT(_target,"cause already set to %s") % switch_channel_cause2str((switch_call_cause_t) _call->_hangup_cause));
+            return;
+        }
+
+        if(!session())
+        {
+            DBG(FUNC,PVT_FMT(_target,"session is null"));
+            return;
+        }
+
+        switch_channel_t * channel = NULL;
+        
+        try
+        {
+            channel = getFSChannel();
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            DBG(FUNC, PVT_FMT(_target,"%s") % err._msg.c_str());
+            return;
+        }
+
+        int cause_from_freeswitch = switch_channel_get_cause(channel);
+        if(cause_from_freeswitch != SWITCH_CAUSE_NONE)
+        {
+            DBG(FUNC,PVT_FMT(_target,"cause already set to %s from freeswitch") % switch_channel_cause2str((switch_call_cause_t)cause_from_freeswitch));
+            _call->_hangup_cause = cause_from_freeswitch;
+            return;
+        }
+        
+        if(!cause)
+        {
+            DBG(FUNC,PVT_FMT(_target,"cause not defined"));
+        }
+        else
+        {
+            DBG(FUNC,PVT_FMT(_target,"setting cause to '%s'") % switch_channel_cause2str((switch_call_cause_t) cause));
+            _call->_hangup_cause = cause;
+
+            // not set variable in channel owner
+            if(set_now)
+            {
+                switch_channel_hangup(channel, (switch_call_cause_t)_call->_hangup_cause);
+            }
+        }
+    }
+
+    bool startCadence(CadencesType type);
+    bool stopCadence()
+    {
+        if(call()->_cadence != PLAY_NONE)
+        {
+            call()->_cadence = PLAY_NONE;
+
+            command(KHOMP_LOG, CM_STOP_CADENCE);
+        }
+    }
+
+    bool startStream(bool enable_mixer = true);
+    bool stopStream(bool enable_mixer = true);
+
+    bool startListen(bool conn_rx = true);
+    bool stopListen(void);
+
+    bool obtainRX(bool with_delay = false);
+    bool obtainTX();
+
+    bool setVolume(const char * type, int volume);
+    bool setVolume()
+    {
+        bool ret = false;
+
+        if(_call->_input_volume >= -10 && _call->_input_volume <= 10)
+        {
+            setVolume("input", _call->_input_volume);
+            ret = true;
+        }
+
+        if(_call->_output_volume >= -10 && _call->_output_volume <= 10)
+        {
+            setVolume("output", _call->_output_volume);
+            ret = true;
+        }
+     
+        return ret;
+    }
+
+    KSignaling getSignaling(void)
+    {
+        return Globals::k3lapi.channel_config(_target.device,_target.object).Signaling;
+    }
+
+    std::string getStateString(void);
+
+    bool dtmfSuppression(bool enable);
+    bool echoCancellation(bool enable);
+    virtual bool autoGainControl(bool enable);    
+
+    /* Timer callbacks */
+    static void pbxRingGen(Board::KhompPvt * pvt);
+    static void coRingGen(Board::KhompPvt * pvt);
+
+    virtual int getActiveChannel(bool invalid_as_not_found);
+
+    MatchType matchExtension(std::string &, std::string &, std::string &, bool match_only = false);
+
+    MatchType findExtension(std::string &, std::string &, ContextListType &, std::string &, std::string &, 
+                            bool default_ctx = true, bool default_ext = true);
+
+    /* Let's validate the contexts */
+    virtual bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_string = "")
+    {
+        DBG(FUNC,PVT_FMT(_target,"c"));
+
+        if(!_group_context.empty())
+        {
+            contexts.push_back(_group_context);
+        }
+    
+        for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++) 
+            replaceTemplate((*i),  "DD", _target.device);
+
+        BEGIN_CONTEXT  
+        {    
+            K3L_DEVICE_CONFIG & dev_cfg = Globals::k3lapi.device_config(_target.device);
+
+            for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++) 
+                replaceTemplate((*i), "SSSS", atoi(dev_cfg.SerialNumber));
+        }    
+        END_CONTEXT
+      
+        DBG(FUNC,PVT_FMT(_target,"r"));
+        return true;
+    }
+
+    void cleanupBuffers()
+    {
+        DBG(FUNC,PVT_FMT(_target, "Cleanup buffers"));
+
+        _reader_frames.clear();
+        _writer_frames.clear();
+
+        for(unsigned int i = 0; i < SILENCE_PACKS; i++)
+        {
+            /* add silence to the read buffer */
+            if (!_reader_frames.give((const char *)Board::_cng_buffer, Globals::switch_packet_size))
+            {
+                LOG(ERROR, PVT_FMT(target(), "Problem in Reader Buffer"));
+            }
+        
+            /* add silence to the writer buffer */
+            if (!_writer_frames.give((const char *)Board::_cng_buffer, Globals::boards_packet_size))
+            {
+                LOG(ERROR, PVT_FMT(target(), "Problem in Writer Buffer"));
+            }
+        }
+    }
+
+    bool freeState()
+    {
+        return !(_call->_flags.check(Kflags::IS_INCOMING) || _call->_flags.check(Kflags::IS_OUTGOING));
+    }
+
+    Call * call() { return _call; }
+
+    K3LAPI::target           _target;    /*!< The device/channel pair to bind this pvt to */
+    ChanLockType             _mutex;     /*!< Used for *our* internal locking */
+    Call                    *_call;
+    switch_core_session_t   *_session;   /*!< The session to which this pvt is associated with */
+    switch_core_session_t   *_owner;
+    bool                     _has_fail;
+
+    switch_caller_profile_t *_caller_profile;
+
+    switch_codec_t           _read_codec;
+    switch_codec_t           _write_codec;
+
+    FrameSwitchManager       _reader_frames;
+    FrameBoardsManager       _writer_frames;
+
+    std::string              _group_context;
+
+    PvtStatistics           *_pvt_statistics;
+};
+
+/******************************************************************************/
+/******************************************************************************/
+    typedef std::vector < Board * >    VectorBoard;
+    typedef std::vector < KhompPvt * > VectorChannel;  /*!< Collection of pointers of KhompPvts */
+
+     /*
+        these (below) are going to rule the elements ordering in our multiset
+        (used as a "ordering-save priority queue").
+     */
+    struct PvtCallCompare
+    {
+        bool operator() (KhompPvt * pvt1, KhompPvt * pvt2) const
+        {
+            /* true if pvt1 precedes pvt2 */
+            return (Board::getStats(pvt1->target().device,pvt1->target().object,kcsiOutbound) <
+                    Board::getStats(pvt2->target().device,pvt2->target().object,kcsiOutbound));
+            return true;
+        }
+    };
+
+    typedef std::multiset< KhompPvt *, PvtCallCompare > PriorityCallQueue;
+   
+public:
+    
+    /* Board constructor */
+    Board(int id) : _device_id(id) {}
+
+    /* Board destructor */    
+    virtual ~Board() {}
+
+    int id() { return _device_id; }
+
+    KhompPvt * channel(int obj)
+    {
+        try
+        {
+            KhompPvt * pvt = _channels.at(obj);
+
+            if(!pvt)
+            {
+                throw;
+            }
+
+            return pvt;
+        }
+        catch (...)
+        {
+            throw K3LAPI::invalid_channel(_device_id, obj);
+        }
+    }
+
+    ChanEventHandler * chanEventHandler() { return _event_handler; }
+    
+    ChanCommandHandler * chanCommandHandler() { return _command_handler; }
+
+    virtual void initializeChannels(void);
+    void finalizeChannels(void);
+
+    virtual bool eventHandler(const int obj, K3L_EVENT *e)
+    {
+        DBG(STRM, D("(Generic Board) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+        case EV_REQUEST_DEVICE_SECURITY_KEY:
+            break;
+        default:
+            try
+            {
+                ret = channel(obj)->eventHandler(e);
+            }
+            catch (K3LAPI::invalid_channel & invalid)
+            {
+                LOG(ERROR, OBJ_FMT(_device_id,obj,"(Generic Board) r (invalid channel on event '%s')") 
+                % Verbose::eventName(e->Code).c_str());
+
+                return false;
+            }
+
+            break;
+        }
+        
+        DBG(STRM, D("(Generic Board) r"));
+
+        return ret;
+    }
+
+public:
+    ChanTimer            _timers;
+protected:
+    const int            _device_id;
+    ChanEventHandler   * _event_handler; /* The device event handler */
+    ChanCommandHandler * _command_handler; /* The device command handler */
+    VectorChannel        _channels;
+
+public:
+    /* static stuff */
+    static bool initializeK3L(void);
+    static bool finalizeK3L(void);
+    static bool initializeHandlers(void);
+    static bool finalizeHandlers(void);
+    static void initializeBoards(void);
+    static void finalizeBoards(void);
+    static void initializeCngBuffer(void);
+    static bool initialize(void);
+    static bool finalize(void);
+
+    /* Thread Device Event Handler */
+    static int eventThread(void *);
+    
+    /* Thread Device Command Handler */
+    static int commandThread(void *);
+
+    /*!
+      \brief Lookup channels and boards when dialed.
+      \param allocation_string The dialstring as put on Dialplan. [Khomp/[a|A|0-board_high]/[a|A|0-channel_high]/dest].
+      \param new_session Session allocated for this call.
+      \param[out] cause Cause returned. Returns NULL if suceeded if not, the proper cause.
+      \return KhompPvt to be used on the call.
+      */
+    static KhompPvt * find_channel(char* allocation_string, switch_core_session_t * new_session, switch_call_cause_t * cause);
+    static void khomp_add_event_board_data(const K3LAPI::target target, switch_event_t *event);
+
+    static Board * board(int dev)
+    {
+        try
+        {
+            Board * b = _boards.at(dev);
+
+            if(!b)
+            {
+                throw;
+            }
+
+            return b;
+        }
+        catch(...)
+        {
+            throw K3LAPI::invalid_device(dev);
+        }
+    }
+
+    static KhompPvt * get(int32 device, int32 object)
+    {
+        //if (!Globals::k3lapi.valid_channel(device, object))
+        //    throw K3LAPI::invalid_channel(device, object);
+
+        try
+        {
+            return board(device)->channel(object);
+        }
+        catch(...)
+        {
+            throw K3LAPI::invalid_channel(device, object);
+        }
+    }
+
+    static KhompPvt * get(K3LAPI::target & target)
+    {
+        //if (!Globals::k3lapi.valid_channel(target.device, target.object))
+        //    throw K3LAPI::invalid_channel(target.device, target.object);
+
+        try
+        {
+            return board(target.device)->channel(target.object);
+            //return KhompPvt::_pvts[target.device][target.object];
+        }
+        catch(...)
+        {
+            return NULL;
+            //throw K3LAPI::invalid_channel(target.device, target.object);
+        }
+    }
+
+    static unsigned int getStats(int32 device, int32 object, uint32 index)
+    {
+        unsigned int stats = (unsigned int)-1;
+
+        try
+        {
+            stats = Globals::k3lapi.channel_stats(device, object, index);
+        }
+        catch(K3LAPI::invalid_channel & err)
+        {
+        //K::logger::logg(C_WARNING, B(dev,channel, "Command get_stats has failed with error '%s'.") %
+        //                          Verbose::status((KLibraryStatus) stt_res));
+        }
+
+        return stats;
+    }
+
+    static KhompPvt * queueFindFree(PriorityCallQueue &pqueue);
+    static void queueAddChannel(PriorityCallQueue &pqueue, unsigned int board, unsigned int object);
+    static KhompPvt * findFree(unsigned int board, unsigned int object, bool fully_available = true);
+    static void applyGlobalVolume(void);
+
+public:
+
+    static VectorBoard     _boards;
+    static char            _cng_buffer[Globals::cng_buffer_size];
+
+    static Kommuter        kommuter;
+
+};
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#endif /* _KHOMP_PVT_H_*/
diff --git a/src/mod/endpoints/mod_khomp/include/khomp_pvt_fxo.h b/src/mod/endpoints/mod_khomp/include/khomp_pvt_fxo.h
new file mode 100644 (file)
index 0000000..87eaa29
--- /dev/null
@@ -0,0 +1,376 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _KHOMP_PVT_FXO_H_
+#define _KHOMP_PVT_FXO_H_
+
+#include "khomp_pvt.h"
+#include "applications.h"
+
+/******************************************************************************/
+/********************************* FXO Board **********************************/
+/******************************************************************************/
+struct BoardFXO: public Board
+{
+/******************************************************************************/
+/******************************** FXO Channel *********************************/
+struct KhompPvtFXO: public KhompPvt 
+{
+/********************************** FXO Call **********************************/
+    struct CallFXO : public Call
+    {
+        CallFXO() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "pre")
+            {
+                DBG(FUNC, D("pre digits adjusted (%s).") % value);
+                _pre_digits = value;
+            }
+            else if (name == "answer_info")
+            {
+                _call_info_report = true;
+            }
+            else if (name == "drop_on")
+            {
+                _call_info_report = true;
+
+                Strings::vector_type drop_item;
+                Strings::tokenize (value, drop_item, ".+");
+
+                for (Strings::vector_type::iterator i = drop_item.begin(); i != drop_item.end(); i++)
+                {
+
+                         if ((*i) == "message_box")        _call_info_drop |= CI_MESSAGE_BOX;
+                    else if ((*i) == "human_answer")       _call_info_drop |= CI_HUMAN_ANSWER;
+                    else if ((*i) == "answering_machine")  _call_info_drop |= CI_ANSWERING_MACHINE;
+                    else if ((*i) == "carrier_message")    _call_info_drop |= CI_CARRIER_MESSAGE;
+                    else if ((*i) == "unknown")            _call_info_drop |= CI_UNKNOWN;
+                    else
+                    {
+                        LOG(ERROR, FMT("unknown paramenter to 'calldrop' Dial option: '%s'.") % (*i));
+                        continue;
+                    }
+
+                    DBG(FUNC, FMT("droping call on '%s'.") % (*i));
+                }
+            }
+            else if (name == "usr_xfer")
+            {
+                _user_xfer_digits = value;
+            }
+            else
+            {            
+                return Call::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            _pre_digits.clear();
+            _call_info_report = false;
+            _call_info_drop = 0;
+
+            _user_xfer_digits = Opt::_user_xfer;
+            _user_xfer_buffer.clear();
+            _digits_buffer.clear();
+
+            _var_fax_adjust = T_UNKNOWN;
+            return Call::clear();
+        }
+
+        std::string  _pre_digits;
+
+        /* report what we got? */
+        bool _call_info_report;
+
+        /* what call info flags should make us drop the call? */
+        long int _call_info_drop;
+
+        /* used for xfer on user signaling */
+        std::string _user_xfer_digits;
+        std::string _user_xfer_buffer;
+        std::string _digits_buffer;
+
+        TriState _var_fax_adjust;
+
+        //ChanTimer::Index _idx_disconnect;        
+    };
+/******************************************************************************/
+    KhompPvtFXO(K3LAPI::target & target) : KhompPvt(target) 
+    {
+        _fax = new Fax(this);
+        _transfer = new Transfer<CallFXO>(this);
+        command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
+    }
+
+    ~KhompPvtFXO() 
+    {
+        delete _fax;
+        delete _transfer;
+    }
+
+    CallFXO * callFXO()
+    {
+        return (CallFXO *)call();
+    }
+
+    int makeCall(std::string params = "");
+    bool doChannelAnswer(CommandRequest &);
+
+    bool onNewCall(K3L_EVENT *e);
+    bool onDisconnect(K3L_EVENT *e);
+    bool onChannelRelease(K3L_EVENT *e);
+    bool onCallSuccess(K3L_EVENT *e);
+    bool onCallFail(K3L_EVENT *e);
+    bool onAudioStatus(K3L_EVENT *e);
+    bool onSeizeSuccess(K3L_EVENT *e);
+    bool onDtmfDetected(K3L_EVENT *e);
+    bool onDtmfSendFinish(K3L_EVENT *);
+    bool onCallAnswerInfo(K3L_EVENT *e);
+
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(FXO) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_NEW_CALL:
+                ret = onNewCall(e);
+                break;
+            case EV_DISCONNECT:
+                ret = onDisconnect(e);
+                break;
+            case EV_CHANNEL_FREE:
+            case EV_CHANNEL_FAIL:
+                ret = onChannelRelease(e);
+                break;
+            case EV_CALL_SUCCESS:
+                ret = onCallSuccess(e);
+                break;
+            case EV_CALL_FAIL:
+                ret = onCallFail(e);
+                break;
+            case EV_AUDIO_STATUS:
+                ret = onAudioStatus(e);
+                break;
+            case EV_SEIZE_SUCCESS:
+                ret = onSeizeSuccess(e);
+                break;
+            case EV_DTMF_DETECTED:
+            case EV_PULSE_DETECTED:
+                ret = onDtmfDetected(e);
+                break;
+            case EV_DTMF_SEND_FINISH:
+                ret = onDtmfSendFinish(e);
+                break;
+            case EV_CALL_ANSWER_INFO:
+                ret = onCallAnswerInfo(e);
+                break;
+            case EV_FAX_CHANNEL_FREE:
+                ret = _fax->onFaxChannelRelease(e);
+                break;
+            case EV_FAX_FILE_SENT:
+            case EV_FAX_FILE_FAIL:
+            case EV_FAX_TX_TIMEOUT:
+            case EV_FAX_PAGE_CONFIRMATION:
+            case EV_FAX_REMOTE_INFO:
+                break;
+            case EV_POLARITY_REVERSAL:
+                break;
+            default:
+                ret = KhompPvt::eventHandler(e);
+                break;
+        }
+
+        DBG(STRM, D("(FXO) r"));
+
+        return ret;
+    }
+
+    bool application(ApplicationType type, switch_core_session_t * session, const char *data);
+
+    bool setupConnection();
+    bool autoGainControl(bool enable);
+    void setAnswerInfo(int answer_info);
+    bool indicateBusyUnlocked(int cause, bool sent_signaling = false);
+    void reportFailToReceive(int fail_code);
+    bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context = "");
+  
+    bool isOK(void); 
+
+    bool isPhysicalFree() 
+    {
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false; 
+
+        bool physically_free = (status.AddInfo == kfcsEnabled);
+
+        if(status.CallStatus != kcsFree || !physically_free)
+        {
+            DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!"));
+            return false;
+        }
+
+        return true;
+    }
+
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        //Board::board(_target.device)->_timers.del(callFXO()->_idx_disconnect);
+        //callFXO()->_idx_disconnect.reset();
+        
+        call()->_flags.clear(Kflags::CALL_WAIT_SEIZE);
+        call()->_flags.clear(Kflags::EARLY_RINGBACK);
+
+        _transfer->clear();
+
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            call()->_flags.clear(Kflags::FAX_DETECTED);
+            break;
+        case CLN_SOFT:
+            break;
+        }
+
+        return KhompPvt::cleanup(type);
+    }
+
+    virtual void getSpecialVariables()
+    {
+        try
+        {
+            const char * str_fax = getFSChannelVar("KAdjustForFax");
+
+            callFXO()->_var_fax_adjust = (str_fax ? (!SAFE_strcasecmp(str_fax, "true") ? T_TRUE : T_FALSE) : T_UNKNOWN);
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "(FXO) %s") % err._msg.c_str());
+        }
+
+        KhompPvt::getSpecialVariables();
+    }
+
+    bool sendDtmf(std::string digit);
+
+    /* used by app FAX */
+    Fax * _fax;
+
+    Transfer<CallFXO> * _transfer;
+
+//    static void delayedDisconnect(Board::KhompPvt * pvt);
+
+};
+/******************************************************************************/
+/******************************************************************************/
+    BoardFXO(int id) : Board(id) {}
+
+    void initializeChannels(void)
+    {
+        LOG(MESSAGE, "(FXO) loading channels ...");
+
+        for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
+        {
+            K3LAPI::target tgt(Globals::k3lapi, K3LAPI::target::CHANNEL, _device_id, obj);
+            KhompPvt * pvt;
+
+            switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
+            {
+            case ksigAnalog:
+                pvt = new BoardFXO::KhompPvtFXO(tgt);
+                pvt->_call = new BoardFXO::KhompPvtFXO::CallFXO();
+                DBG(FUNC, "(FXO) FXO channel");
+                break;
+            default:
+                pvt = new Board::KhompPvt(tgt);
+                pvt->_call = new Board::KhompPvt::Call();
+                DBG(FUNC, FMT("(FXO) signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
+                break;
+            }
+
+            _channels.push_back(pvt);
+
+            pvt->cleanup();
+
+        }
+    }
+
+    /*
+    virtual bool eventHandler(const int obj, K3L_EVENT *e)
+    {
+        DBG(STRM, D("(FXO Board) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+        case :
+            break;
+        default:
+            ret = Board::eventHandler(obj, e);
+            break;
+        }
+
+        DBG(STRM, D("(FXO Board) r"));
+
+        return ret;
+    }
+    */
+   
+};
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+#endif /* _KHOMP_PVT_FXO_H_*/
+
diff --git a/src/mod/endpoints/mod_khomp/include/khomp_pvt_gsm.h b/src/mod/endpoints/mod_khomp/include/khomp_pvt_gsm.h
new file mode 100644 (file)
index 0000000..31ca1a0
--- /dev/null
@@ -0,0 +1,332 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _KHOMP_PVT_GSM_H_
+#define _KHOMP_PVT_GSM_H_
+
+#include "khomp_pvt.h"
+#include "applications.h"
+
+/******************************************************************************/
+/********************************* GSM Board **********************************/
+/******************************************************************************/
+struct BoardGSM: public Board
+{
+/******************************************************************************/
+/******************************** GSM Channel *********************************/
+struct KhompPvtGSM: public KhompPvt 
+{
+/********************************** GSM Call **********************************/
+    struct CallGSM : public Call
+    {
+        CallGSM() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "answer_info")
+            {
+                _call_info_report = true;
+            }
+            else if (name == "drop_on")
+            {
+                _call_info_report = true;
+
+                Strings::vector_type drop_item;
+                Strings::tokenize (value, drop_item, ".+");
+
+                for (Strings::vector_type::iterator i = drop_item.begin(); i != drop_item.end(); i++)
+                {
+
+                         if ((*i) == "message_box")        _call_info_drop |= CI_MESSAGE_BOX;
+                    else if ((*i) == "human_answer")       _call_info_drop |= CI_HUMAN_ANSWER;
+                    else if ((*i) == "answering_machine")  _call_info_drop |= CI_ANSWERING_MACHINE;
+                    else if ((*i) == "carrier_message")    _call_info_drop |= CI_CARRIER_MESSAGE;
+                    else if ((*i) == "unknown")            _call_info_drop |= CI_UNKNOWN;
+                    else
+                    {
+                        LOG(ERROR, FMT("unknown paramenter to 'calldrop' Dial option: '%s'.") % (*i));
+                        continue;
+                    }
+
+                    DBG(FUNC, FMT("droping call on '%s'.") % (*i));
+                }
+            }
+            else
+            {            
+                return Call::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            _call_info_report = false;
+            _call_info_drop = 0;
+            return Call::clear();
+        }
+
+        /* report what we got? */
+        bool _call_info_report;
+
+        /* what call info flags should make us drop the call? */
+        long int _call_info_drop;
+    };
+
+/******************************************************************************/
+    KhompPvtGSM(K3LAPI::target & target) : KhompPvt(target) 
+    {
+        _sms = new SMS(this);
+        command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
+    }
+
+    ~KhompPvtGSM() 
+    {
+        delete _sms;
+    }
+
+    CallGSM * callGSM()
+    {
+        return (CallGSM *)call();
+    }
+
+    int makeCall(std::string params = "");
+    bool doChannelAnswer(CommandRequest &);
+    bool doChannelHangup(CommandRequest &);
+
+    //bool onNewCall(K3L_EVENT *e);
+    bool onChannelRelease(K3L_EVENT *e);
+    bool onCallFail(K3L_EVENT *e);
+    bool onCallSuccess(K3L_EVENT *e);
+    bool onCallAnswerInfo(K3L_EVENT *e);
+    bool onDisconnect(K3L_EVENT *e);
+    //bool onDtmfDetected(K3L_EVENT *e);
+
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(GSM) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            /*
+            case EV_NEW_CALL:
+                onNewCall(e);
+                break;
+            */
+            case EV_CHANNEL_FREE:
+            case EV_CHANNEL_FAIL:
+                ret = onChannelRelease(e);
+                break;
+            case EV_CALL_SUCCESS:
+                ret = onCallSuccess(e);
+                break;
+            case EV_DISCONNECT:
+                ret = onDisconnect(e);
+                break;
+            case EV_CALL_FAIL:
+                ret = onCallFail(e);
+                break;
+            case EV_CALL_ANSWER_INFO:
+                ret = onCallAnswerInfo(e);
+                break;
+            case EV_RECV_FROM_MODEM:
+                break;
+            case EV_NEW_SMS:
+                ret = _sms->onNewSMS(e);
+                break;
+            case EV_SMS_INFO:
+                ret = _sms->onSMSInfo(e);
+                break;
+            case EV_SMS_DATA:
+                ret = _sms->onSMSData(e);
+                break;
+            case EV_SMS_SEND_RESULT:
+                ret = _sms->onSMSSendResult(e);
+                break;
+            default:
+                ret = KhompPvt::eventHandler(e);
+                break;
+        }        
+
+        DBG(STRM, D("(GSM) r"));
+
+        return ret;
+    }
+
+    bool application(ApplicationType type, switch_core_session_t * session, const char *data);    
+  
+    bool setupConnection();
+    void setAnswerInfo(int answer_info);
+    bool indicateBusyUnlocked(int cause, bool sent_signaling = false);
+    void reportFailToReceive(int fail_code);
+    int causeFromCallFail(int fail);
+    int callFailFromCause(int cause);
+    bool isOK(void); 
+
+    bool isPhysicalFree() 
+    {
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false; 
+
+        bool physically_free = (status.AddInfo == kgsmIdle);
+
+        if(status.CallStatus != kcsFree || !physically_free)
+        {
+            DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!"));
+            return false;
+        }
+
+        return true;
+    }
+
+    bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING)
+    {
+        return false;
+    }
+
+    bool selectSimCard(const char * sim_card)
+    {
+        return command(KHOMP_LOG, CM_SIM_CARD_SELECT, sim_card);
+    }
+
+    std::string getStatistics(Statistics::Type type)
+    {
+        switch(type)
+        {
+            case Statistics::DETAILED:
+            {
+                /* buffer our data to return at the end */
+                std::string strBuffer;
+
+                strBuffer.append(_pvt_statistics->getDetailed());
+                strBuffer.append(_sms->statistics()->getDetailed());
+                return strBuffer;
+            }
+            case Statistics::ROW:
+            {
+                return _pvt_statistics->getRow();
+            }
+            default:
+                return "";
+        }
+    }
+
+    void clearStatistics()
+    {
+        KhompPvt::clearStatistics();
+        _sms->statistics()->clear();
+    }
+
+    bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context = "");
+        
+    SMS * _sms;
+
+};
+/******************************************************************************/
+/******************************************************************************/
+    BoardGSM(int id) : Board(id) {}
+
+    void initializeChannels(void)
+    {
+        LOG(MESSAGE, "(GSM) loading channels ...");
+
+        for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
+        {
+            K3LAPI::target tgt(Globals::k3lapi, K3LAPI::target::CHANNEL, _device_id, obj);
+            KhompPvt * pvt;
+
+            switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
+            {
+            case ksigGSM:
+                pvt = new BoardGSM::KhompPvtGSM(tgt);
+                pvt->_call = new BoardGSM::KhompPvtGSM::CallGSM();
+                ((BoardGSM::KhompPvtGSM *)pvt)->_sms->start();
+                DBG(FUNC, "(GSM) GSM channel");
+                break;
+            default:
+                pvt = new Board::KhompPvt(tgt);
+                pvt->_call = new Board::KhompPvt::Call();
+                DBG(FUNC, FMT("(GSM) signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
+                break;
+            }
+
+            _channels.push_back(pvt);
+
+            pvt->cleanup();
+
+        }
+    }
+
+/*
+    virtual bool eventHandler(const int obj, K3L_EVENT *e)
+    {
+        DBG(STRM, D("(GSM Board) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+        case :
+            break;
+        default:
+            ret = Board::eventHandler(obj, e);
+            break;
+        }
+
+        DBG(STRM, D("(GSM Board) r"));
+
+        return ret;
+    }
+*/
+   
+};
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+#endif /* _KHOMP_PVT_GSM_H_*/
+
diff --git a/src/mod/endpoints/mod_khomp/include/khomp_pvt_kxe1.h b/src/mod/endpoints/mod_khomp/include/khomp_pvt_kxe1.h
new file mode 100644 (file)
index 0000000..c87dd23
--- /dev/null
@@ -0,0 +1,1122 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _KHOMP_PVT_E1_H_
+#define _KHOMP_PVT_E1_H_
+
+#include "khomp_pvt.h"
+
+#include "applications.h"
+
+/******************************************************************************/
+/********************************** E1 Board **********************************/
+/******************************************************************************/
+struct BoardE1: public Board
+{
+/******************************************************************************/
+/********************************* E1 Channel *********************************/
+struct KhompPvtE1: public KhompPvt 
+{
+/*********************************** E1 Call **********************************/
+    struct CallE1 : public Call
+    {
+        CallE1() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "answer_info")
+            {
+                _call_info_report = true;
+            }
+            else if (name == "drop_on")
+            {
+                _call_info_report = true;
+
+                Strings::vector_type drop_item;
+                Strings::tokenize (value, drop_item, ".+");
+
+                for (Strings::vector_type::iterator i = drop_item.begin(); i != drop_item.end(); i++)
+                {
+
+                         if ((*i) == "message_box")        _call_info_drop |= CI_MESSAGE_BOX;
+                    else if ((*i) == "human_answer")       _call_info_drop |= CI_HUMAN_ANSWER;
+                    else if ((*i) == "answering_machine")  _call_info_drop |= CI_ANSWERING_MACHINE;
+                    else if ((*i) == "carrier_message")    _call_info_drop |= CI_CARRIER_MESSAGE;
+                    else if ((*i) == "unknown")            _call_info_drop |= CI_UNKNOWN;
+                    else
+                    {
+                        LOG(ERROR, FMT("unknown paramenter to 'calldrop' Dial option: '%s'.") % (*i));
+                        continue;
+                    }
+
+                    DBG(FUNC, FMT("droping call on '%s'.") % (*i));
+                }
+            }
+            else
+            {            
+                return Call::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            _call_info_report = false;
+            _call_info_drop = 0;
+
+            _var_fax_adjust = T_UNKNOWN;
+            return Call::clear();
+        }
+
+        /* report what we got? */
+        bool _call_info_report;
+
+        /* what call info flags should make us drop the call? */
+        long int _call_info_drop;
+
+        TriState _var_fax_adjust;
+
+        ChanTimer::Index _idx_disconnect;
+    
+    };
+/******************************************************************************/
+    KhompPvtE1(K3LAPI::target & target) : KhompPvt(target)
+    {
+        _fax = new Fax(this);
+        command(KHOMP_LOG,CM_ENABLE_CALL_ANSWER_INFO); 
+    }
+
+    ~KhompPvtE1() 
+    {
+        delete _fax;
+    }
+
+    CallE1 * callE1()
+    {
+        return (CallE1 *)call();
+    }
+
+    int makeCall(std::string params = "");
+
+    bool onChannelRelease(K3L_EVENT *e);
+    bool onCallSuccess(K3L_EVENT *e);
+    bool onAudioStatus(K3L_EVENT *e);
+    bool onCallAnswerInfo(K3L_EVENT *e);
+    bool onDisconnect(K3L_EVENT *e);
+    
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(E1) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_CHANNEL_FREE:
+            case EV_CHANNEL_FAIL:
+                ret = onChannelRelease(e);
+                break;
+            case EV_CALL_ANSWER_INFO:
+                ret = onCallAnswerInfo(e);
+                break;
+            case EV_DISCONNECT:
+                ret = onDisconnect(e);
+                break;                            
+            case EV_AUDIO_STATUS:
+                ret = onAudioStatus(e);
+                break;
+            case EV_FAX_CHANNEL_FREE:
+                ret = _fax->onFaxChannelRelease(e);
+                break;
+            case EV_FAX_FILE_SENT:
+            case EV_FAX_FILE_FAIL:
+            case EV_FAX_TX_TIMEOUT:
+            case EV_FAX_PAGE_CONFIRMATION:
+            case EV_FAX_REMOTE_INFO:
+                break;
+            default:
+                ret = KhompPvt::eventHandler(e);
+                break;
+        }        
+
+        DBG(STRM, D("(E1) r"));
+
+        return ret;
+    }
+    
+    bool application(ApplicationType type, switch_core_session_t * session, const char *data);
+    
+    bool setupConnection();
+    bool indicateBusyUnlocked(int cause, bool sent_signaling = false);
+    void setAnswerInfo(int answer_info);
+    bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context = "");
+    bool isOK(void); 
+
+    bool isPhysicalFree() 
+    {
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false; 
+
+        bool physically_free = (status.AddInfo == kecsFree);
+
+        if(status.CallStatus != kcsFree || !physically_free)
+        {
+            DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!"));
+            return false;
+        }
+
+        return true;
+    }
+
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        try
+        {
+            Board::board(_target.device)->_timers.del(callE1()->_idx_disconnect);
+        }
+        catch (K3LAPI::invalid_device & err)
+        {
+            LOG(ERROR, PVT_FMT(target(), "Unable to get device: %d!") % err.device);
+        }
+
+        callE1()->_idx_disconnect.reset();
+
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            call()->_flags.clear(Kflags::FAX_DETECTED);
+            break;
+        case CLN_SOFT:
+            break;
+        }
+
+        return KhompPvt::cleanup(type);
+    }
+
+    virtual void getSpecialVariables()
+    {
+        try
+        {
+            const char * str_fax = getFSChannelVar("KAdjustForFax");
+
+            callE1()->_var_fax_adjust = (str_fax ? (!SAFE_strcasecmp(str_fax, "true") ? T_TRUE : T_FALSE) : T_UNKNOWN);
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "(E1) %s") % err._msg.c_str());
+        }
+
+        KhompPvt::getSpecialVariables();
+    }
+        
+    /* used by app FAX */
+    Fax * _fax;
+
+    static void delayedDisconnect(Board::KhompPvt * pvt);
+};
+/******************************************************************************/
+/********************************** ISDN Channel ******************************/
+struct KhompPvtISDN: public KhompPvtE1 
+{
+/********************************** ISDN Call *********************************/
+    struct CallISDN : public CallE1
+    {
+    
+        CallISDN() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "uui")
+            {
+                Strings::vector_type values;
+                Strings::tokenize(value, values, "#", 2);
+
+                try
+                {
+                    std::string uui_proto_s = values[0];
+                    std::string uui_data_s = values[1];
+
+                    _uui_descriptor = Strings::toulong(uui_proto_s);
+                    _uui_information.append(uui_data_s);
+
+                    DBG(FUNC, FMT("uui adjusted (%s, '%s')!") % uui_proto_s.c_str() % uui_data_s.c_str());
+                }
+                catch (...)
+                {
+                    LOG(ERROR, FMT("invalid uui protocol descriptor: '%s' is not a number.") % value.c_str());
+                }
+            }
+            else if (name == "usr_xfer")
+            {
+                _user_xfer_digits = value;
+            }
+            else
+            {            
+                return CallE1::process(name, value);
+            }
+
+            return true;
+        }
+    
+        bool clear()
+        {
+            _uui_descriptor = -1;
+            _uui_information.clear();
+            _isdn_cause = -1;
+
+            _user_xfer_digits = Opt::_user_xfer;
+            _user_xfer_buffer.clear();
+            _digits_buffer.clear();
+            _qsig_number.clear();
+    
+            return CallE1::clear();
+        }
+        
+        /* used for isdn EV_USER_INFORMATION */
+        long int     _uui_descriptor;
+        std::string  _uui_information;
+        long int     _isdn_cause;
+
+        /* what should we dial to trigger an user-signaled transfer? */
+        /* used for xfer on user signaling */
+        std::string _user_xfer_digits;
+        std::string _user_xfer_buffer;
+        std::string _digits_buffer;
+        std::string _qsig_number;
+
+    };
+/******************************************************************************/
+    KhompPvtISDN(K3LAPI::target & target) : KhompPvtE1(target) 
+    {
+        _transfer = new Transfer<CallISDN, false>(this);
+    }
+
+    ~KhompPvtISDN() 
+    {
+        delete _transfer;
+    }
+
+    CallISDN * callISDN()
+    {
+        return (CallISDN *)call();
+    }
+    
+    int makeCall(std::string params = "");
+    bool doChannelAnswer(CommandRequest &); 
+
+    bool onSyncUserInformation(K3L_EVENT *e);
+    bool onIsdnProgressIndicator(K3L_EVENT *e);
+    bool onNewCall(K3L_EVENT *e);
+    bool onCallSuccess(K3L_EVENT *e);
+    bool onCallFail(K3L_EVENT *e);
+
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(ISDN) c"));
+
+        bool ret = true;
+        
+        switch(e->Code)
+        {
+            case EV_USER_INFORMATION:
+                ret = onSyncUserInformation(e);
+                break;
+            case EV_ISDN_PROGRESS_INDICATOR:
+                ret = onIsdnProgressIndicator(e);
+                break;
+            case EV_NEW_CALL:
+                ret = onNewCall(e);
+                break;
+            case EV_CALL_SUCCESS:
+                ret = onCallSuccess(e);
+                break;
+            case EV_CALL_FAIL:
+                ret = onCallFail(e);
+                break;
+            case EV_SS_TRANSFER_FAIL:
+                break;
+            default:
+                ret = KhompPvtE1::eventHandler(e);
+                break;
+        }        
+
+        DBG(STRM, D("(ISDN) r"));
+
+        return ret;
+    }
+    
+    bool application(ApplicationType type, switch_core_session_t * session, const char *data);
+
+    int causeFromCallFail(int fail);
+    int callFailFromCause(int cause);
+    void reportFailToReceive(int fail_code);
+    RingbackDefs::RingbackStType sendRingBackStatus(int rb_value = RingbackDefs::RB_SEND_DEFAULT); 
+    bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING);
+    bool sendDtmf(std::string digit);
+
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        _transfer->clear();
+        
+        /*
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            break;
+        case CLN_SOFT:
+            break;
+        }
+        */
+
+        return KhompPvtE1::cleanup(type);
+    }
+
+    virtual void setSpecialVariables()
+    {
+        try
+        {
+            /* rdsi user info */
+            if (callISDN()->_uui_descriptor != -1)
+            {
+                DBG(FUNC,"Setting ISDN descriptor");
+
+                std::string descriptor = STG(FMT("%d") % callISDN()->_uui_descriptor);
+
+                setFSChannelVar("KUserInfoDescriptor", descriptor.c_str());
+                setFSChannelVar("KUserInfoData", callISDN()->_uui_information.c_str());
+
+                callISDN()->_uui_descriptor = -1;
+                callISDN()->_uui_information.clear();
+            }
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "(ISDN) %s") % err._msg.c_str());
+        }
+
+        KhompPvtE1::setSpecialVariables();
+    }
+
+    Transfer<CallISDN, false> * _transfer;
+
+};
+/******************************************************************************/
+/********************************* R2 Channel *********************************/
+struct KhompPvtR2: public KhompPvtE1
+{
+/********************************* R2 Call ************************************/
+    struct CallR2 : public CallE1
+    {
+    
+        CallR2() {}
+
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "category")
+            {
+                try
+                {
+                    unsigned long int category = Strings::toulong (value);
+                    DBG(FUNC, FMT("r2 category adjusted (%s)!") % value.c_str());
+                    _r2_category = category;
+                }
+                catch (...)
+                {
+                   LOG(ERROR, FMT("invalid r2 category: '%s' is not a number.") % value.c_str());
+                }
+
+            }
+            else
+            {
+                return CallE1::process(name, value);
+            }
+            return true;
+        }
+        
+        bool clear()
+        {
+            _r2_category  = -1; 
+            _r2_condition = -1;
+
+            return CallE1::clear();
+        }
+
+        long int _r2_category;
+        long int _r2_condition;
+
+        ChanTimer::Index _idx_number_dial;
+        std::string _incoming_exten;
+    };
+/******************************************************************************/
+    KhompPvtR2(K3LAPI::target & target) : KhompPvtE1(target) 
+    {
+        K3L_E1600A_FW_CONFIG dspAcfg;
+
+        if (k3lGetDeviceConfig(_target.device, ksoFirmware + kfiE1600A, &dspAcfg, sizeof(dspAcfg)) != ksSuccess)
+        {
+            DBG(FUNC, PVT_FMT(target, "unable to get signaling locality for board: assuming brazilian signaling"));
+            _r2_country = Verbose::R2_COUNTRY_BRA;
+           
+            return;
+        }
+        Regex::Expression e(".+\\((Arg|Bra|Chi|Mex|Ury|Ven)\\).+", Regex::E_EXTENDED);
+        std::string fwname(dspAcfg.FwVersion);
+
+        Regex::Match what(fwname, e);
+
+        if (!what.matched() || !what.matched(1))
+        {
+            DBG(FUNC, PVT_FMT(target, "invalid firmware string, unable to find country code: assuming brazilian signaling.\n"));
+            
+            _r2_country = Verbose::R2_COUNTRY_BRA;
+            return;
+        }
+
+        std::string country = what.submatch(1);
+    
+        /**/ if (country == "Arg")
+            _r2_country = Verbose::R2_COUNTRY_ARG;
+        else if (country == "Bra")
+            _r2_country = Verbose::R2_COUNTRY_BRA;
+        else if (country == "Chi")
+            _r2_country = Verbose::R2_COUNTRY_CHI;
+        else if (country == "Mex")
+            _r2_country = Verbose::R2_COUNTRY_MEX;
+        else if (country == "Ury")
+            _r2_country = Verbose::R2_COUNTRY_URY;
+        else if (country == "Ven")
+            _r2_country = Verbose::R2_COUNTRY_VEN;
+        else
+        {
+            DBG(FUNC, PVT_FMT(target, "invalid firmware string (%s), assuming brazilian signaling.") % country.c_str());
+
+            _r2_country = Verbose::R2_COUNTRY_BRA;
+            return;
+        }
+    
+        DBG(FUNC, PVT_FMT(target, "adjusting country signaling to code '%s'...")
+            % country.c_str());
+
+    }
+
+    ~KhompPvtR2() {}
+    
+    CallR2 * callR2()
+    {
+        return (CallR2 *)call();
+    }
+    
+    int makeCall(std::string params = "");
+    bool doChannelAnswer(CommandRequest &); 
+    bool doChannelHangup(CommandRequest &);
+
+    bool onNewCall(K3L_EVENT *e);
+    bool onCallSuccess(K3L_EVENT *e);
+    bool onCallFail(K3L_EVENT *e);
+    bool onNumberDetected(K3L_EVENT *e);
+    
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(R2) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_NEW_CALL:
+                ret = onNewCall(e);
+                break;
+            case EV_CALL_SUCCESS:
+                ret = onCallSuccess(e);
+                break;
+            case EV_CALL_FAIL:
+                ret = onCallFail(e);
+                break;
+            case EV_DIALED_DIGIT:
+                ret = onNumberDetected(e);
+                break;
+            default:
+                ret = KhompPvtE1::eventHandler(e);
+                break;
+        }        
+
+        DBG(STRM, D("(R2) r"));
+
+        return ret;
+
+    }
+    
+    int causeFromCallFail(int fail);
+    int callFailFromCause(int cause);
+    void reportFailToReceive(int fail_code);
+    RingbackDefs::RingbackStType sendRingBackStatus(int rb_value = RingbackDefs::RB_SEND_DEFAULT); 
+    bool sendPreAudio(int rb_value = RingbackDefs::RB_SEND_NOTHING);
+    bool indicateRinging();
+
+    virtual void setSpecialVariables()
+    {
+        try
+        {
+            /* r2 caller category */
+            if (callR2()->_r2_category != -1)
+            {
+                setFSChannelVar("KR2GotCategory",Verbose::signGroupII((KSignGroupII)callR2()->_r2_category).c_str());
+            }
+
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "(R2) %s") % err._msg.c_str());
+        }
+
+        KhompPvtE1::setSpecialVariables();
+    }
+
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        call()->_flags.clear(Kflags::NEEDS_RINGBACK_CMD);
+        call()->_flags.clear(Kflags::NUMBER_DIAL_ONGOING);
+        call()->_flags.clear(Kflags::NUMBER_DIAL_FINISHD);
+
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            break;
+        case CLN_SOFT:
+            break;
+        }
+
+        return KhompPvtE1::cleanup(type);
+    }
+
+    static void numberDialTimer(Board::KhompPvt * pvt);
+
+public:
+    Verbose::R2CountryType _r2_country;
+
+};
+/******************************************************************************/
+/********************************* FLASH Channel ******************************/
+/* ksigLineSide ksigCAS_EL7 ksigE1LC */
+struct KhompPvtFlash: public KhompPvtR2 
+{
+/********************************* R2 Call ************************************/
+    struct CallFlash : public CallR2
+    {
+    
+        CallFlash() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "usr_xfer")
+            {
+                _user_xfer_digits = value;
+            }
+            else
+            {
+                return CallR2::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            _user_xfer_digits = Opt::_user_xfer;
+            _user_xfer_buffer.clear();
+            _digits_buffer.clear();
+
+            return CallR2::clear();
+        }
+
+        /* used for xfer on user signaling */
+        std::string _user_xfer_digits;
+        std::string _user_xfer_buffer;
+        std::string _digits_buffer;
+
+    };
+/******************************************************************************/
+    KhompPvtFlash(K3LAPI::target & target) : KhompPvtR2(target) 
+    {
+        _transfer = new Transfer<CallFlash>(this);
+    }
+    
+    ~KhompPvtFlash() 
+    {
+        delete _transfer;
+    }
+    
+    CallFlash * callFlash()
+    {
+        return (CallFlash *)call();
+    }
+
+    bool application(ApplicationType type, switch_core_session_t * session, const char *data);
+
+    bool sendDtmf(std::string digit);
+
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        _transfer->clear();
+
+        /*
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            break;
+        case CLN_SOFT:
+            break;
+        }
+        */
+
+        return KhompPvtR2::cleanup(type);
+    }
+
+    Transfer<CallFlash> * _transfer;
+};
+/******************************************************************************/
+/********************************* FSX Channel ********************************/
+struct KhompPvtFXS: public KhompPvt 
+{
+/********************************** FXS Call **********************************/
+    struct CallFXS : public Call
+    {
+        CallFXS() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            if (name == "ring")
+            {
+                Strings::vector_type ring_item;
+                Strings::tokenize (value, ring_item, ".");
+
+                if (ring_item.size() != 2)
+                {
+                    LOG(ERROR, FMT("invalid values on ring string: two numbers, dot separated, are needed."));
+                    return false;
+                }
+
+                try
+                {
+                    unsigned long int time_on = Strings::toulong (ring_item[0]);
+                    unsigned long int time_off = Strings::toulong (ring_item[1]);
+
+                    _ring_on = time_on;
+                    _ring_off = time_off;
+
+                    DBG(FUNC, D("ring values adjusted (%i,%i).") % time_on % time_off);
+                }
+                catch (...)
+                {
+                    LOG(ERROR, FMT("invalid number on ring string."));
+                }
+            }
+            else if (name == "ring_ext")
+            {
+                if (_ring_on == -1) // so ring was not set.
+                {
+                    LOG(ERROR, FMT("ring_ext only make sense if ring values are set."));
+                    return false;
+                }
+
+                Strings::vector_type ring_item;
+                Strings::tokenize (value, ring_item, ".");
+
+                if (ring_item.size() != 2)
+                {
+                    LOG(ERROR, FMT("invalid values on ring_ext string: two numbers, dot separated, are needed."));
+                    return false;
+                }
+
+                try
+                {
+                    unsigned long int time_on = Strings::toulong (ring_item[0]);
+                    unsigned long int time_off = Strings::toulong (ring_item[1]);
+
+                    _ring_on_ext = time_on;
+                    _ring_off_ext = time_off;
+
+                    DBG(FUNC, D("ring_ext values adjusted (%i,%i).") % time_on % time_off);
+                }
+                catch (...)
+                {
+                    LOG(ERROR, FMT("invalid number on ring_ext string."));
+                }
+            }
+            else if (name == "ring_cadence")
+            {
+                Opt::CadencesMapType::iterator i = Opt::_cadences.find(value);
+
+                if (i != Opt::_cadences.end())
+                {
+                    CadenceType cadence = (*i).second;
+
+                    _ring_on      = cadence.ring;
+                    _ring_off     = cadence.ring_s;
+                    _ring_on_ext  = cadence.ring_ext;
+                    _ring_off_ext = cadence.ring_ext_s;
+
+                    DBG(FUNC, D("cadence adjusted (%i,%i,%i,%i).") 
+                            % cadence.ring
+                            % cadence.ring_s 
+                            % cadence.ring_ext 
+                            % cadence.ring_ext_s);
+                }
+                else
+                {
+                    LOG(ERROR, FMT("unable to find cadence '%s'!") % value);
+                }
+            }
+            else
+            {            
+                return Call::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            _ring_on      = -1;
+            _ring_off     = -1;
+            _ring_on_ext  = -1;
+            _ring_off_ext = -1;
+
+            _incoming_exten.clear();
+            _flash_transfer.clear();
+
+            _uuid_other_session.clear();
+            return Call::clear();
+        }
+
+        long int _ring_on;
+        long int _ring_off;
+        long int _ring_on_ext;
+        long int _ring_off_ext;
+
+        ChanTimer::Index _idx_dial;
+
+        std::string _incoming_exten;
+        
+        ChanTimer::Index _idx_transfer;
+
+        std::string _flash_transfer;
+        std::string _uuid_other_session;
+        
+
+    };
+/******************************************************************************/
+    KhompPvtFXS(K3LAPI::target & target) : KhompPvt(target)
+    {
+       //command(KHOMP_LOG,CM_ENABLE_CALL_ANSWER_INFO);
+       /* sequence numbers on FXS */
+       static Opt::OrigToNseqMapType fxs_nseq = generateNseqMap();
+
+       load(fxs_nseq);
+    }
+
+    ~KhompPvtFXS() {}
+
+    CallFXS * callFXS()
+    {
+        return (CallFXS *)call();
+    }
+
+    int makeCall(std::string params = "");
+    bool doChannelAnswer(CommandRequest &);
+    bool doChannelHangup(CommandRequest &);
+   
+    bool onChannelRelease(K3L_EVENT *e);
+    bool onSeizureStart(K3L_EVENT *);
+    bool onCallSuccess(K3L_EVENT *);
+    bool onDtmfDetected(K3L_EVENT *);
+    //bool onDtmfSendFinish(K3L_EVENT *);
+    bool onFlashDetected(K3L_EVENT *);
+    
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(FXS) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_CHANNEL_FREE:
+            case EV_CHANNEL_FAIL:
+                ret = onChannelRelease(e);
+                break;
+            case EV_SEIZURE_START:
+                ret = onSeizureStart(e);                
+                break;
+            case EV_CALL_SUCCESS:
+                ret = onCallSuccess(e);
+                break;
+            case EV_DTMF_DETECTED:
+            case EV_PULSE_DETECTED:
+                ret = onDtmfDetected(e);
+                break;
+            /*
+            case EV_DTMF_SEND_FINISH:
+                ret = onDtmfSendFinish(e);
+                break;
+            */
+            case EV_FLASH:
+                ret = onFlashDetected(e);
+                break;
+            default:
+                ret = KhompPvt::eventHandler(e);
+                break;
+        }        
+
+        DBG(STRM, D("(FXS) r"));
+
+        return ret;
+    }
+
+    bool setupConnection();
+    void load(Opt::OrigToNseqMapType & fxs_nseq);
+    void loadOptions();
+    bool parseBranchOptions(std::string options_str);
+    bool alloc();
+    bool indicateBusyUnlocked(int cause, bool sent_signaling = false);
+    void reportFailToReceive(int fail_code);
+    bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context = "");
+    bool isOK(void);
+
+    bool startTransfer();
+    bool stopTransfer();
+    bool transfer(std::string & context, bool blind = false);
+
+    bool hasNumberDial() { return false; }
+    
+    bool isPhysicalFree() 
+    {
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false; 
+
+        bool physically_free = (status.AddInfo == kfxsOnHook);
+
+        if(status.CallStatus != kcsFree || !physically_free)
+        {
+            DBG(FUNC, PVT_FMT(_target, "call status not free, or not physically free!"));
+            return false;
+        }
+
+        return true;
+    }
+    
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        callFXS()->_flags.clear(Kflags::FXS_DIAL_ONGOING);
+        callFXS()->_flags.clear(Kflags::FXS_DIAL_FINISHD);
+        callFXS()->_flags.clear(Kflags::FXS_FLASH_TRANSFER);
+
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            callFXS()->_flags.clear(Kflags::FXS_OFFHOOK);        
+            break;
+        case CLN_SOFT:
+            break;
+        }
+
+        return KhompPvt::cleanup(type);
+    }
+
+    
+    /* number based on fxs-global-orig */
+    std::string _fxs_fisical_addr; 
+    /* the branch number, possibly the new calleridnum */
+    std::string _fxs_orig_addr; 
+    std::string _calleridname;
+    int         _amaflags;
+    std::string _callgroup;
+    std::string _pickupgroup;
+    std::string _context;
+    int         _input_volume;
+    int         _output_volume;
+    std::string _mohclass;
+    std::string _language;
+    std::string _accountcode;
+    std::string _mailbox;
+
+    static Opt::OrigToNseqMapType generateNseqMap();
+    static void dialTimer(KhompPvt * pvt);
+    static void transferTimer(KhompPvt * pvt);
+
+    static std::string padOrig(std::string orig_base, unsigned int padding)
+    {
+        unsigned int orig_size = orig_base.size();
+        unsigned int orig_numb = 0;
+
+        try
+        {
+            orig_numb = Strings::toulong(orig_base);
+        }
+        catch(Strings::invalid_value & e)
+        {
+            LOG(ERROR, D("invalid numeric value: %s") % e.value());
+        }
+
+        return STG(FMT(STG(FMT("%%0%dd") % orig_size)) % (orig_numb + padding));
+    }
+
+    /*
+    virtual void getSpecialVariables()
+    {
+        try
+        {
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "(FXS) %s") % err._msg.c_str());
+        }
+
+        KhompPvt::getSpecialVariables();
+    }
+    */
+
+};
+/******************************************************************************/
+/******************************************************************************/
+    BoardE1(int id) : Board(id) {}
+
+    void initializeChannels(void)
+    {
+        LOG(MESSAGE, "(E1) loading channels ...");
+
+        for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
+        {
+            K3LAPI::target tgt(Globals::k3lapi, K3LAPI::target::CHANNEL, _device_id, obj);
+            KhompPvt * pvt;
+
+            switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
+            {
+            CASE_RDSI_SIG:
+                pvt = new BoardE1::KhompPvtISDN(tgt);
+                pvt->_call = new BoardE1::KhompPvtISDN::CallISDN();
+                DBG(FUNC, "(E1) ISDN channel");
+                break;
+            CASE_R2_SIG:
+                pvt = new BoardE1::KhompPvtR2(tgt);
+                pvt->_call = new BoardE1::KhompPvtR2::CallR2();
+                pvt->command(KHOMP_LOG, CM_DISCONNECT);
+                DBG(FUNC, "(E1) R2 channel");
+                break;
+            CASE_FLASH_GRP:
+                pvt = new BoardE1::KhompPvtFlash(tgt);
+                pvt->_call = new BoardE1::KhompPvtFlash::CallFlash();
+                pvt->command(KHOMP_LOG, CM_DISCONNECT);
+                DBG(FUNC, "(E1) \"Flash\" channel");
+                break;
+            case ksigAnalogTerminal:
+                pvt = new BoardE1::KhompPvtFXS(tgt);
+                pvt->_call = new BoardE1::KhompPvtFXS::CallFXS();
+                DBG(FUNC, "(E1) FXS channel");
+                break;
+            default:
+                pvt = new Board::KhompPvt(tgt);
+                pvt->_call = new Board::KhompPvt::Call();
+                DBG(FUNC, FMT("(E1) signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
+                break;
+            }
+
+            _channels.push_back(pvt);
+
+            pvt->cleanup();
+
+        }
+    }
+
+    bool onLinkStatus(K3L_EVENT *e);
+
+    virtual bool eventHandler(const int obj, K3L_EVENT *e)
+    {
+        DBG(STRM, D("(E1 Board) c"));
+
+        int ret = true;
+
+        switch(e->Code)
+        {
+        case EV_LINK_STATUS:
+        case EV_PHYSICAL_LINK_DOWN:
+        case EV_PHYSICAL_LINK_UP:
+
+            if (K::Logger::Logg.classe(C_LINK_STT).enabled() || K::Logger::Logg.classe(C_EVENT).enabled())
+            {    
+                std::string msg = Globals::verbose.event (obj, e) + "."; 
+                LOG(LINK_STT, msg);
+            }            
+
+            ret = onLinkStatus(e);
+            break;
+        default:
+            ret = Board::eventHandler(obj, e);
+            break;
+        }
+
+        DBG(STRM, D("(E1 Board) r"));
+
+        return ret;
+    }
+   
+};
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+#endif /* _KHOMP_PVT_H_*/
+
diff --git a/src/mod/endpoints/mod_khomp/include/khomp_pvt_passive.h b/src/mod/endpoints/mod_khomp/include/khomp_pvt_passive.h
new file mode 100644 (file)
index 0000000..55b0659
--- /dev/null
@@ -0,0 +1,304 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _KHOMP_PVT_PASSIVE_H_
+#define _KHOMP_PVT_PASSIVE_H_
+
+#include "khomp_pvt.h"
+#include "applications.h"
+
+/******************************************************************************/
+/******************************** Passive Board *******************************/
+/******************************************************************************/
+struct BoardPassive: public Board
+{
+/******************************************************************************/
+/******************************** Passive Channel *****************************/
+struct KhompPvtPassive: public KhompPvt 
+{
+/******************************** Passive Call ********************************/
+/*
+    struct CallPassive : public Call
+    {
+        CallPassive() {}
+
+        bool process(std::string name, std::string value = "")
+        {
+            }
+            else
+            {            
+                return Call::process(name, value);
+            }
+
+            return true;
+        }
+        
+        bool clear()
+        {
+            return Call::clear();
+        }
+
+    };
+*/
+/******************************************************************************/
+    KhompPvtPassive(K3LAPI::target & target) : KhompPvt(target) 
+    {
+    }
+
+    ~KhompPvtPassive() 
+    {
+    }
+/*    
+    CallPassive * callPassive()
+    {
+        return (CallPassive *)call();
+    }
+*/
+    
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(Passive) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_CHANNEL_FREE:
+            case EV_CHANNEL_FAIL:
+                ret = onChannelRelease(e);
+                break;
+/*
+            case EV_CALL_SUCCESS:
+            case EV_CALL_FAIL:
+            case EV_PULSE_DETECTED:
+*/
+            case EV_DISCONNECT:
+            case EV_DTMF_DETECTED:
+            case EV_AUDIO_STATUS:
+                break;
+            default:
+                ret = true;
+                break;
+        }
+
+        DBG(STRM, D("(Passive) r"));
+
+        return ret;
+    }
+    
+    bool validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context = "");
+
+/*
+    virtual bool cleanup(CleanupType type = CLN_HARD)
+    {
+        switch (type)
+        {
+        case CLN_HARD:
+        case CLN_FAIL:
+            break;
+        case CLN_SOFT:
+            break;
+        }
+
+        return KhompPvt::cleanup(type);
+    }
+*/
+
+};
+/******************************************************************************/
+/********************************** HI Channel ********************************/
+struct KhompPvtHI: public KhompPvtPassive
+{
+    KhompPvtHI(K3LAPI::target & target) : KhompPvtPassive(target) 
+    {
+    }
+
+    ~KhompPvtHI() 
+    {
+    }
+    
+    bool onSeizureStart(K3L_EVENT *e);
+
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(HI) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_SEIZURE_START:
+                ret = onSeizureStart(e);
+                break;
+            case EV_RING_DETECTED:
+            case EV_POLARITY_REVERSAL:
+                break;
+            default:
+                ret = KhompPvtPassive::eventHandler(e);
+                break;
+        }
+
+        DBG(STRM, D("(HI) r"));
+
+        return ret;
+    }
+
+};
+/******************************************************************************/
+/********************************* KPR Channel ********************************/
+struct KhompPvtKPR: public KhompPvtPassive
+{
+    KhompPvtKPR(K3LAPI::target & target) : KhompPvtPassive(target) 
+    {
+    }
+
+    ~KhompPvtKPR() 
+    {
+    }
+    
+    bool onNewCall(K3L_EVENT *e);
+/*
+    bool onConnect(K3L_EVENT *e);
+*/
+
+    virtual bool eventHandler(K3L_EVENT *e)
+    {
+        DBG(STRM, D("(KPR) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+            case EV_NEW_CALL:
+                ret = onNewCall(e);
+                break;
+            case EV_CONNECT:
+                break;
+            case EV_SEIZURE_START:
+            case EV_CAS_MFC_RECV:
+            case EV_CAS_LINE_STT_CHANGED:
+            case EV_LINK_STATUS:
+                break;
+            default:
+                ret = KhompPvtPassive::eventHandler(e);
+                break;
+        }
+
+        DBG(STRM, D("(KPR) r"));
+
+        return ret;
+    }
+
+    bool obtainBoth();
+
+};
+/******************************************************************************/
+/******************************************************************************/
+    BoardPassive(int id) : Board(id) {}
+
+    void initializeChannels(void)
+    {
+        LOG(MESSAGE, "(Passive) loading channels ...");
+
+        for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
+        {
+            K3LAPI::target tgt(Globals::k3lapi, K3LAPI::target::CHANNEL, _device_id, obj);
+            KhompPvt * pvt;
+
+            switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
+            {
+            case ksigAnalog:
+                pvt = new BoardPassive::KhompPvtHI(tgt);
+                pvt->_call = new BoardPassive::KhompPvtHI::Call();
+                DBG(FUNC, "(Passive) HI channel");
+                break;
+            CASE_RDSI_SIG:
+            CASE_R2_SIG:
+            CASE_FLASH_GRP:
+            case ksigAnalogTerminal:
+                pvt = new BoardPassive::KhompPvtKPR(tgt);
+                pvt->_call = new BoardPassive::KhompPvtKPR::Call();
+                DBG(FUNC, "(Passive) KPR channel");
+                break;
+            default:
+                pvt = new Board::KhompPvt(tgt);
+                pvt->_call = new Board::KhompPvt::Call();
+                DBG(FUNC, FMT("(Passive) signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
+                break;
+            }
+
+            _channels.push_back(pvt);
+
+            pvt->cleanup();
+
+        }
+    }
+
+    /*
+    virtual bool eventHandler(const int obj, K3L_EVENT *e)
+    {
+        DBG(STRM, D("(Passive Board) c"));
+
+        bool ret = true;
+
+        switch(e->Code)
+        {
+        case :
+            break;
+        default:
+            ret = Board::eventHandler(obj, e);
+            break;
+        }
+
+        DBG(STRM, D("(Passive Board) r"));
+
+        return ret;
+    }
+    */
+   
+};
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+#endif /* _KHOMP_PVT_PASSIVE_H_*/
+
diff --git a/src/mod/endpoints/mod_khomp/include/lock.h b/src/mod/endpoints/mod_khomp/include/lock.h
new file mode 100644 (file)
index 0000000..621b724
--- /dev/null
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef CHAN_LOCK_H
+#define CHAN_LOCK_H
+
+#include <scoped_lock.hpp>
+#include "khomp_pvt.h"
+
+
+struct ScopedLockFailed
+{
+    typedef enum { NULL_PVT, NULL_SOFT_CHAN, FAILED, ALLOC_FAILED } FailType;
+
+    ScopedLockFailed(FailType fail, std::string msg)
+    : _fail(fail), _msg(msg) {};
+
+    FailType    _fail;
+    std::string _msg;
+};
+
+
+struct ScopedPvtLock: public ScopedLockBasic
+{
+    typedef Board::KhompPvt KhompPvt;
+
+    ScopedPvtLock(KhompPvt * pvt);
+    ~ScopedPvtLock();
+
+    void unlock();
+
+ protected:
+    KhompPvt * _pvt;
+};
+
+
+struct ScopedAllocLock : public ScopedLockBasic
+{
+    ScopedAllocLock();
+    ~ScopedAllocLock();
+
+    void unlock();
+
+};
+
+#endif /* CHAN_LOCK_H */
diff --git a/src/mod/endpoints/mod_khomp/include/logger.h b/src/mod/endpoints/mod_khomp/include/logger.h
new file mode 100644 (file)
index 0000000..554a48d
--- /dev/null
@@ -0,0 +1,141 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _Logger_H_
+#define _Logger_H_
+
+#include <switch.h>
+#include <string>
+#include <simple_lock.hpp>
+#include <logger.hpp>
+#include <configurator/configfile.hpp>
+#include <klog-config.hpp>
+#include "defs.h"
+#include "format.hpp"
+
+namespace K
+{
+    struct LogConfig
+    {
+        static bool set(Logfile &, const char *, const char *, bool);
+        static bool commit(Logfile &);
+    };
+
+    struct SwitchConsoleLog {}; 
+
+    struct SwitchPrinter: public Logger::DefaultPrinter
+    {
+        typedef Logger::DefaultPrinter Super;
+        typedef Tagged::Union < std::ostream *, Tagged::Union < int, Tagged::Union < SwitchConsoleLog > > > BaseType;
+
+        SwitchPrinter(std::string & msg): Super(msg) {}; 
+
+        using Super::operator();
+
+        bool operator()(const SwitchConsoleLog & ignored)
+        {   
+            switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN,SWITCH_LOG_CONSOLE,"%s",_msg.c_str());
+            return true;
+        };  
+    };
+
+    /* Log manager declaration. */
+    typedef Logger::Manager <class_type, output_type, SwitchPrinter, SimpleLock>  LogManager;
+
+    /* Forward declaration */
+    struct LogInternalManager; 
+
+    struct Logger
+    {
+        /* Logger instance. */
+        static LogManager Logg;
+
+        /* Util Logger instance. */
+        static LogInternalManager Logg2;
+
+        static bool start();
+        static void stop();
+        static bool rotate();
+        static void processLogConsole(switch_stream_handle_t *s, const std::string options, bool invert, bool unique);
+        static void processLogDisk(switch_stream_handle_t *s, const std::string options, bool invert, bool unique);
+
+    private:
+        static std::string     base_path;
+        static std::ofstream   generic_file;
+    };
+
+    /* Internal logging facility declaration */
+    struct LogInternalManager
+    {
+        bool operator()(class_type classe, switch_stream_handle_t *stream, const char *args)
+        {
+            switch (classe)
+            {
+                case C_CLI:
+                    stream->write_function(stream,"%s\n",args);
+                    return true;
+                default:
+                    return K::Logger::Logg(classe, args);
+            }
+        }
+        
+        bool operator()(class_type classe, switch_stream_handle_t *stream, Format &fmt)
+        {
+            return K::Logger::Logg2(classe,stream,(char*) STR(fmt));
+        }
+
+        bool operator()(class_type classe, switch_stream_handle_t *stream, const char *fmt, const char *args)
+        {
+            switch (classe)
+            {
+                case C_CLI:
+                    stream->write_function(stream,fmt,args); 
+                    return true;
+                default:
+                    return K::Logger::Logg(classe, FMT(fmt) % args);
+            }
+        }
+    };
+};
+
+#endif /* _Logger_H_ */
diff --git a/src/mod/endpoints/mod_khomp/include/opt.h b/src/mod/endpoints/mod_khomp/include/opt.h
new file mode 100644 (file)
index 0000000..0f93215
--- /dev/null
@@ -0,0 +1,250 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _OPT_H_
+#define _OPT_H_
+
+#include <string>
+#include <map>
+#include <vector>
+#include "switch.h"
+#include "utils.h"
+
+struct CadenceType
+{
+    CadenceType(void)
+    : ring(0), ring_s(0), ring_ext(0), ring_ext_s(0) {};
+
+    CadenceType(unsigned int _ring, unsigned int _ring_s)
+    : ring(_ring), ring_s(_ring_s), ring_ext(0), ring_ext_s(0) {};
+
+    CadenceType(unsigned int _ring, unsigned int _ring_s, unsigned int _ring_ext, unsigned int _ring_ext_s)
+    : ring(_ring), ring_s(_ring_s), ring_ext(_ring_ext), ring_ext_s(_ring_ext_s) {};
+
+    unsigned int ring;
+    unsigned int ring_s;
+    unsigned int ring_ext;
+    unsigned int ring_ext_s;
+};
+
+struct CSpan {
+    std::string _dialplan;
+    std::string _context;
+    std::string _dialstring;
+};
+
+struct Opt
+{
+    typedef std::pair   < std::string, CadenceType >  CadencesPairType;
+    typedef std::map    < std::string, CadenceType >  CadencesMapType;
+
+    typedef std::map    < std::string, std::string >  OrigToDestMapType;
+    typedef std::pair   < std::string, std::string >  OrigToDestPairType;
+    typedef std::vector < std::string >               DestVectorType;
+
+    typedef std::map    < unsigned int, std::string > BoardToOrigMapType;
+    typedef std::pair   < unsigned int, std::string > BoardToOrigPairType;
+
+    typedef std::map    < std::string, unsigned int > OrigToNseqMapType;
+    typedef std::pair   < std::string, unsigned int > OrigToNseqPairType;
+
+    typedef std::pair   < unsigned int,unsigned int > ObjectIdType;
+    typedef std::pair   < std::string, ObjectIdType > BranchToObjectPairType;
+    typedef std::map    < std::string, ObjectIdType > BranchToObjectMapType;
+
+    typedef std::map    < std::string, std::string >  BranchToOptMapType;
+    typedef std::pair   < std::string, std::string >  BranchToOptPairType;
+    
+    typedef std::map    < std::string, std::string >  GroupToDestMapType;
+    typedef std::pair   < std::string, std::string >  GroupToDestPairType;
+
+    typedef std::pair   < std::string, CSpan >        SpanPairType;
+
+    typedef enum
+    {
+            GFLAG_MY_CODEC_PREFS = (1 << 0)
+    }
+    GFLAGS;
+
+    static void initialize(void);
+    static void obtain(void);
+    static void commit(void);
+    static void printConfiguration(switch_stream_handle_t*);
+
+protected:
+
+    static void loadConfiguration(const char *, const char **, bool show_errors = true);
+    static void cleanConfiguration(void);
+    
+    static switch_xml_t processSimpleXML(switch_xml_t &xml, const std::string& child_name);
+    static void processGroupXML(switch_xml_t &xml);
+    static void processCadenceXML(switch_xml_t &xml);
+    static void processFXSBranchesXML(switch_xml_t &xml);
+    static void processFXSHotlines(switch_xml_t &xml);
+    static void processFXSOptions(switch_xml_t &xml);
+
+public:
+    static bool                            _debug;
+    static std::string                     _dialplan;
+    static std::string                     _context;
+    static std::map < std::string, CSpan > _spans;
+       static GroupToDestMapType              _groups;
+       static CadencesMapType                 _cadences;
+    
+    static bool  _echo_canceller;
+    static bool  _auto_gain_control;
+    static bool  _out_of_band_dtmfs;
+    static bool  _suppression_delay;
+    static bool  _pulse_forwarding;
+    static bool  _native_bridge;
+    static bool  _recording;
+    static bool  _has_ctbus;
+    static bool  _fxs_bina;
+    static bool  _fxo_send_pre_audio;
+    static bool  _drop_collect_call;
+    static bool  _ignore_letter_dtmfs;
+    static bool  _optimize_audio_path;
+
+    static bool         _auto_fax_adjustment;
+    static unsigned int _fax_adjustment_timeout;
+
+    static bool         _r2_strict_behaviour;
+    static unsigned int _r2_preconnect_wait;
+
+    static unsigned int _fxs_digit_timeout;
+
+    static unsigned int _transferdigittimeout;
+
+    static std::string _blindxfer;
+    static std::string _atxfer;
+
+    static unsigned int _ringback_co_delay;
+    static unsigned int _ringback_pbx_delay;
+
+    static unsigned int _disconnect_delay;
+
+    static int _input_volume;
+    static int _output_volume;
+
+    static DestVectorType    _fxs_co_dialtone;
+    static OrigToDestMapType _fxs_hotline;
+    static std::string       _fxs_global_orig_base;
+
+    static BoardToOrigMapType    _fxs_orig_base;
+    static BranchToObjectMapType _fxs_branch_map;
+    static BranchToOptMapType    _branch_options;
+
+    static std::string _global_mohclass;
+    static std::string _global_language;
+
+    static std::string _record_prefix;
+
+    static std::string  _context_gsm_call;
+    static std::string  _context2_gsm_call;
+    static std::string  _context_gsm_sms;
+    static std::string  _context_fxo;
+    static std::string  _context2_fxo;
+    static std::string  _context_fxs;
+    static std::string  _context2_fxs;
+    static std::string  _context_digital;
+    static std::string  _context_pr;
+    static std::string  _user_xfer;
+
+    static int                _amaflags;
+    static std::string _callgroup;
+    static std::string _pickupgroup; /* or intercept */
+
+    static std::string _accountcode;
+    
+    static unsigned int _kommuter_timeout;
+    static std::string  _kommuter_activation;
+
+    static unsigned int _audio_packet_size;
+
+protected:
+
+    struct ProcessFXSCODialtone
+    {
+        void operator()(std::string options);
+    };
+
+    struct ProcessRecordPrefix
+    {
+        void operator()(std::string path);
+    };
+
+    struct ProcessAMAFlags
+    {
+        void operator()(std::string options);
+    };
+
+    struct ProcessCallGroup
+    {
+        void operator()(std::string options);
+    };
+
+    struct ProcessPickupGroup
+    {
+        void operator()(std::string options);
+    };
+
+    struct ProcessLogOptions
+    {
+        ProcessLogOptions(output_type output): _output(output) {}; 
+
+        void operator()(std::string options); 
+
+        protected:
+            output_type _output;
+    };
+
+    struct ProcessTraceOptions
+    {
+        void operator()(std::string options);
+    };
+};
+
+
+
+#endif /* _OPT_H_ */
+
diff --git a/src/mod/endpoints/mod_khomp/include/revision.h b/src/mod/endpoints/mod_khomp/include/revision.h
new file mode 100644 (file)
index 0000000..4665cda
--- /dev/null
@@ -0,0 +1 @@
+#define MOD_KHOMP_VERSION "1.0 - (rev: 5796)"
diff --git a/src/mod/endpoints/mod_khomp/include/spec.h b/src/mod/endpoints/mod_khomp/include/spec.h
new file mode 100644 (file)
index 0000000..119607b
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _SPEC_HPP_
+#define _SPEC_HPP_
+
+#include <function.hpp>
+#include "khomp_pvt.h"
+
+typedef enum
+{
+    SPR_CONTINUE,
+    SPR_SUCCESS,
+    SPR_FAIL,
+}
+SpecRetType;
+
+typedef enum
+{
+    SPF_FIRST  = 0x01,
+    SPF_CYCLIC = 0x02,
+}
+SpecFlagType;
+
+typedef unsigned int SpecFlagsType;
+
+
+typedef Function::Function3 < bool, unsigned int, unsigned int, SpecFlagsType & > SpecFunType;
+
+
+//SpecRetType processSpecAtom(std::string &, SpecFlagsType &, SpecFunType &);
+//SpecRetType processSpecAtoms(std::string &, SpecFlagsType &, SpecFunType &);
+//bool processCallChannelString(std::string &, Board::KhompPvt *&, int *, bool need_free = true);
+
+/* Request a Board::KhompPvt based on dialplan string.
+
+-- Format of dialplan string. --
+
+Dial(Khomp/B2C58/4832625644)
+ |      |    |       |
+ |      |    |       |
+ |      |    |       |
+ |      |    |       +- Destination number.
+ |      |    |
+ |      |    +- Identifier for board 2, channel 58.
+ |      |
+ |      +- Khomp channel identifier.
+ |
+ +- Dial Application.
+*/
+
+Board::KhompPvt * processDialString(const char *, int *);
+void processGroupString();
+
+Board::KhompPvt * processSMSString(const char *, int *);
+
+#endif /* _SPEC_HPP_ */
+
diff --git a/src/mod/endpoints/mod_khomp/include/utils.h b/src/mod/endpoints/mod_khomp/include/utils.h
new file mode 100644 (file)
index 0000000..34e9b26
--- /dev/null
@@ -0,0 +1,772 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include <bitset>
+#include <refcounter.hpp>
+#include <ringbuffer.hpp>
+#include <simple_lock.hpp>
+#include <saved_condition.hpp>
+#include <thread.hpp>
+#include "globals.h"
+#include "logger.h"
+#include "defs.h"
+
+/******************************************************************************/
+/************************** Defining applications *****************************/
+
+typedef enum
+{
+    FAX_ADJUST,
+    FAX_SEND,
+    FAX_RECEIVE,
+    USER_TRANSFER,
+    SMS_CHECK,
+    SMS_SEND,
+    SELECT_SIM_CARD,
+}
+ApplicationType;
+
+/******************************************************************************/
+/***************** Abstraction for defining channel flags *********************/
+
+struct Kflags
+{
+    typedef enum
+    {
+        CONNECTED = 0,
+        REALLY_CONNECTED,
+
+        IS_OUTGOING,
+        IS_INCOMING,
+
+        STREAM_UP,
+        LISTEN_UP,
+
+        GEN_CO_RING,
+        GEN_PBX_RING,
+
+        HAS_PRE_AUDIO,
+        HAS_CALL_FAIL,
+
+        DROP_COLLECT,
+
+        NEEDS_RINGBACK_CMD, //R2
+        EARLY_RINGBACK, //FXO
+
+        FAX_DETECTED, //Digital, FXO
+        FAX_SENDING, //Digital, FXO
+        FAX_RECEIVING, //Digital, FXO
+
+        OUT_OF_BAND_DTMFS,
+
+        KEEP_DTMF_SUPPRESSION,
+        KEEP_ECHO_CANCELLATION,
+        KEEP_AUTO_GAIN_CONTROL,
+
+        WAIT_SEND_DTMF,
+
+        CALL_WAIT_SEIZE, //FXO
+
+        NUMBER_DIAL_FINISHD, //R2
+        NUMBER_DIAL_ONGOING, //R2
+
+        FXS_OFFHOOK, //FXS
+        FXS_DIAL_FINISHD, //FXS
+        FXS_DIAL_ONGOING, //FXS
+        FXS_FLASH_TRANSFER, //FXS
+
+        XFER_QSIG_DIALING, //ISDN
+        XFER_DIALING, //ISDN, FXO
+
+        SMS_DOING_UPLOAD, //GSM
+
+        /*
+        NOW LOADING ...
+
+        BRIDGED,
+        */
+
+        /* Do not remove this last FLAG */
+        INVALID_FLAG
+    }
+    FlagType;
+
+    struct Flag
+    {        
+        const char *_name;
+        bool _value;
+    };
+
+    Kflags() { init(); };
+
+    void init();
+
+    inline const char * name(FlagType bit) { return _flags[bit]._name; }
+
+    inline bool check(FlagType bit) 
+    {
+#ifdef DEBUG_FLAGS
+        DBG(FUNC, D("Flag %s=%s") % name(bit) % 
+                (_flags[bit]._value ? "TRUE" : "FALSE"));
+#endif
+        return _flags[bit]._value;
+    }
+
+    inline void set(FlagType bit)
+    {
+#ifdef DEBUG_FLAGS
+        DBG(FUNC, D("Flag %s") % name(bit));
+#endif
+        _flags[bit]._value = true;
+    }
+
+    inline void clear(FlagType bit)
+    { 
+#ifdef DEBUG_FLAGS
+        DBG(FUNC, D("Flag %s") % name(bit));
+#endif
+        _flags[bit]._value = false;
+    }
+
+    inline void clearAll()
+    {
+        unsigned int index = 0;
+        for(; (FlagType)index < INVALID_FLAG; index++)
+        {
+            if(_flags[index]._value)
+            {
+                DBG(FUNC, D("Flag %s was not clean!") % name((FlagType)index));
+                clear((FlagType)index);
+            }
+        }
+    }
+
+ protected:
+    Flag _flags[INVALID_FLAG+1];
+};
+
+/******************************************************************************/
+/************************* Commands and Events Handler ************************/
+struct CommandRequest
+{
+    typedef enum
+    {
+        NONE = 0,
+        COMMAND,
+        ACTION
+    }
+    ReqType;
+
+    typedef enum
+    {
+        CNONE = 0,
+
+        /* Commands */
+        CMD_CALL,
+        CMD_ANSWER,
+        CMD_HANGUP,
+        
+        /* Actions */
+        FLUSH_REC_STREAM,
+        FLUSH_REC_BRIDGE,
+        START_RECORD,
+        STOP_RECORD
+
+    }
+    CodeType;
+
+    typedef enum
+    {
+        RFA_CLOSE,
+        RFA_KEEP_OPEN,
+        RFA_REMOVE
+    }
+    RecFlagType;
+
+    /* "empty" constructor */
+    CommandRequest() : 
+        _type(NONE),
+        _code(CNONE),
+        _obj(-1)
+    {}
+
+    CommandRequest(ReqType type, CodeType code, int obj) : 
+            _type(type),
+            _code(code),
+            _obj(obj)
+    {}
+
+    CommandRequest(const CommandRequest & cmd) : 
+            _type(cmd._type), 
+            _code(cmd._code), 
+            _obj(cmd._obj) 
+    {}
+
+    ~CommandRequest() {}
+
+    void operator=(const CommandRequest & cmd)
+    {
+        _type = cmd._type;
+        _code = cmd._code;
+        _obj = cmd._obj;
+    }
+
+    void mirror(const CommandRequest & cmd_request)
+    {
+        _type = cmd_request._type;
+        _code = cmd_request._code;
+        _obj = cmd_request._obj;
+    }
+
+    short type() { return _type; }
+    
+    short code() { return _code; }
+
+    int obj() { return _obj; }
+
+private:
+    short _type;
+    short _code;
+    int   _obj;
+};
+
+struct EventRequest
+{
+    /* "empty" constructor */
+    EventRequest(bool can_delete = true) : 
+        _delete(can_delete), 
+        _obj(-1)
+    {
+        if(can_delete)
+            _event = new K3L_EVENT();
+    }
+
+    /* Temporary constructor */
+    EventRequest(int obj, K3L_EVENT * ev) :
+            _delete(false),
+            _obj(obj),
+            _event(ev)
+    {}
+    
+    //EventRequest(const EventRequest & ev) : _obj(ev._obj) {}
+
+    ~EventRequest()
+    {
+
+        if(!_delete || !_event)
+            return;
+
+        if(_event->ParamSize)
+            free(_event->Params);
+
+        delete _event;
+    }
+
+    void operator=(const EventRequest & ev)
+    {
+        _delete = false;
+        _obj = ev._obj;
+        _event = ev._event;
+
+    }
+
+    void mirror(const EventRequest & ev_request)
+    {
+        //Checar o _event
+
+        if(_event->ParamSize)
+        {
+            free(_event->Params);
+        }
+
+        _event->Params = NULL;
+
+        _obj = ev_request._obj;
+
+        K3L_EVENT * ev     = ev_request._event;
+
+        if(!ev)
+        {
+            clearEvent();
+            return;
+        }
+
+        _event->Code       = ev->Code;       // API code
+        _event->AddInfo    = ev->AddInfo;    // Parameter 1
+        _event->DeviceId   = ev->DeviceId;   // Hardware information
+        _event->ObjectInfo = ev->ObjectInfo; // Additional object information
+        _event->ParamSize  = ev->ParamSize;  // Size of parameter buffer
+        _event->ObjectId   = ev->ObjectId;   // KEventObjectId: Event thrower object id
+
+        if(ev->ParamSize)
+        {
+            // Pointer to the parameter buffer
+            _event->Params = malloc(ev->ParamSize+1);
+            memcpy(_event->Params, ev->Params, ev->ParamSize);
+            ((char *)(_event->Params))[ev->ParamSize] = 0;
+        }
+    }
+
+    bool clearEvent()
+    {
+        _event->Code       = -1;
+        _event->AddInfo    = -1;
+        _event->DeviceId   = -1;
+        _event->ObjectInfo = -1;
+        _event->ParamSize  = 0;
+        _event->ObjectId   = -1;
+    }
+
+    int obj() { return _obj; }
+
+    K3L_EVENT * event() { return _event; }
+
+
+private:
+    bool        _delete;
+    int         _obj;
+    K3L_EVENT * _event;
+};
+
+template < typename R, int S >
+struct GenericFifo
+{
+    typedef R RequestType;
+    typedef SimpleNonBlockLock<25,100>  LockType;
+
+    GenericFifo(int device) : 
+            _device(device), 
+            _shutdown(false), 
+            _buffer(S), 
+            _mutex(Globals::module_pool), 
+            _cond(Globals::module_pool)
+    {};
+
+    int                         _device;
+    bool                        _shutdown;
+    Ringbuffer < RequestType >  _buffer;
+    LockType                    _mutex; /* to sync write acess to event list */
+    SavedCondition              _cond;
+    Thread                     *_thread;
+
+};
+
+typedef GenericFifo < CommandRequest, 250 > CommandFifo;
+typedef GenericFifo < EventRequest, 500 >   EventFifo;
+
+/* Used inside KhompPvt to represent an command handler */
+struct ChanCommandHandler: NEW_REFCOUNTER(ChanCommandHandler)
+{
+    typedef int (HandlerType)(void *);
+
+    ChanCommandHandler(int device, HandlerType * handler)
+    {
+        _fifo = new CommandFifo(device);
+        /* device event handler */
+        _fifo->_thread = new Thread(handler, (void *)this, Globals::module_pool);
+        if(_fifo->_thread->start())
+        {
+            DBG(FUNC,"Device command handler started");
+        }
+        else
+        {
+            LOG(ERROR, "Device command handler error");
+        }
+    }
+
+    ChanCommandHandler(const ChanCommandHandler & cmd)
+    : INC_REFCOUNTER(cmd, ChanCommandHandler),
+      _fifo(cmd._fifo)
+    {};
+
+    void unreference();
+
+    CommandFifo * fifo()
+    {
+        return _fifo;
+    }
+
+    void signal()
+    {
+        _fifo->_cond.signal();
+    };
+
+    bool writeNoSignal(const CommandRequest &);
+    bool write(const CommandRequest &);
+
+protected:
+    CommandFifo * _fifo;
+};
+
+/* Used inside KhompPvt to represent an event handler */
+struct ChanEventHandler: NEW_REFCOUNTER(ChanEventHandler)
+{
+    typedef int (HandlerType)(void *);
+
+    ChanEventHandler(int device, HandlerType * handler)
+    {
+        _fifo = new EventFifo(device);
+        /* device event handler */
+        _fifo->_thread = new Thread(handler, (void *)this, Globals::module_pool);
+        if(_fifo->_thread->start())
+        {
+            DBG(FUNC,"Device event handler started");
+        }
+        else
+        {
+            LOG(ERROR, "Device event handler error");
+        }
+    }
+
+    ChanEventHandler(const ChanEventHandler & evt)
+    : INC_REFCOUNTER(evt, ChanEventHandler),
+      _fifo(evt._fifo)
+    {};
+
+    void unreference();
+
+    EventFifo * fifo()
+    {
+        return _fifo;
+    }
+
+    void signal()
+    {
+        _fifo->_cond.signal();
+    };
+
+    bool provide(const EventRequest &);
+    bool writeNoSignal(const EventRequest &);
+    bool write(const EventRequest &);
+
+protected:
+    EventFifo * _fifo;
+};
+
+
+/******************************************************************************/
+/****************************** Internal **************************************/
+struct RingbackDefs
+{
+    enum
+    {
+        RB_SEND_DEFAULT = -1,
+        RB_SEND_NOTHING = -2,
+    };
+
+    typedef enum
+    {
+        RBST_SUCCESS,
+        RBST_UNSUPPORTED,
+        RBST_FAILURE,
+    }
+    RingbackStType;
+};
+
+/******************************************************************************/
+/******************************* Others ***************************************/
+static bool checkTrueString(const char * str)
+{   
+    if (str && *str)
+    {   
+        if (!SAFE_strcasecmp(str, "yes") || !SAFE_strcasecmp(str, "true") ||
+                !SAFE_strcasecmp(str, "enabled") || !SAFE_strcasecmp(str, "sim"))
+        {   
+            return true;
+        }   
+    }   
+
+    return false;
+}   
+
+static bool checkFalseString(const char * str)
+{   
+    if (str && *str)
+    {   
+        if (!SAFE_strcasecmp(str, "no") || !SAFE_strcasecmp(str, "false") ||
+                !SAFE_strcasecmp(str, "disabled") || !SAFE_strcasecmp(str, "não"))
+        {   
+            return true;
+        }   
+    }   
+
+    return false;
+}   
+
+static TriState getTriStateValue(const char * str)
+{
+    if (str)
+    {   
+        /**/ if (checkTrueString(str))  return T_TRUE;
+        else if (checkFalseString(str)) return T_FALSE;
+        else /***********************************/ return T_UNKNOWN;
+    }   
+
+    return T_UNKNOWN;
+}
+
+const char * answerInfoToString(int answer_info);
+
+static bool replaceTemplate(std::string & haystack, const std::string & needed, int value)
+{
+    Regex::Expression e(std::string(needed).c_str());
+    Regex::Match r(haystack,e);
+
+    if(!r.matched()) return false;
+
+    int len;
+    std::string fmt;
+    std::string tmp;
+
+    // if needed isn't "SSSS" the length of needed will give string format
+    // if needed is "SSSS" the length of value will give string format
+    std::string ssss("SSSS");
+
+    if (ssss != needed)
+    {   
+        len = needed.size();
+        fmt = STG(FMT("%%0%dd") % len);
+        tmp = STG(FMT(fmt) % value);
+    }   
+    else
+    {   
+        len = (STG(FMT("%d") % value)).size();
+        fmt = STG(FMT("%%%dd") % len);
+        tmp = STG(FMT(fmt) % value);
+    }   
+
+    haystack = r.replace(STG(FMT(fmt) % value));
+
+    DBG(FUNC,FMT("haystack: %s") % haystack);
+    return true;
+}
+
+
+static std::string timeToString (time_t time_value)
+{
+    int horas = (int)time_value / 3600;
+
+    if (horas > 0) 
+        time_value -= horas * 3600;
+
+    int minutos = (int)time_value / 60;
+
+    if (minutos > 0) 
+        time_value -= minutos * 60;
+
+    return STG(FMT("%02d:%02d:%02d") % horas % minutos % (int)time_value);
+}
+/******************************************************************************/
+/******************************* Match functions ******************************/
+typedef enum
+{
+    MATCH_NONE,
+    MATCH_EXACT,
+    MATCH_MORE
+}
+MatchType;
+
+static bool canMatch(std::string & context, std::string & exten, std::string & caller_id, bool match_more = false)
+{
+    switch_xml_t xml = NULL;
+    switch_xml_t xcontext = NULL;
+    switch_regex_t *re;
+    int ovector[30];
+    
+    if (switch_xml_locate("dialplan","context","name",context.c_str(),&xml,&xcontext, NULL,SWITCH_FALSE) == SWITCH_STATUS_SUCCESS)
+    {
+        switch_xml_t xexten = NULL;
+        
+        if(!(xexten = switch_xml_child(xcontext,"extension")))
+        {
+            DBG(FUNC,"extension cannot match, returning");
+
+            if(xml)
+                switch_xml_free(xml); 
+
+            return false;
+        }
+
+        while(xexten)
+        {
+            switch_xml_t xcond = NULL;
+
+            for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next)
+            {
+                std::string expression;
+
+                if (switch_xml_child(xcond, "condition")) 
+                { 
+                    LOG(ERROR,"Nested conditions are not allowed");
+                }  
+
+                switch_xml_t xexpression = switch_xml_child(xcond, "expression");
+
+                if ((xexpression = switch_xml_child(xcond, "expression"))) 
+                {
+                    expression = switch_str_nil(xexpression->txt);
+                }
+                else 
+                {
+                    expression =  switch_xml_attr_soft(xcond, "expression");
+                }  
+
+                if(expression.empty() || expression == "^(.*)$")
+                {
+                    /** 
+                    * We're not gonna take it
+                    * No, we ain't gonna take it
+                    * We're not gonna take it anymore
+                    **/
+                    continue;
+                }
+          
+                int pm = -1; 
+                switch_status_t is_match = SWITCH_STATUS_FALSE;
+                is_match =  switch_regex_match_partial(exten.c_str(),expression.c_str(),&pm);
+                
+                if(is_match == SWITCH_STATUS_SUCCESS)
+                {
+                    if(match_more)
+                    {
+                        if(pm == 1)
+                        {
+                            switch_xml_free(xml);
+                            return true;
+                        }
+                    }
+                    else
+                    {
+                        switch_xml_free(xml);
+                        return true;
+                    }
+                }
+                else
+                {
+                    // not match
+                }
+            }            
+
+            xexten = xexten->next;
+        }
+    }
+    else
+    {
+        DBG(FUNC,"context cannot match, returning");
+    }
+
+    if(xml)
+        switch_xml_free(xml); 
+
+    return false;
+}
+
+/******************************************************************************/
+/************************** Thread helper functions ***************************/
+typedef int (HandlerType)(void *);
+static Thread * threadCreate(HandlerType * handler,void * arg)
+{
+    Thread *t = new Thread(handler, (void *) arg, Globals::module_pool);
+    return t;
+}
+
+/******************************************************************************/
+/******************************** Kommuter ************************************/
+struct Kommuter
+{
+    Kommuter() : 
+        _kommuter_count(-1), 
+        _kwtd_timer_on(false)
+    {}
+    
+    bool start()
+    {
+        /* Checks for kommuter */
+        try
+        {
+            Globals::k3lapi.command(-1,-1,CM_WATCHDOG_COUNT);
+        }
+        catch(K3LAPI::failed_command & e)
+        {
+            LOG(WARNING , "libkwd.so used by Kommuter devices is not available.");
+            return false;
+        }
+
+        return true;
+    }
+
+    bool stop();
+    
+    bool initialize(K3L_EVENT *e);
+  
+    /* Index of the WatchDog timer */ 
+    TimerTraits::Index  _kwtd_timer_index;
+    int                 _kommuter_count;
+    bool                _kwtd_timer_on;
+
+    /* Timer to control our dog (totó) */
+    static void wtdKickTimer(void *);
+    
+};
+
+/******************************************************************************/
+/******************************* Statistics ***********************************/
+struct Statistics
+{
+    typedef enum
+    {
+        DETAILED = 0,
+        ROW
+    }
+    Type;
+
+    virtual std::string getDetailed() { return ""; }
+    virtual void clear() {}
+};
+
+/******************************************************************************/
+/******************************************************************************/
+#endif  /* _UTILS_H_ */
diff --git a/src/mod/endpoints/mod_khomp/install.sh b/src/mod/endpoints/mod_khomp/install.sh
new file mode 100755 (executable)
index 0000000..8cc60f2
--- /dev/null
@@ -0,0 +1,93 @@
+#!/bin/bash
+
+###############################################################################
+#   KHOMP generic endpoint/channel library.
+#   Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.1 (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+# the specific language governing rights and limitations under the License.
+
+# Alternatively, the contents of this file may be used under the terms of the
+# "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+# case the provisions of "LGPL License" are applicable instead of those above.
+
+# If you wish to allow use of your version of this file only under the terms of
+# the LGPL License and not to allow others to use your version of this file
+# under the MPL, indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by the LGPL
+# License. If you do not delete the provisions above, a recipient may use your
+# version of this file under either the MPL or the LGPL License.
+
+# The LGPL header follows below:
+
+#   This library is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU Lesser General Public
+#   License as published by the Free Software Foundation; either
+#   version 2.1 of the License, or (at your option) any later version.
+
+#   This library is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   Lesser General Public License for more details.
+
+#   You should have received a copy of the GNU Lesser General Public License
+#   along with this library; if not, write to the Free Software Foundation,
+#   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+###############################################################################
+
+
+clean()
+{
+    printf "$1"
+    exit 1
+}
+
+if [ `whoami` != 'root' ] 
+then
+     clean "Need to be root\n"
+fi  
+
+if [ "w$FREESWITCH_PATH" == "w" ]
+then
+    clean "FreeSWITCH source PATH is needed: \n\tSet \"FREESWITCH_PATH=\"\n"
+fi
+
+if ! which 'kserver' &> /dev/null
+then
+    echo "k3l will be installed"
+    K3L_FILE="k3l_2.1_client.sh"
+
+    if [ "w`uname -m | grep x86_64`" == "w" ]
+    then
+        echo "Downloading i686 package"
+        wget -t15 -c --progress=bar:force -O $K3L_FILE.gz http://www.khomp.com.br/binaries/softpbx/freeswitch/k3l_2.1_client_i686.sh.gz
+    else
+        echo "Downloading x86_64 package"
+        wget -t15 -c --progress=bar:force -O $K3L_FILE.gz http://www.khomp.com.br/binaries/softpbx/freeswitch/k3l_2.1_client_x86-64.sh.gz
+    fi
+
+    gunzip $K3L_FILE.gz
+    chmod 0755 $K3L_FILE
+
+    (./$K3L_FILE) || clean "Error on k3l install\n"
+    
+    rm $K3L_FILE
+fi
+
+if [ "w`kserver --version | grep 2.1`" == "w" ]
+then
+    clean "k3l version 2.1 must be installed: \n\tUninstall the old version of k3l and try again\n"
+fi
+
+make || clean "Error on compilation\n"
+
+make install || clean "Error on installation\n"
+
+echo "Successfully installed!"
+
diff --git a/src/mod/endpoints/mod_khomp/mod_khomp.cpp b/src/mod/endpoints/mod_khomp/mod_khomp.cpp
new file mode 100644 (file)
index 0000000..d09a8a3
--- /dev/null
@@ -0,0 +1,1509 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Khomp development team
+ * Geovani Ricardo Wiedenhoft <grw.freeswitch  (at) gmail.com>
+ * Leonardo Lang              <lang.freeswitch (at) gmail.com> 
+ * Eduardo Nunes              <eduardonunesp   (at) gmail.com>
+ * Joao Mesquita              <mesquita        (at) khomp.com.br>
+ * Raul Fragoso               <raulfragoso     (at) gmail.com>
+ *
+ *
+ * mod_khomp.c -- Khomp board Endpoint Module
+ *
+ */
+
+/**
+  \mainpage Khomp board Endpoint Module
+  
+  \section Introduction
+  This module has been developed to make a nice, affordable brazilian board
+  called Khomp (http://www.khomp.com.br) compatible with FreeSWITCH.
+  This module is supported by the manufacturer.
+
+  \section Contributors
+  \li Khomp development team
+  \li Geovani Ricardo Wiedenhoft <grw.freeswitch  (at) gmail.com>
+  \li Leonardo Lang              <lang.freeswitch (at) gmail.com>
+  \li Eduardo Nunes              <eduardonunesp   (at) gmail.com>
+  \li Joao Mesquita              <jmesquita       (at) gmail.com>
+  \li Raul Fragoso               <raulfragoso     (at) gmail.com>
+**/
+
+/**
+ * @file mod_khomp.cpp
+ * @brief Khomp Endpoint Module
+ * @see mod_khomp
+ */
+
+#include <string>
+#include "khomp_pvt.h"
+#include "spec.h"
+#include "lock.h"
+#include "logger.h"
+#include "opt.h"
+#include "globals.h"
+#include "cli.h"
+
+extern "C" void Kstdcall khompAudioListener(int32 deviceid, int32 objectid,
+                                          byte * read_buffer, int32 read_size);
+
+/*!
+  \brief Load the module. Expadend by a FreeSWITCH macro.
+  Things we do here:
+  \li Initialize a static structure on KhompPvt
+  \li Load the configuration
+  \li Start the K3L API, responsible for connecting to KServer
+  \li Register mod APIs and APPs
+  \li Register audio callback for KServer
+  \li Register event callback for KServer
+  \see Opt Where all the configs are handled
+  \see khompEventCallback To where we bind the event handler
+  \see khompAudioListener To where we bind the audio handlers
+  */
+SWITCH_MODULE_LOAD_FUNCTION(mod_khomp_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_khomp_shutdown);
+SWITCH_MODULE_DEFINITION(mod_khomp, mod_khomp_load, mod_khomp_shutdown, NULL);
+
+/*!
+ \defgroup fs_states FreeSWITCH State Handlers
+            We get called back from FreeSWITCH core everytime we make a
+            transition to any of these states. Refer to FreeSWITCH docs for a
+            detailed explanation of each state.
+ */
+/*@{*/
+switch_status_t khompInit(switch_core_session_t *session);
+switch_status_t khompRouting(switch_core_session_t *session);
+switch_status_t khompExecute(switch_core_session_t *session);
+switch_status_t khompHangup(switch_core_session_t *session);
+switch_status_t khompExchangeMedia(switch_core_session_t *session);
+switch_status_t khompSoftExecute(switch_core_session_t *session);
+switch_status_t khompDestroy(switch_core_session_t *session);
+/*@}*/
+
+switch_state_handler_table_t khomp_state_handlers = {
+    khompInit,          /*.on_init */
+    khompRouting,       /*.on_routing */
+    khompExecute,       /*.on_execute */
+    khompHangup,        /*.on_hangup */
+    khompExchangeMedia, /*.on_exchange_media */
+    khompSoftExecute,   /*.on_soft_execute */
+    NULL,               /*.on_consume_media */
+    NULL,               /*.on_hibernate */
+    NULL,               /*.on_reset */
+    NULL,               /*.on_park*/
+    NULL,               /*.on_reporting*/
+    khompDestroy        /*.on_destroy*/
+};
+
+switch_status_t khompSMSDestroy(switch_core_session_t *session);
+
+switch_state_handler_table_t khomp_sms_state_handlers = {
+    khompInit,          /*.on_init */
+    khompRouting,       /*.on_routing */
+    khompExecute,       /*.on_execute */
+    NULL,               /*.on_hangup */
+    khompExchangeMedia, /*.on_exchange_media */
+    khompSoftExecute,   /*.on_soft_execute */
+    NULL,               /*.on_consume_media */
+    NULL,               /*.on_hibernate */
+    NULL,               /*.on_reset */
+    NULL,               /*.on_park*/
+    NULL,               /*.on_reporting*/
+    khompSMSDestroy     /*.on_destroy*/
+};
+
+switch_status_t khompPRHangup(switch_core_session_t *session);
+
+switch_state_handler_table_t khomp_pr_state_handlers = {
+    khompInit,          /*.on_init */
+    khompRouting,       /*.on_routing */
+    khompExecute,       /*.on_execute */
+    khompPRHangup,      /*.on_hangup */
+    khompExchangeMedia, /*.on_exchange_media */
+    khompSoftExecute,   /*.on_soft_execute */
+    NULL,               /*.on_consume_media */
+    NULL,               /*.on_hibernate */
+    NULL,               /*.on_reset */
+    NULL,               /*.on_park*/
+    NULL,               /*.on_reporting*/
+    khompDestroy        /*.on_destroy*/
+};
+
+/* Callbacks for FreeSWITCH */
+switch_call_cause_t khompCall(
+        switch_core_session_t *session,
+        switch_event_t *var_event,
+        switch_caller_profile_t *outbound_profile,
+        switch_core_session_t **new_session,
+        switch_memory_pool_t **pool,
+        switch_originate_flag_t flags,
+        switch_call_cause_t *cancel_cause);
+switch_status_t khompRead(switch_core_session_t *session,
+        switch_frame_t **frame,
+        switch_io_flag_t flags,
+        int stream_id);
+switch_status_t khompWrite(switch_core_session_t *session,
+        switch_frame_t *frame,
+        switch_io_flag_t flags,
+        int stream_id);
+switch_status_t khompKill(switch_core_session_t *session,
+        int sig);
+switch_status_t khompDigit(switch_core_session_t *session,
+        const switch_dtmf_t *dtmf);
+switch_status_t khompReceiveMessage(switch_core_session_t *session,
+        switch_core_session_message_t *msg);
+switch_status_t khompReceiveEvent(switch_core_session_t *session,
+        switch_event_t *event);
+
+/*!
+ \ingroup fs_states
+ */
+switch_io_routines_t khomp_io_routines = {
+    khompCall,           /*.outgoing_channel */
+    khompRead,           /*.read_frame */
+    khompWrite,          /*.write_frame */
+    khompKill,           /*.kill_channel */
+    khompDigit,          /*.send_dtmf */
+    khompReceiveMessage, /*.receive_message */
+    khompReceiveEvent    /*.receive_event */
+};
+
+switch_io_routines_t khomp_sms_io_routines = {
+    NULL,           /*.outgoing_channel */
+    NULL,           /*.read_frame */
+    NULL,           /*.write_frame */
+    khompKill,      /*.kill_channel */
+    NULL,           /*.send_dtmf */
+    NULL,           /*.receive_message */
+    NULL            /*.receive_event */
+};
+
+switch_status_t khompPRWrite(switch_core_session_t *session,
+        switch_frame_t *frame,
+        switch_io_flag_t flags,
+        int stream_id);
+
+switch_io_routines_t khomp_pr_io_routines = {
+    NULL,                /*.outgoing_channel */
+    khompRead,           /*.read_frame */
+    khompPRWrite,        /*.write_frame */
+    khompKill,           /*.kill_channel */
+    NULL,                /*.send_dtmf */
+    NULL,                /*.receive_message */
+    NULL                 /*.receive_event */
+};
+
+/* Macros to define specific API functions */
+SWITCH_STANDARD_API(apiKhomp);
+
+/*!
+ \brief Print link status. [khomp show links]
+ */
+void apiPrintLinks(switch_stream_handle_t* stream, unsigned int device,
+        unsigned int link);
+/*!
+ \brief Print board channel status. [khomp show channels]
+ */
+void apiPrintChannels(switch_stream_handle_t* stream);
+
+/*!
+   \brief State methods they get called when the state changes to the specific state
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+switch_status_t khompInit(switch_core_session_t *session)
+{
+    DBG(FUNC, "CHANNEL INIT")
+    switch_channel_t *channel = switch_core_session_get_channel(session);
+
+    if(!channel)
+    {
+        DBG(FUNC, D("Channel is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    /* Move channel's state machine to ROUTING. This means the call is trying
+       to get from the initial start where the call because, to the point
+       where a destination has been identified. If the channel is simply
+       left in the initial state, nothing will happen. */
+    switch_channel_set_state(channel, CS_ROUTING);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompRouting(switch_core_session_t *session)
+{
+    DBG(FUNC, "CHANNEL ROUTING");
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompExecute(switch_core_session_t *session)
+{
+
+    DBG(FUNC, "CHANNEL EXECUTE");
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompHangup(switch_core_session_t *session)
+{
+    DBG(FUNC, D("c"));
+
+    Board::KhompPvt *tech_pvt = NULL;
+
+    if(!session)
+    {
+        LOG(ERROR, D("r (Session is NULL)"));
+        return SWITCH_STATUS_SUCCESS;
+    }
+    
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("r (pvt is NULL)"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    try
+    {       
+        ScopedPvtLock lock(tech_pvt);
+
+        if(tech_pvt->freeState())
+        {
+            DBG(FUNC, PVT_FMT(tech_pvt->target(), "r (Already disconnected)"));
+            return SWITCH_STATUS_SUCCESS;
+        }
+
+        tech_pvt->setHangupCause(SWITCH_CAUSE_NORMAL_CLEARING, true);
+
+        //tech_pvt->doHangup();
+
+        lock.unlock();
+
+        CommandRequest c_req(CommandRequest::COMMAND, CommandRequest::CMD_HANGUP, tech_pvt->target().object);
+
+        Board::board(tech_pvt->target().device)->chanCommandHandler()->write(c_req);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+        return SWITCH_STATUS_FALSE;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "r (unable to get device: %d!)") % err.device);
+        return SWITCH_STATUS_FALSE;
+    }
+
+    DBG(FUNC, D("r"))
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompPRHangup(switch_core_session_t *session)
+{
+    DBG(FUNC, D("CHANNEL HANGUP"))
+}
+
+
+switch_status_t khompDestroy(switch_core_session_t *session)
+{
+    DBG(FUNC, D("c"))
+
+    if(!session)
+    {
+        DBG(FUNC, D("r (session is null)"))
+        return SWITCH_STATUS_SUCCESS;
+    }
+    
+    Board::KhompPvt *tech_pvt = NULL;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("r (pvt is null)"))
+        return SWITCH_STATUS_FALSE;
+    }
+    try
+    {       
+        ScopedPvtLock lock(tech_pvt);
+
+        switch_core_session_set_private(session, NULL);
+        tech_pvt->destroyAll();
+    }
+    catch (ScopedLockFailed & err)
+    {
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+    }
+
+    DBG(FUNC, D("r"))
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompSMSDestroy(switch_core_session_t *session)
+{
+    DBG(FUNC, D("c"))
+
+    if(!session)
+    {
+        DBG(FUNC, D("r (session is null)"))
+        return SWITCH_STATUS_SUCCESS;
+    }
+/*    
+    Board::KhompPvt *tech_pvt = NULL;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("r (pvt is null)"))
+        return SWITCH_STATUS_FALSE;
+    }
+    
+    try
+    {       
+        ScopedPvtLock lock(tech_pvt);
+*/
+        switch_core_session_set_private(session, NULL);
+/*
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+    }
+*/
+
+    DBG(FUNC, D("r"))
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompKill(switch_core_session_t *session, int sig)
+{
+    //DBG(FUNC,FMT("CHANNEL KILL, kill = %d") % sig) 
+    Board::KhompPvt *tech_pvt = NULL;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        return SWITCH_STATUS_FALSE;
+    }
+
+    switch (sig) 
+    {
+    case SWITCH_SIG_NONE:
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL KILL,  NONE!"));
+        break;
+    case SWITCH_SIG_KILL:
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL KILL, SIGKILL!"));
+        //switch_thread_cond_signal(tech_pvt->_cond);
+        break;
+    case SWITCH_SIG_XFER:
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL KILL, SIGXFER!"));
+        break;
+    case SWITCH_SIG_BREAK:
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL KILL, BREAK!"));
+        break;
+    default:
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL KILL, WHAT?!"));
+        break;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompExchangeMedia(switch_core_session_t *session)
+{
+    DBG(FUNC, "CHANNEL LOOPBACK")
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompSoftExecute(switch_core_session_t *session)
+{
+    DBG(FUNC, "CHANNEL TRANSMIT")
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompDigit(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+    Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+    
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "c (%c)") % dtmf->digit);
+
+    try
+    {
+        ScopedPvtLock lock(tech_pvt);
+
+        char s[] = { dtmf->digit, '\0' };
+
+        tech_pvt->sendDtmf(s);
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "r (unable to lock: %s!)") % err._msg.c_str());
+        return SWITCH_STATUS_FALSE;
+    }
+
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "r"));
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompRead(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+    Board::KhompPvt *tech_pvt = NULL;
+    //switch_time_t started = switch_time_now();
+    //unsigned int elapsed;
+    //switch_byte_t *data;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("pvt is NULL"))
+        return SWITCH_STATUS_FALSE;
+    }
+
+    *frame = NULL;
+
+    while (true)
+    {
+        /*
+        if (switch_test_flag(tech_pvt, TFLAG_BREAK))
+        {
+            switch_clear_flag_locked(tech_pvt, TFLAG_BREAK);
+
+            *frame = tech_pvt->_reader_frames.cng();
+            return SWITCH_STATUS_SUCCESS;
+        }
+        */
+
+        if (tech_pvt->call()->_flags.check(Kflags::LISTEN_UP))
+        {
+            *frame = tech_pvt->_reader_frames.pick();
+
+            if (!*frame)
+            {
+                //Reader buffer empty, waiting...
+                switch_cond_next();
+                continue;
+            }
+        }
+        else
+        {
+            switch_yield(20000);
+            *frame = tech_pvt->_reader_frames.cng();
+        }
+/*
+#ifdef BIGENDIAN
+        if (switch_test_flag(tech_pvt, TFLAG_LINEAR))
+        {
+            switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2);
+        }
+#endif
+*/
+        return SWITCH_STATUS_SUCCESS;
+    }
+
+    return SWITCH_STATUS_FALSE;
+}
+
+switch_status_t khompWrite(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+    Board::KhompPvt *tech_pvt = NULL;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+/*
+#ifdef BIGENDIAN
+    if (switch_test_flag(tech_pvt, TFLAG_LINEAR))
+    {
+        switch_swap_linear(frame->data, (int) frame->datalen / 2);
+    }
+#endif
+*/
+
+    if (frame) // && frame->flags != SFF_CNG)
+    {
+        if(frame->datalen != 0 && tech_pvt->call()->_flags.check(Kflags::GEN_CO_RING))
+        {
+            tech_pvt->call()->_flags.clear(Kflags::GEN_CO_RING);
+
+            try
+            {
+                Board::board(tech_pvt->target().device)->_timers.del(tech_pvt->call()->_idx_co_ring);
+            }
+            catch (K3LAPI::invalid_device & err)
+            {
+                LOG(ERROR, PVT_FMT(tech_pvt->target(), "Unable to get device: %d!") % err.device);
+            }
+
+            if(tech_pvt->call()->_cadence != Board::KhompPvt::PLAY_VM_TONE)
+            {    
+                tech_pvt->stopCadence();
+            } 
+        }
+
+        if (!tech_pvt->_writer_frames.give((const char *)frame->data, (size_t)frame->datalen))
+        {
+            DBG(STRM, PVT_FMT(tech_pvt->target(), "Writer buffer full!"));
+            //Writer buffer full!
+        }
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+
+}
+
+switch_status_t khompPRWrite(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+    /*
+    Board::KhompPvt *tech_pvt = NULL;
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+    */
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t khompAnswer(switch_core_session_t *session)
+{
+    Board::KhompPvt *tech_pvt;
+    switch_channel_t *channel = NULL;
+
+    channel = switch_core_session_get_channel(session);
+
+    if(!channel)
+    {
+        LOG(ERROR, D("channel is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "CHANNEL ANSWER"));
+
+    try
+    {
+        ScopedPvtLock lock(tech_pvt);
+
+        if(!tech_pvt->session() || !tech_pvt->call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "Channel is not connected"));
+            return SWITCH_STATUS_FALSE;
+        }
+
+        tech_pvt->getSpecialVariables();
+
+        tech_pvt->setVolume();
+
+        tech_pvt->setCollectCall();
+
+        if (!tech_pvt->call()->_flags.check(Kflags::CONNECTED))
+        {
+            /* we can unlock it now */
+            lock.unlock();
+
+            CommandRequest c_req(CommandRequest::COMMAND, CommandRequest::CMD_ANSWER, tech_pvt->target().object);
+
+            Board::board(tech_pvt->target().device)->chanCommandHandler()->write(c_req);
+
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(tech_pvt->target(), "channel is already connected"));
+        }
+
+        //Esperar o atendimento EV_CONNECT
+        //if (!khomp_pvt::loop_while_flag_timed(pvt, c, kflags::REALLY_CONNECTED, timeout, &lock, false)) { return SWITCH_STATUS_FALSE; }
+
+
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, D("unable to get device: %d!") % err.device);
+        return SWITCH_STATUS_FALSE;
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to lock: %s!") % err._msg.c_str());
+        return SWITCH_STATUS_FALSE;
+
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t khompReceiveMessage(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+    Board::KhompPvt *tech_pvt;
+    
+    if(!session)
+    {
+        LOG(ERROR, D("session is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    if(!msg)
+    {
+        LOG(ERROR, D("msg is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    tech_pvt = (Board::KhompPvt *) switch_core_session_get_private(session);
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+    
+    switch (msg->message_id) {
+        case SWITCH_MESSAGE_REDIRECT_AUDIO:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_REDIRECT_AUDIO")); 
+            break;
+        case SWITCH_MESSAGE_TRANSMIT_TEXT:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_TRANSMIT_TEXT")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_ANSWER:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_ANSWER")); 
+            return khompAnswer(session);
+            break;
+        case SWITCH_MESSAGE_INDICATE_PROGRESS:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_PROGRESS")); 
+            tech_pvt->indicateProgress();
+            break;
+        case SWITCH_MESSAGE_INDICATE_BRIDGE:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_BRIDGE")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_UNBRIDGE")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_TRANSFER:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_TRANSFER")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_RINGING:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_RINGING")); 
+            tech_pvt->indicateRinging();
+            break;
+        case SWITCH_MESSAGE_INDICATE_MEDIA:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_MEDIA")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_NOMEDIA:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_NOMEDIA")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_HOLD:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_HOLD")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_UNHOLD:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_UNHOLD")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_REDIRECT:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_REDIRECT")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_RESPOND:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_RESPOND")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_BROADCAST:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_BROADCAST")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_DEFLECT:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_DEFLECT")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_DISPLAY:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_DISPLAY")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_TRANSCODING_NECESSARY")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_AUDIO_SYNC")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_UUID_CHANGE:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_UUID_CHANGE")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_SIMPLIFY:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_SIMPLIFY")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_PROXY_MEDIA:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_PROXY_MEDIA")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC")); 
+            break;
+        case SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC_COMPLETE:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC_COMPLETE")); 
+            break;
+        case SWITCH_MESSAGE_INVALID:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "SWITCH_MESSAGE_INVALID")); 
+            break;
+        default:
+            DBG(FUNC, PVT_FMT(tech_pvt->_target, "unknown message received [%d].") % msg->message_id % (msg->from ? msg->from : 0)); 
+            break;
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/*!
+  \brief Make sure when you have 2 sessions in the same scope that you pass
+  the appropriate one to the routines that allocate memory or you will have
+  1 channel with memory allocated from another channel's pool!
+*/
+switch_call_cause_t khompCall
+        (switch_core_session_t *session,
+         switch_event_t *var_event,
+         switch_caller_profile_t *outbound_profile,
+         switch_core_session_t **new_session,
+         switch_memory_pool_t **pool,
+         switch_originate_flag_t flags,
+         switch_call_cause_t *cancel_cause)
+{
+    if (!outbound_profile)
+    {
+        LOG(ERROR, D("No caller profile"));
+        //switch_core_session_destroy(new_session);
+        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+    }
+
+    Board::KhompPvt *tech_pvt;
+    int cause = (int)SWITCH_CAUSE_SUCCESS;
+    
+    try
+    {
+        ScopedAllocLock alloc_lock;
+
+        // got the pvt
+        tech_pvt = processDialString(outbound_profile->destination_number,&cause);
+
+        if(tech_pvt == NULL || cause != SWITCH_CAUSE_SUCCESS)
+        {
+            LOG(ERROR, D("unable to find free channel"));
+            return (cause == SWITCH_CAUSE_SUCCESS) ? SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER : (switch_call_cause_t) cause;
+        }
+
+        ScopedPvtLock lock(tech_pvt);
+
+        if(tech_pvt->justAlloc(false, pool) != SWITCH_STATUS_SUCCESS)
+        {
+            tech_pvt->cleanup(Board::KhompPvt::CLN_HARD);
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "Initilization Error!"));
+            return SWITCH_CAUSE_UNALLOCATED_NUMBER; 
+        }
+
+        tech_pvt->owner((session ? session : tech_pvt->session()));
+        // get the session to FS
+        *new_session = tech_pvt->session();
+
+        if(tech_pvt->justStart(outbound_profile) != SWITCH_STATUS_SUCCESS)
+        {
+            *new_session = NULL;
+            tech_pvt->cleanup(Board::KhompPvt::CLN_HARD);
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to justStart"));
+            return SWITCH_CAUSE_UNALLOCATED_NUMBER;
+        }
+
+        alloc_lock.unlock();
+        
+        tech_pvt->getSpecialVariables();
+
+        tech_pvt->setVolume();
+        
+        if(tech_pvt->makeCall() != ksSuccess)
+        {
+            *new_session = NULL;
+            tech_pvt->cleanup(Board::KhompPvt::CLN_HARD);
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to makeCall"));
+            return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+        }
+
+        tech_pvt->setFSChannelVar("KCallAnswerInfo", "Unknown");
+    }
+    catch(ScopedLockFailed & err)
+    {
+        if(err._fail == ScopedLockFailed::ALLOC_FAILED)
+        {
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to global alloc lock"));
+        }
+        else
+        {
+            tech_pvt->cleanup(Board::KhompPvt::CLN_HARD);
+            LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to lock: %s!") % err._msg.c_str());
+        }
+        return SWITCH_CAUSE_INTERWORKING;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "%s") % err._msg.c_str());
+    }
+
+    return SWITCH_CAUSE_SUCCESS;
+}
+
+switch_status_t khompReceiveEvent(switch_core_session_t *session, switch_event_t *event)
+{
+    struct Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+    char *body = switch_event_get_body(event);
+    //switch_assert(tech_pvt != NULL);
+
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return SWITCH_STATUS_FALSE;
+    }
+    
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "Receive Event id[%d] name[%s] body=[%s]") % event->event_id % event->headers->name % body); 
+
+    if (!body) {
+        body = (char *)"";
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/* A simple idea of app */
+SWITCH_STANDARD_APP(klogFunction)
+{
+    if (zstr(data)) 
+    {
+        LOG(ERROR, D("No data specified"));
+    } 
+    else 
+    {
+        LOG(MESSAGE, FMT("KLOG: %s") %  std::string(data));
+    }
+}
+
+void setVariable(switch_core_session_t * session, const char * variable, const char * data)
+{
+    if(!session)
+    {
+        LOG(ERROR, FMT("Session is NULL in %s") % variable);
+        return;
+    }
+
+    if (zstr(data)) 
+    {
+        LOG(ERROR, FMT("No %s specified") % variable);
+        return;
+    } 
+
+    if(strcasecmp(data, "on") && strcasecmp(data, "off"))
+    {
+        LOG(ERROR, FMT("On %s specify on or off") % variable);
+        return;
+    }
+
+    switch_channel_t *c = switch_core_session_get_channel(session);
+
+    if(!c)
+    {
+        LOG(ERROR, FMT("Channel is NULL in %s") % variable);
+        return;
+    }
+
+    switch_channel_set_variable(c, variable, (!strcasecmp(data, "on") ? "true" : "false" ));
+
+    DBG(FUNC,FMT("%s set %s") % variable % data);
+}
+
+SWITCH_STANDARD_APP(kdtmfSuppressionFunction)
+{
+    setVariable(session, "KDTMFSuppression", data);
+}
+
+SWITCH_STANDARD_APP(kechoCancellerFunction)
+{
+    setVariable(session, "KEchoCanceller", data);
+}
+
+SWITCH_STANDARD_APP(kautoGainControlFunction)
+{
+    setVariable(session, "KAutoGainControl", data);
+}
+
+SWITCH_STANDARD_APP(kr2SendConditionFunction)
+{
+    setVariable(session, "KR2SendCondition", data);
+}
+
+SWITCH_STANDARD_APP(kadjustForFaxFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+    
+    Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return;
+    }
+
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "Application KAdjustForFax"));
+
+    try
+    {
+        ScopedPvtLock lock(tech_pvt);
+
+        if(tech_pvt->application(FAX_ADJUST, session, data))
+        {
+            /* adjust the flag */
+            tech_pvt->call()->_flags.set(Kflags::FAX_DETECTED);
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(tech_pvt->target(), "unable to lock: %s!") %  err._msg.c_str());
+        return;
+    }
+}
+
+SWITCH_STANDARD_APP(ksendFaxFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+    
+
+    Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return;
+    }
+
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "Application KSendFax"));
+
+    tech_pvt->application(FAX_SEND, session, data);
+}
+
+SWITCH_STANDARD_APP(kreceiveFaxFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+    
+
+    Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        LOG(ERROR, D("pvt is NULL"));
+        return;
+    }
+    
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "Application KReceiveFax"));
+
+    tech_pvt->application(FAX_RECEIVE, session, data);
+}
+
+SWITCH_STANDARD_APP(kUserTransferFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+    
+    if (zstr(data)) 
+    {
+        LOG(ERROR, D("No number specified"));
+        return;
+    } 
+
+    Board::KhompPvt *tech_pvt = static_cast<Board::KhompPvt*>(switch_core_session_get_private(session));
+
+    if(!tech_pvt)
+    {
+        DBG(FUNC, D("pvt is NULL"));
+        return;
+    }
+    
+    DBG(FUNC, PVT_FMT(tech_pvt->target(), "Application KUserTransfer"));
+
+    tech_pvt->application(USER_TRANSFER, session, data);
+}
+
+SWITCH_STANDARD_APP(ksetVolumeFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+
+    if (zstr(data)) 
+    {
+        LOG(ERROR, D("No KSetVolume specified"));
+        return;
+    } 
+
+    switch_channel_t *c = switch_core_session_get_channel(session);
+
+    if(!c)
+    {
+        LOG(ERROR, D("Channel is NULL"));
+        return;
+    }
+
+    switch_channel_set_variable(c, "KSetVolume", data);
+
+    DBG(FUNC, FMT("KSetVolume set %s") % data);
+}
+
+SWITCH_STANDARD_APP(kSendSMSFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+
+    switch_channel_t *channel = switch_core_session_get_channel(session);
+
+    if(!channel)
+    {
+        LOG(ERROR, D("Channel is NULL"));
+        return;
+    }
+
+    switch_channel_set_variable(channel, "KSmsDelivered", "no");
+    switch_channel_set_variable(channel, "KSmsErrorCode", "42");
+    switch_channel_set_variable(channel, "KSmsErrorName", Verbose::gsmSmsCause((KGsmSmsCause)42).c_str());
+
+    if (zstr(data))
+    {
+        LOG(ERROR, D("No data specified"));
+        return;
+    }
+
+    int cause = (int)SWITCH_CAUSE_SUCCESS;
+
+    try
+    {
+        ScopedAllocLock alloc_lock;
+
+        Board::KhompPvt *tech_pvt = processSMSString(data, &cause);
+
+        if(!tech_pvt)
+        {
+            DBG(FUNC, D("pvt is NULL, cause '%d'") % cause);
+            return;
+        }
+
+        DBG(FUNC, PVT_FMT(tech_pvt->target(), "Application KSendSMS"));
+
+        ScopedPvtLock lock(tech_pvt);
+
+        alloc_lock.unlock();
+        
+        tech_pvt->application(SMS_SEND, session, data);
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        if(err._fail == ScopedLockFailed::ALLOC_FAILED)
+        {
+            LOG(ERROR, D("unable to global alloc lock"));
+        }
+        else
+        {
+            LOG(ERROR, D("unable to lock: %s!") % err._msg.c_str());
+        }
+    }
+
+}
+
+SWITCH_STANDARD_APP(kSelectSimCardFunction)
+{
+    if(!session)
+    {
+        LOG(ERROR, D("Session is NULL"));
+        return;
+    }
+
+    if (zstr(data))
+    {    
+        LOG(ERROR, D("invalid number of arguments"));
+        return;
+    }    
+
+    int dev = -1;
+    int obj = -1;
+
+    try
+    {
+        std::string datastr((const char*) data);
+        Strings::trim(datastr);
+
+        Strings::vector_type params;
+        Strings::tokenize(datastr, params, "|,",3);
+
+        std::string num("0");
+
+        if (params.size() == 3)
+        {    
+            dev = Strings::tolong(params[0]);
+            obj = Strings::tolong(params[1]);
+            num = params[2];
+
+            /* just check for validity */
+            (void)Strings::tolong(params[2]);
+        }    
+        else
+        {
+            LOG(ERROR, D("Invalid number of arguments!"));
+            return;
+        }
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            LOG(ERROR, D("ERROR: Invalid device number '%d'!") % dev);
+            return;
+        }
+
+        if (!Globals::k3lapi.valid_channel(dev, obj))
+        {
+            LOG(ERROR, D("ERROR: Invalid channel number '%d' on device '%d'!") % obj % dev);
+            return;
+        }
+
+        if(!Board::get(dev, obj)->application(SELECT_SIM_CARD, NULL, num.c_str()))
+        {
+            LOG(ERROR, D("ERROR: Unable to select sim card"));
+        }
+    }
+    catch (Strings::invalid_value & e)
+    {
+        LOG(ERROR, D("invalid numeric value: %s") % e.value());
+    }
+    catch(...)
+    {
+        LOG(ERROR, D("ERROR: Unable to select sim card"));
+    }
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_khomp_load)
+{
+    /* start log early */
+    if(!K::Logger::start())
+    {
+        return SWITCH_STATUS_FALSE;
+    }
+
+    /* Two bodies can not occupy the same space at the same time */ 
+    if(switch_loadable_module_exists("mod_kommuter") == SWITCH_STATUS_SUCCESS)
+    {   
+        LOG(ERROR, D("Kommuter module for FreeSWITCH is already loaded."));
+        return SWITCH_STATUS_FALSE;
+    } 
+
+    //TODO: must put the autorevision variable here
+    LOG(MESSAGE, "loading Khomp module");
+
+    /* get a reference for the module pool */
+    Globals::module_pool = pool;
+
+    /* start config system! */
+    Opt::initialize();
+
+    if(!Board::initializeK3L())
+    {
+        return SWITCH_STATUS_TERM;
+    }
+
+    /* read configuration first */
+    Opt::obtain();
+
+    /*
+       Spawn our k3l global var that will be used along the module
+       for sending info to the boards
+    */
+
+    if(!Board::initialize())
+    {
+        LOG(ERROR, "Error while initialize Board struct");
+        return SWITCH_STATUS_TERM;
+    }
+
+    /* apply global volume now */
+    if(Opt::_input_volume != 0 || Opt::_output_volume != 0)
+        Board::applyGlobalVolume();
+
+    Opt::commit();
+
+    /* create module interface, set state handlers and give a name */
+    *module_interface = switch_loadable_module_create_module_interface(pool, "mod_khomp");
+    Globals::khomp_endpoint_interface = static_cast<switch_endpoint_interface_t*>(switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE));
+    Globals::khomp_endpoint_interface->interface_name = "khomp";
+    Globals::khomp_endpoint_interface->io_routines = &khomp_io_routines;
+    Globals::khomp_endpoint_interface->state_handler = &khomp_state_handlers;
+
+
+    Globals::khomp_sms_endpoint_interface = static_cast<switch_endpoint_interface_t*>(switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE));
+    Globals::khomp_sms_endpoint_interface->interface_name = "khomp_SMS";
+    Globals::khomp_sms_endpoint_interface->io_routines = &khomp_sms_io_routines;
+    Globals::khomp_sms_endpoint_interface->state_handler = &khomp_sms_state_handlers;
+    
+    Globals::khomp_pr_endpoint_interface = static_cast<switch_endpoint_interface_t*>(switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE));
+    Globals::khomp_pr_endpoint_interface->interface_name = "khomp_PR";
+    Globals::khomp_pr_endpoint_interface->io_routines = &khomp_pr_io_routines;
+    Globals::khomp_pr_endpoint_interface->state_handler = &khomp_pr_state_handlers;
+
+    /* Register cli commands */
+    Cli::registerCommands(apiKhomp,module_interface);
+
+    /* Add applications */
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KLog", "KLog", "KLog log every string to khomp log system", klogFunction, "<value>", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KDTMFSuppression", "KDTMFSuppression", "KDTMFSuppresion", kdtmfSuppressionFunction, "on|off", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KEchoCanceller", "KEchoCanceller", "KEchoCanceller", kechoCancellerFunction, "on|off", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KAutoGainControl", "KAutoGainControl", "KAutoGainControl", kautoGainControlFunction, "on|off", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KSetVolume", "KSetVolume", "KSetVolume", ksetVolumeFunction, "value|value", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KR2SendCondition", "KR2SendCondition", "KR2SendCondition", kr2SendConditionFunction, "value|value", SAF_SUPPORT_NOMEDIA);
+    
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KAdjustForFax", "KAdjustForFax", "KAdjustForFax", kadjustForFaxFunction, "", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KSendFax", "KSendFax", "KSendFax", ksendFaxFunction, "<infilename>[:<infilename2>[:...]][|<faxid>]", SAF_SUPPORT_NOMEDIA);
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KReceiveFax", "KReceiveFax", "KReceiveFax", kreceiveFaxFunction, "<outfilename>[|<faxid>]", SAF_SUPPORT_NOMEDIA);
+    
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KUserTransfer", "KUserTransfer", "KUserTransfer", kUserTransferFunction, "number", SAF_SUPPORT_NOMEDIA);
+    
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KSendSMS", "KSendSMS", "KSendSMS", kSendSMSFunction, "resource|destination|message", SAF_SUPPORT_NOMEDIA);
+
+    SWITCH_ADD_APP(Globals::khomp_app_inteface, "KSelectSimCard", "KSelectSimCard", "KSelectSimCard", kSelectSimCardFunction, "<board>|<channel>|<sim_card>", SAF_SUPPORT_NOMEDIA);
+
+    Board::initializeHandlers();
+
+    Board::kommuter.start();
+
+    /* indicate that the module should continue to be loaded */
+    return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_khomp_shutdown)
+{
+    Board::kommuter.stop();
+
+    Cli::unregisterCommands();
+
+    /* Finnish him! */
+    DBG(FUNC, "Unloading mod_khomp...")
+
+    Board::finalizeHandlers();
+
+    Board::finalize();
+    
+    DBG(FUNC, "Successfully Unloaded mod_khomp")
+
+    K::Logger::stop();
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+/*!
+   \brief khomp API definition
+   TODO: Add as xml modifier
+*/
+SWITCH_STANDARD_API(apiKhomp)
+{
+    char *argv[10] = { 0 };
+    int argc = 0;
+    void *val;
+    char *myarg = NULL;
+    switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+    /* We should not ever get a session here */
+    if (session) return SWITCH_STATUS_FALSE;
+
+    /* Set the stream for Cli class */
+    Cli::setStream(stream);
+
+    if (zstr(cmd))
+    {
+        Cli::printKhompUsage();
+        return status;
+    }
+
+    if (!(myarg = strdup(cmd))) return SWITCH_STATUS_MEMERR;
+
+
+    if ((argc = switch_separate_string(myarg, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
+        Cli::printKhompUsage();
+        goto done;
+    }
+
+    /* Parse all commands */
+    Cli::parseCommands(argc,argv);
+
+done:
+    switch_safe_free(myarg);
+    return status;
+}
+
+extern "C" void Kstdcall khompAudioListener (int32 deviceid, int32 objectid, byte * read_buffer, int32 read_size)
+{
+    try
+    {
+    
+    //If NULL get throws K3LAPI::invalid_channel exception.
+    Board::KhompPvt * pvt = Board::get(deviceid, objectid);
+
+    /* add listener audio to the read buffer */
+    if (!pvt->_reader_frames.give((const char *)read_buffer, read_size))
+    {
+        DBG(STRM, PVT_FMT(pvt->target(), "Reader buffer full (read_size: %d)") % read_size);
+    }
+
+    if (!pvt->call()->_flags.check(Kflags::STREAM_UP))
+    {
+        DBG(STRM, PVT_FMT(pvt->target(), "Stream not enabled, skipping write..."));
+        return;
+    }
+    
+    /* will be used below for CM_ADD_STREAM_BUFFER */
+    struct
+    {
+        const byte * buff;
+        size_t       size;
+    }
+    write_packet = { (const byte *)0, 0 };
+    
+    /* push audio from the write buffer */
+    switch_frame_t * fr = pvt->_writer_frames.pick();
+
+    if (!fr)
+    {
+        //Writer buffer empty!
+        DBG(STRM, PVT_FMT(pvt->target(), "Writer buffer empty (silence to board)"));
+
+        write_packet.buff = (const byte *) Board::_cng_buffer;
+        write_packet.size = (size_t)       Globals::boards_packet_size;
+
+        pvt->command(KHOMP_LOG, CM_ADD_STREAM_BUFFER,
+                (const char *)&write_packet);
+        return;
+    }
+
+
+    /* what is the frame type? */
+    switch (fr->flags)
+    {
+        case SFF_NONE:
+        {
+            write_packet.buff = (const byte *) fr->data;
+            write_packet.size = (size_t)       fr->datalen;
+
+
+            pvt->command(KHOMP_LOG, CM_ADD_STREAM_BUFFER,
+                    (const char *)&write_packet);
+
+            break;
+        }
+
+        case SFF_CNG:
+        {
+            write_packet.buff = (const byte *) Board::_cng_buffer;
+            write_packet.size = (size_t)       Globals::boards_packet_size;
+
+            pvt->command(KHOMP_LOG, CM_ADD_STREAM_BUFFER,
+                    (const char *)&write_packet);
+
+            break;
+        }
+
+        default:
+            DBG(FUNC, PVT_FMT(pvt->target(), "DROPPING AUDIO..."));
+            /* TODO: log something here... */
+            break;
+    }
+
+    }
+    catch (K3LAPI::invalid_channel & err)
+    {
+        LOG(ERROR, OBJ_FMT(deviceid, objectid, "Invalid channel..."));
+        return;
+    }
+    catch (...)
+    {
+        LOG(ERROR, OBJ_FMT(deviceid, objectid, "Unexpected error..."));
+        return;
+    }
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */
diff --git a/src/mod/endpoints/mod_khomp/src/applications.cpp b/src/mod/endpoints/mod_khomp/src/applications.cpp
new file mode 100644 (file)
index 0000000..3826431
--- /dev/null
@@ -0,0 +1,968 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "applications.h"
+#include "lock.h"
+
+bool Fax::adjustForFax()
+{
+    /* Don't worry, let the man work */
+    DBG(FUNC, PVT_FMT(_pvt->target(),"Channel is now being adjusted for fax!"));
+    
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        _pvt->echoCancellation(false);
+        _pvt->dtmfSuppression(false);
+        _pvt->autoGainControl(false);
+
+        _pvt->call()->_input_volume = 0;
+        _pvt->setVolume("input" , 0);
+        _pvt->call()->_output_volume = 0;
+        _pvt->setVolume("output", 0);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool Fax::sendFax(switch_core_session_t * session, const char *data)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "c (%s)") % data);
+
+    try
+    {
+        switch_channel_t *channel = _pvt->getFSChannel(session);
+
+        switch_channel_set_variable(channel, "KFaxSent", "no");
+        switch_channel_set_variable(channel, "KFaxResult", "none");
+
+        std::string           fax_string((const char *)data);
+        Strings::vector_type  fax_args;
+        Strings::vector_type  fax_files;
+
+        Strings::tokenize(fax_string, fax_args, "|,");
+
+        if(fax_args.size() != 1 && fax_args.size() != 2)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (invalid string '%s': wrong number of separators.)") % fax_string);
+            return false;
+        }
+
+        Strings::tokenize(fax_args[0], fax_files, ":");
+
+        if(fax_files.size() <= 0)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (invalid string '%s': wrong number of separators.)") % fax_string);
+            return false;
+        }
+
+        ScopedPvtLock lock(_pvt);
+
+        std::string id;
+        
+        if(fax_args.size() == 2)
+        {
+            id = fax_args[1];
+        }
+        else if(!_pvt->call()->_orig_addr.empty())
+        {
+            id = _pvt->call()->_orig_addr;
+        }
+
+        const char * orig_addr = id.empty() ? NULL : id.c_str();
+
+        int timeout = 5;
+
+        if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
+            return false;
+        
+        if(!startFaxTX(orig_addr))
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to start send fax)"));
+            return false;
+        }
+
+        for(unsigned int i = 0; i < fax_files.size() ; ++i)
+        {
+            if (!addFaxFile(fax_files[i].c_str(), (i == fax_files.size()-1)? true : false))
+            {
+                DBG(FUNC, D("unable to add fax file='%s'")
+                        % fax_files[i].c_str());
+            }
+        }
+        
+        _fax_cond.reset();
+
+        lock.unlock();
+
+        _fax_cond.wait();
+        
+        switch_channel_set_variable(channel, "KFaxSent", ((_fax_result == kfaxrEndOfTransmission) ? "yes" : "no"));
+        switch_channel_set_variable(channel, "KFaxResult", (Verbose::faxResult((KFaxResult)_fax_result).c_str()));
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (%s)") % err._msg.c_str());
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
+    return true;
+}
+
+
+bool Fax::receiveFax(switch_core_session_t * session, const char *data)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "c (%s)") % data);
+
+    try
+    {
+        switch_channel_t *channel = _pvt->getFSChannel(session);
+
+        switch_channel_set_variable(channel, "KFaxReceived", "no");
+        switch_channel_set_variable(channel, "KFaxResult", "none");
+
+        std::string          fax_string((const char *)data);
+        Strings::vector_type fax_args;
+
+        Strings::tokenize(fax_string, fax_args, "|,");
+
+        if(fax_args.size() != 1 && fax_args.size() != 2)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (invalid string '%s': wrong number of separators.)") % fax_string);
+            return false;
+        }
+
+        ScopedPvtLock lock(_pvt);
+
+        std::string id;
+
+        if(fax_args.size() == 2)
+        {
+            id = fax_args[1];
+        }
+        else if(!_pvt->call()->_dest_addr.empty())
+        {
+            id = _pvt->call()->_dest_addr;
+        }
+
+        const char * orig_addr = id.empty() ? NULL : id.c_str();
+
+        int timeout = 5;
+
+        if(!_pvt->call()->_flags.check(Kflags::REALLY_CONNECTED) && !_pvt->loopWhileFlagTimed(Kflags::REALLY_CONNECTED, timeout, false))
+            return false;
+
+        if(!startFaxRX(fax_args[0].c_str(), orig_addr))
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to start receive fax)"));
+            return false;
+        }
+        
+        _fax_cond.reset();
+
+        lock.unlock();
+
+        _fax_cond.wait();
+
+        switch_channel_set_variable(channel, "KFaxReceived", ((_fax_result == kfaxrEndOfReception) ? "yes" : "no"));
+        switch_channel_set_variable(channel, "KFaxResult", (Verbose::faxResult((KFaxResult)_fax_result).c_str()));
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to lock: %s!)") %  err._msg.c_str());
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (%s)") % err._msg.c_str());
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
+
+    return true;
+}
+
+bool Fax::onFaxChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "c"));
+
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        if (_pvt->call()->_flags.check(Kflags::FAX_SENDING))
+        {
+            _pvt->call()->_flags.clear(Kflags::FAX_SENDING);
+
+            /* make audio come back.. */
+            _pvt->startStream(false);
+            _pvt->startListen();
+        }
+        else if (_pvt->call()->_flags.check(Kflags::FAX_RECEIVING))
+        {
+            _pvt->call()->_flags.clear(Kflags::FAX_RECEIVING);
+
+            /* make audio come back.. */
+            _pvt->startStream(false);
+            _pvt->startListen();
+        }
+
+        _fax_result = (KFaxResult)e->AddInfo;
+
+        _fax_cond.signal();
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (unable to lock %s!)") % err._msg.c_str());
+        return false;
+    };
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "r"));
+
+    return true;
+}
+
+bool Fax::startFaxTX(const char * orig_addr)
+{
+    /* no audio after this point, so stop streams! */
+    _pvt->stopStream(false);
+    _pvt->stopListen();
+
+    std::string id;
+
+    if(orig_addr)
+        id = STG(FMT("orig_addr=\"%s\"") % orig_addr);
+
+    const char * param = id.empty() ? NULL : id.c_str();
+
+
+    if (!_pvt->command(KHOMP_LOG, CM_START_FAX_TX, param))
+    {
+        _pvt->startStream(false);
+        _pvt->startListen();
+        return false;
+    }
+
+    _pvt->call()->_flags.set(Kflags::FAX_SENDING);
+
+    return true;
+
+}
+
+bool Fax::stopFaxTX(void)
+{
+    /* EV_FAX_CHANNEL_FREE , EV_FAX_FILE_FAIL */
+    if (!_pvt->command(KHOMP_LOG, CM_STOP_FAX_TX))
+        return false;
+
+    _pvt->call()->_flags.clear(Kflags::FAX_SENDING);
+
+    /* make audio come back.. */
+    _pvt->startStream(false);
+    _pvt->startListen();
+
+    return true;
+}
+
+
+
+bool Fax::startFaxRX(const char * filename, const char * orig_addr)
+{
+    if(!filename)
+        return false;
+
+    std::string param = STG(FMT("filename=\"%s\"") % filename);
+
+    if(orig_addr)
+        param += STG(FMT(" orig_addr=\"%s\"") % orig_addr);
+
+    /* no audio after this point, so stop streams! */
+    _pvt->stopStream(false);
+    _pvt->stopListen();
+
+    if (!_pvt->command(KHOMP_LOG, CM_START_FAX_RX, param.c_str()))
+    {
+        _pvt->startStream(false);
+        _pvt->startListen();
+        return false;
+    }
+
+    _pvt->call()->_flags.set(Kflags::FAX_RECEIVING);
+
+    return true;
+}
+
+bool Fax::stopFaxRX()
+{
+    /* Events: EV_FAX_CHANNEL_FREE */
+    if (!_pvt->command(KHOMP_LOG, CM_STOP_FAX_RX))
+        return false;
+
+    _pvt->call()->_flags.clear(Kflags::FAX_RECEIVING);
+
+    /* make audio come back.. */
+    _pvt->startStream(false);
+    _pvt->startListen();
+
+    return true;
+}
+
+bool Fax::addFaxFile(const char * filename, bool last)
+{
+    /* Events: EV_FAX_FILE_SENT , EV_FAX_FILE_FAIL , EV_FAX_TX_TIMEOUT */
+    if(!filename)
+        return false;
+
+    std::string params = STG(FMT("filename=\"%s\" last=\"%s\"") % filename
+            % (last ? "true": "false"));
+
+    if (!_pvt->command(KHOMP_LOG, CM_ADD_FAX_FILE, params.c_str()))
+        return false;
+
+    return true;
+}
+
+/******************************************************************************/
+bool SMS::justAlloc(unsigned int count)
+{
+    /* incoming contexts */
+    Board::KhompPvt::ContextListType contexts;
+
+    contexts.push_back(Opt::_context_gsm_sms);
+
+    /* temporary variables */
+    std::string context;
+    std::string exten;
+
+    K3L_DEVICE_CONFIG & dev_cfg = Globals::k3lapi.device_config(_pvt->_target.device);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++)
+    {
+        replaceTemplate((*i), "DD", _pvt->_target.device);
+        replaceTemplate((*i), "CC", _pvt->_target.object);
+        replaceTemplate((*i), "SSSS", atoi(dev_cfg.SerialNumber));
+    }
+
+    switch(_pvt->findExtension(exten, context, contexts, _got_sms._type, _got_sms._from, false, true))
+    {
+    case MATCH_NONE:
+        if( _got_sms._type != "broadcast")
+        {
+            LOG(WARNING, PVT_FMT(_pvt->target(), "unable to find context/exten for incoming SMS (s/%s), processing disabled for this channel.")
+                    % (contexts.size() >= 1 ? contexts[0] : "default"));
+
+        }
+
+        return false;
+
+    default:
+        DBG(FUNC, PVT_FMT(_pvt->target(), "our: context '%s', exten '%s'") % context % exten);
+        break;
+    }
+
+    for(unsigned int c = 0; c < count; c++)
+    {
+
+#if SWITCH_LESS_THAN(1,0,6)
+        switch_core_session_t *session = switch_core_session_request(Globals::khomp_sms_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL);
+#else
+        switch_core_session_t *session = switch_core_session_request(Globals::khomp_sms_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL);
+#endif
+
+        if(!session)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "Initilization Error, session not created!"));
+            return false;
+        }
+
+        switch_core_session_add_stream(session, NULL);
+
+        switch_core_session_set_private(session, _pvt);
+
+        switch_caller_profile_t *caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+                "Khomp_SMS",                       //username
+                "XML",                             //dialplan
+                NULL,                              //caller_id_name
+                _got_sms._from.c_str(),            //caller_id_number
+                NULL,                              //network_addr
+                _got_sms._from.c_str(),            //ani
+                NULL,                              //aniii
+                NULL,                              //rdnis
+                (char *) "mod_khomp",              //source
+                context.c_str(),                   //context
+                exten.c_str());                    //destination_number
+
+        if(!caller_profile)
+        {
+            _pvt->destroy(session);        
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (Cannot create caller profile)"));
+            return false;
+        }
+
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+
+        if(!channel)
+        {
+            _pvt->destroy(session);
+            LOG(ERROR, PVT_FMT(_pvt->target(), "r (Cannot get channel)"));
+            return false;
+        }
+
+        std::string name = STG(FMT("Khomp_SMS/%hu/%hu")
+                % _pvt->target().device
+                % _pvt->target().object);
+
+        switch_channel_set_name(channel, name.c_str());
+        switch_channel_set_caller_profile(channel, caller_profile);
+    
+        //DBG(FUNC, PVT_FMT(_pvt->target(), "Connect inbound SMS channel %s") % name.c_str());
+
+        switch_channel_set_state(channel, CS_INIT);
+
+
+        _owners.push_front(session);
+    }
+    
+    return true;
+}
+
+bool SMS::justStart()
+{
+    OwnersList::iterator i = _owners.begin();
+
+    if(i == _owners.end())
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "Cannot get session"));
+        return false;
+    }
+
+    switch_core_session_t *session = (*i);
+
+    _owners.pop_front();
+
+    if(!session)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "Cannot get session"));
+        return false;
+    }
+
+    switch_channel_t *channel = switch_core_session_get_channel(session);
+
+    if(!channel)
+    {
+        _pvt->destroy(session);
+        LOG(ERROR, PVT_FMT(_pvt->target(), "r (Cannot get channel)"));
+        return false;
+    }
+
+    switch_channel_set_variable(channel, "KSmsType", _got_sms._type.c_str());
+
+    if (_got_sms._type == "message" || _got_sms._type == "confirm")
+    {
+        switch_channel_set_variable(channel, "KSmsFrom", _got_sms._from.c_str());
+        switch_channel_set_variable(channel, "KSmsDate", _got_sms._date.c_str());
+    }
+
+    if(_got_sms._type == "confirm")
+    {
+        switch_channel_set_variable(channel, "KSmsDelivery", _got_sms._sc_date.c_str());
+        switch_channel_set_variable(channel, "KSmsStatus", _got_sms._status.c_str());
+    }
+    else
+    {
+        if(_got_sms._type == "broadcast")
+        {
+            switch_channel_set_variable(channel, "KSmsSerial", _got_sms._serial.c_str());
+            switch_channel_set_variable(channel, "KSmsPage", _got_sms._page.c_str());
+            switch_channel_set_variable(channel, "KSmsPages", _got_sms._pages.c_str());
+        }
+        switch_channel_set_variable(channel, "KSmsSize", _got_sms._size.c_str());
+        switch_channel_set_variable(channel, "KSmsMode", _got_sms._coding.c_str());
+        switch_channel_set_variable(channel, "KSmsBody", _got_sms._body.c_str());
+    }
+
+
+    if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS)
+    {
+        _pvt->destroy(session);
+        LOG(ERROR, PVT_FMT(_pvt->target(), "Error spawning thread"));
+        return false;
+    }
+
+    return true;
+}
+
+bool SMS::sendSMS(switch_core_session_t * session, const char *data)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) c"));
+
+    volatile bool finished = false;
+    volatile KGsmCallCause result = kgccNone; 
+
+    try
+    {
+        //ScopedAllocLock alloc_lock;
+
+        if(!_can_send)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (cannot send SMS messages, modem NOT initialized!)"));
+            return false;
+        }
+
+        std::string           sms_string((const char *)data);
+        Strings::vector_type  sms_args;
+
+        Strings::tokenize(sms_string, sms_args, "/|,", 3);
+
+        if (sms_args.size() != 3)
+        {
+            LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (invalid dial string '%s': wrong number of separators.)") % sms_string);
+            return false;
+        }
+
+        std::string dest(sms_args[1]);
+
+        bool conf = false;
+
+        if (dest[0] == '!')
+        {
+            dest.erase(0,1);
+            conf = true;
+        }
+
+        if (dest[dest.size()-1] == '!')
+        {
+            dest.erase(dest.size()-1,1);
+            conf = true;
+        }
+
+        // get options/values 
+        
+        _send_sms._dest = dest;
+        _send_sms._conf = conf;
+        _send_sms._body = sms_args[2];
+
+        Request request_sms(_send_sms, &finished, &result);
+
+        _mutex.lock();
+        bool status = _buffer.provide(request_sms);
+        _mutex.unlock();
+
+        _pvt->_mutex.unlock();
+
+        if(status)
+            _cond.signal();
+    
+        while (!finished)
+        {
+            usleep(200000);
+        }
+
+        _pvt->_mutex.lock();
+
+        switch_channel_t *channel = _pvt->getFSChannel(session);
+
+        switch_channel_set_variable(channel, "KSmsDelivered", ((KGsmSmsCause)result == ((KGsmSmsCause)0) ? "yes" : "no"));
+        switch_channel_set_variable(channel, "KSmsErrorCode", STG(FMT("%d") % result).c_str());
+        switch_channel_set_variable(channel, "KSmsErrorName", ((KGsmSmsCause)result == ((KGsmSmsCause)0) ? "None" : Verbose::gsmSmsCause((KGsmSmsCause)result).c_str()));
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (unable to global alloc lock)"));
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) %s") % err._msg.c_str());
+        //return false;
+    }
+
+    bool ret = ((KGsmSmsCause)result == ((KGsmSmsCause)0));
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) r (%s)") % (ret ? "true" : "false"));
+
+    //return (KGsmSmsCause)result;
+    return ret;
+}
+
+bool SMS::onNewSMS(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        if(!_can_receive)
+        {
+            DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) received new SMS message(s), but receiving is disabled. keeping the message(s) at the SIM card."));
+            ret = false;
+        }
+        else if(!justAlloc(e->AddInfo))
+        {
+            LOG(WARNING, PVT_FMT(_pvt->target(), "(SMS) unable to allocate channel for new SMS message(s). disabling processing to prevent messages from being lost."));
+            _can_receive = false;
+            ret = false;
+        }
+        else
+        {
+
+            DBG(FUNC, PVT_FMT(_pvt->target(), "downloading %d SMS message(s) on the SIM card.") % e->AddInfo);
+
+            _pvt->command(KHOMP_LOG, CM_GET_SMS);
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) r"));
+
+    return ret;
+}
+
+bool SMS::onSMSInfo(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) c"));
+
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        Globals::k3lapi.get_param(e, "sms_type",    _got_sms._type);
+        Globals::k3lapi.get_param(e, "sms_from",    _got_sms._from);
+        Globals::k3lapi.get_param(e, "sms_date",    _got_sms._date);
+        Globals::k3lapi.get_param(e, "sms_size",    _got_sms._size);
+        Globals::k3lapi.get_param(e, "sms_coding",  _got_sms._coding);
+        Globals::k3lapi.get_param(e, "sms_serial",  _got_sms._serial);
+        Globals::k3lapi.get_param(e, "sms_id",      _got_sms._id);
+        Globals::k3lapi.get_param(e, "sms_page",    _got_sms._page);
+        Globals::k3lapi.get_param(e, "sms_pages",   _got_sms._pages);
+        Globals::k3lapi.get_param(e, "sms_sc_date", _got_sms._sc_date);
+        Globals::k3lapi.get_param(e, "sms_status",  _got_sms._status);
+
+        //DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) type=%s from=%s date=%s size=%s coding=%s serial=%s id=%s page=%s pages=%s sc_date=%s status=%s") % _got_sms._type % _got_sms._from % _got_sms._date % _got_sms._size % _got_sms._coding % _got_sms._serial % _got_sms._id % _got_sms._page % _got_sms._pages % _got_sms._sc_date % _got_sms._status);
+
+        if (_owners.empty() && !justAlloc(1) && (_got_sms._type.compare("broadcast") != 0))
+        {
+            // this error is fatal
+            LOG(ERROR, PVT_FMT(_pvt->target(), "unable to allocate channel, new SMS message from %s will not be sent to dialplan!") % _got_sms._from);
+            return false;
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) r"));
+
+    return true;
+}
+
+bool SMS::onSMSData(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) c"));
+
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        if (_owners.empty())
+        {
+            if(_got_sms._type != "broadcast")
+            {
+                LOG(WARNING, PVT_FMT(_pvt->target(), "unable to allocate channel for new SMS message(s). disabling processing to prevent messages from being lost."));
+                _can_receive = false;
+            }
+        }
+        else
+        {
+            _got_sms._body = (const char *)(e->Params ? e->Params : "");
+
+            if(!justStart())
+            {
+                if(_got_sms._type != "broadcast")
+                {
+                    LOG(ERROR, PVT_FMT(_pvt->target(), "unable to receive SMS from '%s', something wrong!") % _got_sms._from);
+                    LOG(ERROR, PVT_FMT(_pvt->target(), "disabling SMS processing to prevent messages from being lost."));
+    
+                    _can_receive = false;
+                }
+            }
+        }
+        
+        if(_can_receive)
+        {
+            /* stats update! */
+            if(_got_sms._type == "message")
+            {
+                statistics<SMSStatistics>()->incrementIncoming();
+            }
+            else if(_got_sms._type == "confirm")
+            {
+                statistics<SMSStatistics>()->incrementConfirm();
+            }
+            else
+            {
+                statistics<SMSStatistics>()->incrementBroadcast();
+            }
+        }
+   
+        /* reset data stuff */
+        _got_sms.clear();
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) r"));
+    return true;
+}
+
+bool SMS::onSMSSendResult(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) c"));
+
+    try
+    {
+        ScopedPvtLock lock(_pvt);
+
+        _result = (KGsmCallCause)e->AddInfo;
+        _pvt->call()->_flags.clear(Kflags::SMS_DOING_UPLOAD);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_pvt->target(), "(SMS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_pvt->target(), "(SMS) r"));
+
+    return true;
+}
+
+int SMS::smsThread(void * sms_ptr)
+{
+    SMS * sms = static_cast < SMS * > (sms_ptr);
+    
+    Board::KhompPvt * pvt = static_cast < Board::KhompPvt * > (sms->_pvt);
+
+    DBG(THRD, PVT_FMT(pvt->target(), "c"));
+
+    bool loop = true;
+
+    while(loop)
+    {
+        if(sms->_cond.wait(1000))
+        {
+            if(sms->_shutdown)
+                return 0;
+        }
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            K3L_CHANNEL_STATUS status;
+
+            KLibraryStatus ret = (KLibraryStatus) k3lGetDeviceStatus(
+                    pvt->_target.device,
+                    pvt->_target.object + ksoChannel,
+                    &status,
+                    sizeof(status));
+
+            if (ret == ksSuccess)
+            {
+                switch (status.AddInfo)
+                {
+                    case kgsmModemError:
+                    case kgsmSIMCardError:
+                        return 0;
+
+                    case kgsmIdle:
+                    {
+                        /* pede registro do canal.. */
+                        pvt->command(KHOMP_LOG, CM_SEND_TO_MODEM, "AT+COPS?");
+
+                        /* pede estado da antena.. */
+                        pvt->command(KHOMP_LOG, CM_SEND_TO_MODEM, "AT+CSQ?");
+
+                        /* forca tipo padrao a ser message... */
+                        sms->_got_sms._type = "message";
+
+                        /* pre-aloca canal para receber mensagens SMS. */
+                        if (sms->justAlloc())
+                        {
+                            /* habilita processamento de SMSs entrantes */
+                            sms->_can_receive = true;
+
+                            /* envia comando para "limpar" SMSs do SIM card */
+                            pvt->command(KHOMP_LOG, CM_CHECK_NEW_SMS);
+                        }
+
+                        sms->_got_sms.clear();
+
+                        /* sai fora do loop! */
+                        loop = false;
+                    }
+                    default:
+                        break;
+                }
+            }
+        }
+        catch (ScopedLockFailed & err)
+        {
+            DBG(FUNC, PVT_FMT(pvt->_target, "unable to obtain lock: %s") % err._msg.c_str());
+        }
+
+    }
+
+    sms->_can_send = true;
+
+    while(true)
+    {
+        Request request_sms;
+
+        DBG(THRD, PVT_FMT(pvt->_target, "begin"));
+
+        while(!sms->_buffer.consume(request_sms))
+        {
+            DBG(THRD, PVT_FMT(pvt->_target, "buffer empty"));
+
+            sms->_cond.wait();
+
+            DBG(THRD, PVT_FMT(pvt->_target, "waked up!"));
+
+            if(sms->_shutdown)
+                return 0;
+        }
+
+        DBG(THRD, PVT_FMT(pvt->_target, "processing buffer..."));
+
+        try
+        {
+            int timeout = 30;
+
+            ScopedPvtLock lock(pvt);
+
+            pvt->call()->_flags.set(Kflags::SMS_DOING_UPLOAD);
+
+            if (pvt->command(KHOMP_LOG, CM_PREPARE_SMS, request_sms._send_sms._body.c_str()))
+            {
+                std::string extra = (request_sms._send_sms._conf ? " sms_confirm=\"TRUE\"" : "");
+
+                if (pvt->command(KHOMP_LOG, CM_SEND_SMS,
+                            STG(FMT("sms_to=\"%s\"%s") % request_sms._send_sms._dest % extra).c_str()))
+                {
+                    if (!pvt->loopWhileFlagTimed(Kflags::SMS_DOING_UPLOAD, timeout))
+                        break;
+                }
+                else
+                {
+                    sms->_result = kgccResourceUnavailable;
+                }
+            }
+            else
+            {
+                sms->_result = kgccInvalidMessage;
+            }
+            
+            pvt->call()->_flags.clear(Kflags::SMS_DOING_UPLOAD);
+
+            if (request_sms._cause)
+                *(request_sms._cause) = (KGsmCallCause)sms->_result;
+
+            if (request_sms._finished)
+                *(request_sms._finished) = true;
+
+            if (sms->_result == kgccNone)
+            {
+                /* stats update if sent! */
+                sms->statistics<SMSStatistics>()->incrementOutgoing();
+            }
+
+            sms->_send_sms.clear();
+
+        }
+        catch (ScopedLockFailed & err)
+        {
+            DBG(FUNC, PVT_FMT(pvt->_target, "unable to obtain lock: %s") % err._msg.c_str());
+        }
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "ok, going to loop..."));
+
+    }
+
+
+    DBG(FUNC, PVT_FMT(pvt->target(), "r"));
+
+    return 0;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/cli.cpp b/src/mod/endpoints/mod_khomp/src/cli.cpp
new file mode 100644 (file)
index 0000000..709abb9
--- /dev/null
@@ -0,0 +1,2408 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "cli.h"
+#include "k3l.h"
+#include "lock.h"
+#include "khomp_pvt.h"
+#include "spec.h"
+
+/* our stream and interface handlers */
+switch_stream_handle_t *Cli::stream;
+switch_loadable_module_interface_t **Cli::module_interface;
+
+/* contains all commands */
+Cli::Commands Cli::_commands;
+
+/* khomp all commands usage */
+std::string Cli::_khomp_usage;
+
+/* register our commands, but you must create the command function */
+void Cli::registerCommands(APIFunc func,switch_loadable_module_interface_t **mod_int)
+{
+    if(!mod_int || !*mod_int)
+    {
+        LOG(ERROR,"Invalid module passed");
+        return;
+    }
+
+    /* the manual */
+    _khomp_usage =                                                             \
+"---------------------------------------------------------------------------\n"\
+"---------------------------------- HELP -----------------------------------\n"\
+"---------------------------------------------------------------------------\n"\
+" khomp channels disconnect {all | <board> all | <board> <channel>}\n"         \
+" khomp channels unblock {all | <board> all | <board> <channel>}\n"            \
+" khomp clear links [<board> [<link>]]\n"                                      \
+" khomp clear statistics [<board> [<channel>]]\n"                              \
+" khomp get <option>\n"                                                        \
+" khomp kommuter {on|off}\n"                                                   \
+" khomp kommuter count\n"                                                      \
+" khomp log console <options>\n"                                               \
+" khomp log disk <options>\n"                                                  \
+" khomp log rotate\n"                                                          \
+" khomp log status\n"                                                          \
+" khomp log trace isdn <what>[,<what2>[,..]]\n"                                \
+" khomp log trace k3l {on|off}\n"                                              \
+" khomp log trace r2 {on|off}\n"                                               \
+" khomp reset links [<board> [<link>]]\n"                                      \
+" khomp revision\n"                                                            \
+" khomp select sim <board> <channel> <sim_card>\n"                             \
+" khomp send command <board> <channel> <command> [argument]\n"                 \
+" khomp send raw command <board> <dsp> <c0> <c1> [...]\n"                      \
+" khomp set <option> <value>\n"                                                \
+" khomp show calls [<board> [<channel>]]\n"                                    \
+" khomp show channels [{<board> [<channel>]} | \n"                             \
+"                               {{concise|verbose} [<board> [<channel>]]}]\n"  \
+" khomp show links [[errors] [{<board>} | {{concise|verbose} [<board>]}]]\n"   \
+" khomp show statistics [{verbose [<board> [<channel>]]} | \n"                 \
+"                        {detailed <board> <channel>}]\n"                      \
+" khomp sms <device> <destination> <message..>\n"                              \
+" khomp summary [concise]\n"                                                   \
+"---------------------------------------------------------------------------\n\n";
+
+    /* we need this module_inteface, is used by SWITCH_ADD_API, there's no escape */
+    module_interface = mod_int;
+
+    /* khomp cli commands */
+    SWITCH_ADD_API(Globals::api_interface, "khomp", "Khomp Menu", func, _khomp_usage.c_str());
+
+    /* insert commands in list */
+    for(Commands::iterator itr = _commands.begin();itr != _commands.end();itr++)
+    {
+        switch_console_set_complete(STR(FMT("add khomp %s") % (*itr)->complete_name));
+
+        /* if we have options, let's insert them */
+        if((*itr)->options.size() > 0)
+        {
+            std::vector<std::string>::iterator itr_option = (*itr)->options.begin();
+            while(itr_option != (*itr)->options.end())
+            {
+                switch_console_set_complete(STR(FMT("add khomp %s %s") % (*itr)->complete_name % *itr_option));
+                itr_option++;
+            }
+        }
+    }
+}
+
+/* is responsible for parse and execute all commands */
+bool Cli::parseCommands(int argc, char *argv[])
+{
+    /* khomp summary */
+    if (ARG_CMP(0, "summary"))
+        return EXEC_CLI_CMD(Cli::KhompSummary);
+
+    /* khomp show */
+    else if(ARG_CMP(0, "show"))
+    {
+        /* khomp show calls */
+        if(ARG_CMP(1, "calls"))
+            return EXEC_CLI_CMD(Cli::KhompShowCalls);
+
+        /* khomp show channels */
+        if(ARG_CMP(1, "channels"))
+            return EXEC_CLI_CMD(Cli::KhompShowChannels);
+        
+        /* khomp show links */
+        if(ARG_CMP(1, "links"))
+            return EXEC_CLI_CMD(Cli::KhompShowLinks);
+
+        /* khomp show statistics */
+        if(ARG_CMP(1, "statistics"))
+            return EXEC_CLI_CMD(Cli::KhompShowStatistics);
+    }
+
+    /* khomp clear */
+    else if(ARG_CMP(0, "clear"))
+    {
+        /* khomp clear links */
+        if(ARG_CMP(1, "links"))
+            return EXEC_CLI_CMD(Cli::KhompClearLinks);
+
+        /* khomp clear statistics */
+        if(ARG_CMP(1, "statistics"))
+            return EXEC_CLI_CMD(Cli::KhompClearStatistics);
+    }
+    
+    /* khomp reset */
+    else if(ARG_CMP(0, "reset"))
+    {
+        /* khomp reset links */
+        if(ARG_CMP(1, "links"))
+            return EXEC_CLI_CMD(Cli::KhompResetLinks);
+
+    }
+    
+    /* khomp sms */
+    else if(ARG_CMP(0, "sms"))
+    {
+        return EXEC_CLI_CMD(Cli::KhompSMS);
+    }
+
+    /* khomp log */
+    else if(ARG_CMP(0, "log"))
+    {
+        /* khomp log console */
+        if(ARG_CMP(1, "console"))
+            return EXEC_CLI_CMD(Cli::KhompLogConsole);
+
+        /* khomp log  disk */
+        if(ARG_CMP(1, "disk"))
+            return EXEC_CLI_CMD(Cli::KhompLogDisk);
+
+        /* khomp log status */
+        if(ARG_CMP(1, "status"))
+            return EXEC_CLI_CMD(Cli::KhompLogStatus);
+
+        /* khomp log rotate */
+        if(ARG_CMP(1, "rotate"))
+            return EXEC_CLI_CMD(Cli::KhompLogRotate);
+
+        /* khomp log trace */
+        if(ARG_CMP(1, "trace"))
+        {
+            /* khomp log trace k3l */
+            if(ARG_CMP(2, "k3l"))
+                return EXEC_CLI_CMD(Cli::KhompLogTraceK3L);
+
+            /* khomp log trace isdn */
+            if(ARG_CMP(2, "isdn"))
+                return EXEC_CLI_CMD(Cli::KhompLogTraceISDN);
+
+            /* khomp log trace r2 */
+            if(ARG_CMP(2, "r2"))
+                return EXEC_CLI_CMD(Cli::KhompLogTraceR2);
+        }
+    }
+
+    /* khomp channels */
+    else if(ARG_CMP(0, "channels"))
+    {
+        /* khomp channels disconnect */
+        if(ARG_CMP(1, "disconnect"))
+            return EXEC_CLI_CMD(Cli::KhompChannelsDisconnect);
+
+        /* khomp channels unblock */
+        if(ARG_CMP(1, "unblock"))
+            return EXEC_CLI_CMD(Cli::KhompChannelsUnblock);
+    }
+
+    /* khomp get */
+    else if(ARG_CMP(0, "get"))
+        return EXEC_CLI_CMD(Cli::KhompGet);
+
+    /* khomp set */
+    else if(ARG_CMP(0, "set"))
+        return EXEC_CLI_CMD(Cli::KhompSet);
+
+    /* khomp reivision */
+    else if(ARG_CMP(0, "revision"))
+        return EXEC_CLI_CMD(Cli::KhompRevision);
+
+    /* khomp send */
+    else if(ARG_CMP(0, "send"))
+    {
+        /* khomp send command */
+        if(ARG_CMP(1, "command"))
+            return EXEC_CLI_CMD(Cli::KhompSendCommand);
+
+        /* khomp send raw */
+        if(ARG_CMP(1, "raw"))
+            return EXEC_CLI_CMD(Cli::KhompSendRawCommand);
+    }
+    
+    /* khomp select */
+    else if(ARG_CMP(0, "select"))
+    {
+        /* khomp select sim */
+        if(ARG_CMP(1, "sim"))
+            return EXEC_CLI_CMD(Cli::KhompSelectSim);
+
+    }
+
+    /* khomp kommuter */
+    else if(ARG_CMP(0, "kommuter"))
+    {
+        if(ARG_CMP(1, "on") || ARG_CMP(1, "off"))
+            return EXEC_CLI_CMD(Cli::KhompKommuterOnOff);
+        
+        if(ARG_CMP(1, "count"))
+            return EXEC_CLI_CMD(Cli::KhompKommuterCount);
+    }
+    
+    /* if everything fails, i'm here to support */
+    printKhompUsage();
+    
+    return false;
+}
+
+/******************************************************************************/
+/******************** Defining the static initialization **********************/
+
+Cli::_KhompSummary            Cli::KhompSummary;
+Cli::_KhompShowCalls          Cli::KhompShowCalls;
+Cli::_KhompShowChannels       Cli::KhompShowChannels;
+Cli::_KhompShowLinks          Cli::KhompShowLinks;
+Cli::_KhompShowStatistics     Cli::KhompShowStatistics;
+Cli::_KhompClearLinks         Cli::KhompClearLinks;
+Cli::_KhompClearStatistics    Cli::KhompClearStatistics;
+Cli::_KhompResetLinks         Cli::KhompResetLinks;
+Cli::_KhompChannelsDisconnect Cli::KhompChannelsDisconnect;
+Cli::_KhompChannelsUnblock    Cli::KhompChannelsUnblock;
+Cli::_KhompSMS                Cli::KhompSMS;
+Cli::_KhompLogConsole         Cli::KhompLogConsole;
+Cli::_KhompLogDisk            Cli::KhompLogDisk;
+Cli::_KhompLogStatus          Cli::KhompLogStatus;
+Cli::_KhompLogRotate          Cli::KhompLogRotate;
+Cli::_KhompLogTraceK3L        Cli::KhompLogTraceK3L;
+Cli::_KhompLogTraceISDN       Cli::KhompLogTraceISDN;
+Cli::_KhompLogTraceR2         Cli::KhompLogTraceR2;
+Cli::_KhompGet                Cli::KhompGet;
+Cli::_KhompSet                Cli::KhompSet;
+Cli::_KhompRevision           Cli::KhompRevision;
+Cli::_KhompSendCommand        Cli::KhompSendCommand;
+Cli::_KhompSendRawCommand     Cli::KhompSendRawCommand;
+Cli::_KhompSelectSim          Cli::KhompSelectSim;
+Cli::_KhompKommuterOnOff      Cli::KhompKommuterOnOff;
+Cli::_KhompKommuterCount      Cli::KhompKommuterCount;
+
+/******************************************************************************/
+/*************************** Defining the commands ****************************/
+/*!
+ \brief Print a system summary for all the boards. [khomp summary]
+ */
+bool Cli::_KhompSummary::execute(int argc, char *argv[])
+{
+    if(argc < 1 || argc > 2)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    /* show concise ? */
+    bool concise = ARG_CMP(1, "concise") ? true:false;
+
+    class_type classe = ( !_on_cli_term ? C_MESSAGE : C_CLI );
+    K3L_API_CONFIG apiCfg;
+
+    if (!concise)
+    {
+        K::Logger::Logg2(classe, stream, " ------------------------------------------------------------------");
+        K::Logger::Logg2(classe, stream, "|---------------------- Khomp System Summary ----------------------|");
+        K::Logger::Logg2(classe, stream, "|------------------------------------------------------------------|");
+    }
+
+    if (k3lGetDeviceConfig(-1, ksoAPI, &apiCfg, sizeof(apiCfg)) == ksSuccess)
+    {
+        if (concise)
+        {
+            K::Logger::Logg2(classe, stream, FMT("%d.%d.%d;%d;%s")
+                        % apiCfg.MajorVersion % apiCfg.MinorVersion % apiCfg.BuildVersion
+                        % apiCfg.VpdVersionNeeded % apiCfg.StrVersion);
+        }
+        else
+        {
+            K::Logger::Logg2(classe, stream, FMT("| K3L API %d.%d.%d [m.VPD %d] - %-38s |")
+                        % apiCfg.MajorVersion % apiCfg.MinorVersion % apiCfg.BuildVersion
+                        % apiCfg.VpdVersionNeeded % apiCfg.StrVersion);
+        }
+    }
+
+#ifndef MOD_KHOMP_VERSION
+#define MOD_KHOMP_VERSION "unknown"
+#endif
+
+#ifndef SWITCH_VERSION_FULL
+#define SWITCH_VERSION_FULL "unknown"
+#endif
+
+    std::string khomp_endpoint_rev(MOD_KHOMP_VERSION);
+    std::string freeswitch_rev(SWITCH_VERSION_FULL);
+
+    if (concise)
+    {
+        K::Logger::Logg2(classe, stream, FMT("%s") % khomp_endpoint_rev);
+        K::Logger::Logg2(classe, stream, FMT("%s") % freeswitch_rev);
+    }
+    else
+    {
+        K::Logger::Logg2(classe, stream, FMT("| Khomp Endpoint - %-47s |") % khomp_endpoint_rev);
+        K::Logger::Logg2(classe, stream, FMT("| FreeSWITCH - %-51s |") % freeswitch_rev);
+    }
+
+
+    for (unsigned int i = 0; i < Globals::k3lapi.device_count(); i++)
+    {
+        K3L_DEVICE_CONFIG & devCfg = Globals::k3lapi.device_config(i);
+
+        std::string tipo = Verbose::deviceName((KDeviceType)Globals::k3lapi.device_type(i), devCfg.DeviceModel);
+
+        if (!concise)
+            K::Logger::Logg2(classe, stream, " ------------------------------------------------------------------");
+
+        switch (Globals::k3lapi.device_type(i))
+        {
+            /* E1 boards */
+            case kdtE1:
+            case kdtConf:
+            case kdtPR:
+            case kdtE1GW:
+            case kdtE1IP:
+            case kdtE1Spx:
+            case kdtGWIP:
+            case kdtFXS:
+            case kdtFXSSpx:
+            case kdtE1FXSSpx:
+            {
+                K3L_E1600A_FW_CONFIG dspAcfg;
+                K3L_E1600B_FW_CONFIG dspBcfg;
+
+                if ((k3lGetDeviceConfig(i, ksoFirmware + kfiE1600A, &dspAcfg, sizeof(dspAcfg)) == ksSuccess) &&
+                    (k3lGetDeviceConfig(i, ksoFirmware + kfiE1600B, &dspBcfg, sizeof(dspBcfg)) == ksSuccess))
+                {
+                    if (concise)
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("%02u;%s;%d;%d;%d;%s;%s;%02d;%02d;%s;%s;%s;%s")
+                                    % i % tipo % atoi(devCfg.SerialNumber) % devCfg.ChannelCount % devCfg.LinkCount
+                                    % dspAcfg.DspVersion % dspBcfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % dspAcfg.FwVersion % dspBcfg.FwVersion
+                                    % Verbose::echoCancellerConfig(devCfg.EchoConfig)
+                                    % Verbose::echoLocation(devCfg.EchoLocation));
+                    }
+                    else
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("| [[ %02u ]] %s, serial '%s', %02d channels, %d links.%s|")
+                                    % i % tipo % devCfg.SerialNumber % devCfg.ChannelCount % devCfg.LinkCount
+                                    % std::string(std::max<int>(0, 22 - tipo.size() - strlen(devCfg.SerialNumber)), ' '));
+                        K::Logger::Logg2(classe, stream, FMT("| * DSP A: %s, DSP B: %s - PCI bus: %02d, PCI slot: %02d %s|")
+                                    % dspAcfg.DspVersion % dspBcfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % std::string(18 - strlen(dspAcfg.DspVersion) - strlen(dspBcfg.DspVersion), ' '));
+                        K::Logger::Logg2(classe, stream, FMT("| * %-62s |") % dspAcfg.FwVersion);
+                        K::Logger::Logg2(classe, stream, FMT("| * %-62s |") % dspBcfg.FwVersion);
+
+                        K::Logger::Logg2(classe, stream, FMT("| * Echo Canceller: %-20s - Location: %-12s  |")
+                                    % Verbose::echoCancellerConfig(devCfg.EchoConfig)
+                                    % Verbose::echoLocation(devCfg.EchoLocation));
+                    }
+                }
+
+                break;
+            }
+
+            /* analog boards */
+            case kdtFXO:
+            case kdtFXOVoIP:
+            /*
+            TODO: This not found
+            case kdtFX:
+            case kdtFXVoIP:
+            */
+            {
+                K3L_FXO80_FW_CONFIG dspCfg;
+
+                if (k3lGetDeviceConfig(i, ksoFirmware + kfiFXO80, &dspCfg, sizeof(dspCfg)) == ksSuccess)
+                {
+                    if (concise)
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("%02u;%s;%d;%d;%s;%02d;%02d;%s")
+                                    % i % tipo % atoi(devCfg.SerialNumber) % devCfg.ChannelCount
+                                    % dspCfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % dspCfg.FwVersion);
+                    }
+                    else
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("| [[ %02u ]] %s, serial '%s', %02d channels. %s|")
+                                    % i % tipo % devCfg.SerialNumber % devCfg.ChannelCount
+                                    % std::string(std::max<int>(0, 30 - tipo.size() - strlen(devCfg.SerialNumber)), ' '));
+                        K::Logger::Logg2(classe, stream, FMT("| * DSP: %s - PCI bus: %02d, PCI slot: %02d%s|")
+                                    % dspCfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % std::string(30 - strlen(dspCfg.DspVersion), ' '));
+                        K::Logger::Logg2(classe, stream, FMT("| * %-63s|") % dspCfg.FwVersion);
+                    }
+                }
+
+                if (Globals::k3lapi.device_type(i) == kdtFXOVoIP)
+                {
+                    if (!concise)
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("| * Echo Canceller: %-20s - Location: %-12s  |")
+                            % Verbose::echoCancellerConfig(devCfg.EchoConfig)
+                            % Verbose::echoLocation(devCfg.EchoLocation));
+                    }
+                }
+
+                break;
+            }
+            case kdtGSM:
+            case kdtGSMSpx:
+            {
+                K3L_GSM40_FW_CONFIG dspCfg;
+
+                if (k3lGetDeviceConfig(i, ksoFirmware + kfiGSM40, &dspCfg, sizeof(dspCfg)) == ksSuccess)
+                {
+                    if (concise)
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("%02d;%s;%d;%d;%s;%02d;%02d;%s")
+                                    % i % tipo % atoi(devCfg.SerialNumber) % devCfg.ChannelCount
+                                    % dspCfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % dspCfg.FwVersion);
+                    }
+                    else
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("| [[ %02d ]] %s, serial '%s', %02d channels. %s|")
+                            % i % tipo % devCfg.SerialNumber % devCfg.ChannelCount
+                            % std::string(std::max<int>(0, 30 - tipo.size() - strlen(devCfg.SerialNumber)), ' '));
+
+                        K::Logger::Logg2(classe, stream, FMT("| * DSP: %s - PCI bus: %02d, PCI slot: %02d%s|")
+                                    % dspCfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % std::string(std::max<int>(30 - strlen(dspCfg.DspVersion), 0), ' '));
+
+                        K::Logger::Logg2(classe, stream, FMT("| * %-62s |") % dspCfg.FwVersion);
+                    }
+                }
+
+                break;
+            }
+            case kdtGSMUSB:
+            case kdtGSMUSBSpx:
+            {
+                K3L_GSMUSB_FW_CONFIG dspCfg;
+
+                if (k3lGetDeviceConfig(i, ksoFirmware + kfiGSMUSB, &dspCfg, sizeof(dspCfg)) == ksSuccess)
+                {
+                    if (concise)
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("%02d;%s;%d;%d;%s;%02d;%02d;%s")
+                                    % i % tipo % atoi(devCfg.SerialNumber) % devCfg.ChannelCount
+                                    % dspCfg.DspVersion % devCfg.PciBus % devCfg.PciSlot
+                                    % dspCfg.FwVersion);
+                    }
+                    else
+                    {
+                        K::Logger::Logg2(classe, stream, FMT("| [[ %02d ]] %s, serial '%s', %02d channels. %s|")
+                            % i % tipo % devCfg.SerialNumber % devCfg.ChannelCount
+                            % std::string(std::max<int>(0, 30 - tipo.size() - strlen(devCfg.SerialNumber)), ' '));
+
+                        int size = strlen(dspCfg.DspVersion) + strlen(dspCfg.FwVersion);
+
+                        K::Logger::Logg2(classe, stream, FMT("| * DSP: %s - %s%s|")
+                            % dspCfg.DspVersion % dspCfg.FwVersion
+                            % std::string(std::max<int>(55 - size, 0), ' '));
+                    }
+                }
+
+                break;
+            }
+
+            default:
+                K::Logger::Logg2(classe, stream, FMT("| [[ %02d ]] Unknown type '%02d'! Please contact Khomp support for help! |")
+                    % i % Globals::k3lapi.device_type(i));
+                break;
+        }
+    }
+
+    if (!concise)
+        K::Logger::Logg2(classe,stream, " ------------------------------------------------------------------");
+
+    return true;
+}
+
+/* support function for _KhompShowCalls */
+void Cli::_KhompShowCalls::showCalls(unsigned int d, unsigned int o, std::string &buffer)
+{
+    buffer += STR(FMT("| %d,%02d |   unused   | %11s | %-36s |\n")
+             % d
+             % o
+             % Globals::k3lutil.callStatus(d,o)
+             % Globals::k3lutil.channelStatus(d,o));
+}
+
+bool Cli::_KhompShowCalls::execute(int argc, char *argv[])
+{
+    if(argc > 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    int device = argv[2] ? atoi(argv[2]) : -1; 
+    int object = argv[3] ? atoi(argv[3]) : -1; 
+
+    int d = -1;
+    int o = -1;
+
+    if (device != -1)
+    {    
+        d = device;
+
+        if (!Globals::k3lapi.valid_device(d))
+        {    
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such device %d!") % d);
+            return false;
+        }    
+    }   
+
+    if (object != -1)
+    {    
+        o = object;
+
+        if (!Globals::k3lapi.valid_channel(d,o))
+        {    
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such chanel %d for device %d!") % o % d);
+            return false;
+        }    
+    } 
+
+    /* keep the channels reponse */
+    std::string buffer("");
+
+    try
+    {
+        /**/ if (d != -1 && o != -1)
+        {    
+            showCalls(d,o,buffer);
+        }    
+        else if (d != -1 && o == -1)
+        {    
+            for (unsigned int i = 0; i < Globals::k3lapi.channel_count(d); i++) 
+            {    
+                buffer += " ------------------------------------------------------------------------\n";
+                showCalls(d,i,buffer);
+            }    
+        }    
+        else if (d == -1 && o == -1)
+        {    
+            for (unsigned int i = 0; i < Globals::k3lapi.device_count(); i++) 
+            {    
+                buffer += " ------------------------------------------------------------------------\n";
+                for (unsigned int j = 0; j < Globals::k3lapi.channel_count(i); j++)
+                {
+                    showCalls(i,j,buffer);
+                }
+            }    
+        }
+    }
+    catch(K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, "ERROR: No such chanel");
+        return false;
+    }
+
+    //TODO: The information shown here, must be reviewed cuz is the same of show channels
+    K::Logger::Logg2(C_CLI, stream, " ------------------------------------------------------------------------");
+    K::Logger::Logg2(C_CLI, stream, "|------------------------------- Khomp Calls ----------------------------|");
+    K::Logger::Logg2(C_CLI, stream, " ------------------------------------------------------------------------ ");
+    K::Logger::Logg2(C_CLI, stream, "|  hw  | freeSWITCH |  khomp call |             khomp channel            |");
+    K::Logger::Logg2(C_CLI, stream, "|  id  |   status   |    status   |                status                |");
+    K::Logger::Logg2(C_CLI, stream, "%s", (char*) buffer.c_str());
+    K::Logger::Logg2(C_CLI, stream, " ------------------------------------------------------------------------");
+
+    return true;
+}
+
+bool Cli::_KhompChannelsDisconnect::forceDisconnect(unsigned int device, unsigned int channel)
+{
+    bool ret = false;
+    Board::KhompPvt *pvt = NULL;
+
+    try
+    {
+        pvt = Board::get(device,channel);
+        ScopedPvtLock lock(pvt);
+
+        ret = pvt->command(KHOMP_LOG,CM_DISCONNECT);
+        DBG(FUNC,PVT_FMT(pvt->target(),"Command CM_DISCONNECT sent!"));
+    }
+    catch (K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+    }
+    catch (ScopedLockFailed & err)
+    {
+        K::Logger::Logg2(C_CLI,stream,FMT("error: channel %d at device %d could not be locked: %s!")
+        % channel 
+        % device
+        % err._msg.c_str());
+    }
+
+    return ret;
+}
+
+bool Cli::_KhompChannelsDisconnect::execute(int argc, char *argv[])
+{
+    if (argc < 3 || argc > 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    switch (argc)
+    {    
+        case 3:
+        {    
+            if (!ARG_CMP(2, "all"))
+            {    
+                K::Logger::Logg2(C_CLI, stream, "usage: khomp channels disconnect < all | <boardid> < all | <channelid> > >");
+                return false;
+            }    
+
+            K::Logger::Logg2(C_CLI, stream, "NOTICE: Disconnecting all channels on all boards!");
+
+            for (unsigned int dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+            {    
+                for (unsigned int chan = 0; chan < Globals::k3lapi.channel_count(dev); chan++)
+                    forceDisconnect(dev,chan);
+            }    
+            break;
+        }    
+        case 4:
+        {    
+            unsigned int dev = atoi(argv[2]);
+
+            if (ARG_CMP(3, "all"))
+            {    
+                K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Disconnecting all channels on board %d!") % dev);
+
+                for (unsigned int chan = 0; chan < Globals::k3lapi.channel_count(dev); chan++)
+                    forceDisconnect(dev,chan);
+            }    
+
+            unsigned int channel = atoi(argv[3]);
+
+            if (dev >= Globals::k3lapi.device_count())
+            {    
+                K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such device: %d!") % dev);
+                return false;
+            }    
+
+            
+            K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Disconnecting channel %d on board %d!") % channel % dev);
+
+            forceDisconnect(dev,channel);
+            break;
+        }    
+
+        default:
+            break;
+    }   
+
+    return true;
+}
+
+bool Cli::_KhompChannelsUnblock::execute(int argc, char *argv[])
+{
+    if (argc != 4 && argc != 3)
+    {    
+        printUsage(stream);
+        return false;
+    }    
+
+    switch (argc)
+    {    
+        case 3:
+        {    
+            K::Logger::Logg2(C_CLI, stream, "NOTICE: Unblocking all channels on all devices!");
+            for (unsigned int dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+            {    
+                for (unsigned int chan = 0; chan < Globals::k3lapi.channel_count(dev); chan++)
+                {    
+                    try
+                    {
+                        Globals::k3lapi.command(dev,chan,CM_UNLOCK_INCOMING);
+                        Globals::k3lapi.command(dev,chan,CM_UNLOCK_OUTGOING);
+                    }
+                    catch(K3LAPI::failed_command &e)
+                    {
+                        if (K::Logger::Logg.classe(C_WARNING).enabled())
+                        {   
+                            LOG(WARNING, FMT("Command '%s' has failed with error '%s'.")
+                                    % Verbose::commandName(e.code) % Verbose::status((KLibraryStatus)e.rc));
+                        }   
+
+                        return false;
+                    }
+                }    
+            }    
+            break;
+        }    
+        case 4:
+        {    
+            int dev = atoi (argv[2]);
+
+            if ( !SAFE_strcasecmp(argv[3], "all") )
+            {    
+                if (!Globals::k3lapi.valid_device( dev ))
+                {    
+                    K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find device: %d!") % dev );
+                    return false;
+                }    
+
+                K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Unblocking all channels on device %d!") % dev);
+
+                for (unsigned int i = 0; i < Globals::k3lapi.channel_count(dev); i++) 
+                {
+                    try
+                    {
+                        Globals::k3lapi.command(dev,i,CM_UNLOCK_INCOMING);
+                        Globals::k3lapi.command(dev,i,CM_UNLOCK_OUTGOING);
+                    }
+                    catch(K3LAPI::failed_command &e)
+                    {
+                        if (K::Logger::Logg.classe(C_WARNING).enabled())
+                        {   
+                            LOG(WARNING, FMT("Command '%s' has failed with error '%s'.")
+                                    % Verbose::commandName(e.code) % Verbose::status((KLibraryStatus)e.rc));
+                        }   
+
+                        return false;
+                    }
+                }
+            } 
+            else 
+            {    
+                int obj = atoi (argv[3]);
+
+                if (!Globals::k3lapi.valid_channel(dev, obj))
+                {    
+                    K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such channel %d at device %d!") % obj % dev);
+                    return false;
+                }    
+
+                K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Unblocking channel %d on device %d!") % obj % dev);
+
+                try
+                {
+                    Globals::k3lapi.command(dev,obj,CM_UNLOCK_INCOMING);
+                    Globals::k3lapi.command(dev,obj,CM_UNLOCK_OUTGOING);
+                }
+                catch(K3LAPI::failed_command &e)
+                {
+                    if (K::Logger::Logg.classe(C_WARNING).enabled())
+                    {   
+                        LOG(WARNING, FMT("Command '%s' has failed with error '%s'.")
+                                % Verbose::commandName(e.code) % Verbose::status((KLibraryStatus)e.rc));
+                    }   
+
+                    return false;
+                }
+            }    
+            break;
+        }    
+        default:
+            break;
+    }    
+    
+    return true;
+}
+
+void Cli::_KhompShowStatistics::cliStatistics(unsigned int device)
+{
+    for (unsigned int channel = 0; channel < Globals::k3lapi.channel_count(device); channel++)
+    {
+        try
+        {
+            Board::KhompPvt *pvt = Board::get(device, channel);
+            K::Logger::Logg2(C_CLI,stream,pvt->getStatistics(Statistics::ROW).c_str());
+        }
+        catch (K3LAPI::invalid_channel & err)
+        {
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+        }
+    }    
+}
+
+void Cli::_KhompShowStatistics::cliDetailedStatistics(unsigned int device, unsigned int channel)
+{
+    try
+    {
+        Board::KhompPvt *pvt = Board::get(device, channel);
+        K::Logger::Logg2(C_CLI,stream,"----------------------------------------------");
+        K::Logger::Logg2(C_CLI,stream,FMT("Detailed statistics of: Device %02d - Channel %02d") % pvt->target().device % pvt->target().object);
+        K::Logger::Logg2(C_CLI,stream,pvt->getStatistics(Statistics::DETAILED).c_str());
+        K::Logger::Logg2(C_CLI,stream,"----------------------------------------------");
+    }
+    catch (K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+    }
+}
+
+bool Cli::_KhompShowStatistics::execute(int argc, char *argv[])
+{
+    if (argc < 2 || argc > 5) 
+    {
+        printUsage(stream);
+        return false;
+    }
+    unsigned int dev = UINT_MAX;
+    unsigned int obj = UINT_MAX;
+    int detailed = 0, verbose  = 0; 
+
+    detailed = ((argc > 2)  && (!strcasecmp(argv[2], "detailed")) ? 1 : 0 ); 
+    verbose  = ((argc > 2)  && (!strcasecmp(argv[2], "verbose"))  ? 1 : 0 ); 
+
+    try  
+    {   
+
+        if(argc > (2+detailed+verbose))
+        {
+            dev = Strings::tolong(argv[2+detailed+verbose]);
+            if (!Globals::k3lapi.valid_device(dev))
+            {    
+                K::Logger::Logg2(C_CLI, stream, "ERROR: No such device!");
+                return false;
+            }    
+        }
+
+        if (argc > (3+detailed+verbose))
+        {   
+            std::string object(argv[3+detailed+verbose]);
+            obj = Strings::tolong(object);
+
+            if (!Globals::k3lapi.valid_channel(dev, obj))
+            {    
+                K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % obj % dev );
+                return false;
+            }  
+        }
+    }    
+    catch (Strings::invalid_value e)
+    {    
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Invalid numeric value!");
+        return false;
+    }    
+    
+    std::string header;
+    header.append( " ------------------------------------------------------------------------------------\n");
+    header.append( "|----------------------------- Khomp Endpoint Statistics ----------------------------|\n");
+    header.append( "|------------------------------------------------------------------------------------|\n");
+    header.append( "|  hw  |          total calls           | channel | FreeSWITCH | channel  |  status  |\n");
+    header.append( "|  id  | incoming | outgoing |  failed  |  fails  |   status   |  state   |   time   |\n");
+    header.append( " ------------------------------------------------------------------------------------");
+    std::string footer;
+    footer.append( " ------------------------------------------------------------------------------------");
+
+    try
+    {
+        if (obj != UINT_MAX)
+        {
+            if(detailed != 0)
+            {
+                cliDetailedStatistics (dev, obj);
+            }
+            else
+            {
+                K::Logger::Logg2(C_CLI,stream,header.c_str());
+                Board::KhompPvt *pvt = Board::get(dev, obj);
+                K::Logger::Logg2(C_CLI,stream,pvt->getStatistics(Statistics::ROW).c_str());
+                K::Logger::Logg2(C_CLI,stream,footer.c_str());
+            }
+        }
+        else
+        {
+            if(detailed != 0)
+            {
+                printUsage(stream);
+                return false;
+            }
+
+            K::Logger::Logg2(C_CLI,stream,header.c_str());
+
+            if (dev == UINT_MAX)
+            {
+                for (dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+                    cliStatistics (dev);
+            }
+            else
+            {
+                cliStatistics (dev);
+            }
+        
+            K::Logger::Logg2(C_CLI,stream,footer.c_str());
+        }
+    }
+    catch(K3LAPI::invalid_channel &e)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % obj % dev );
+    }
+
+    return true;
+}
+
+void Cli::_KhompShowChannels::showChannel(unsigned int device, bool concise, unsigned int channel)
+{
+    try
+    {
+
+        Board::KhompPvt *pvt = Board::get(device, channel);
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "found channel.."));
+
+        /* skip inactive channels */
+        if (pvt->getSignaling() == ksigInactive)
+            return;
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "is valid.."));
+
+        /* make sure the states wont start 'dancing' at random.. */
+        ScopedPvtLock lock(pvt);
+
+        std::string tmp_call = Globals::k3lutil.callStatus(
+                pvt->target().device, 
+                pvt->target().object, 
+                (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+        std::string tmp_chan = Globals::k3lutil.channelStatus(
+                pvt->target().device, 
+                pvt->target().object, 
+                (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+        if (concise)
+        {   
+            std::string state = pvt->getStateString();
+
+            if (pvt->getSignaling() == ksigGSM)
+            {    
+                K3L_GSM_CHANNEL_STATUS gsmStatus;
+
+                if (k3lGetDeviceStatus(device, channel + ksoGsmChannel, &gsmStatus, sizeof(gsmStatus)) != ksSuccess)
+                    return;
+
+                const unsigned int sign_numb = (gsmStatus.SignalStrength != 255 ? gsmStatus.SignalStrength : 0);
+
+                std::string gsm_registry = (strlen(gsmStatus.OperName) != 0 ? gsmStatus.OperName : "<none>");
+
+                K::Logger::Logg2(C_CLI, stream, FMT("B%02dC%02d:%s:%s:%s:%d%%:%s")
+                        % device % channel % state % tmp_call % tmp_chan
+                        % sign_numb % gsm_registry);
+            }    
+            else 
+            {    
+                K::Logger::Logg2(C_CLI, stream, FMT("B%02dC%02d:%s:%s:%s")
+                        % device % channel %  state % tmp_call % tmp_chan);
+            }    
+        }    
+        else 
+        {    
+            if (pvt->getSignaling() == ksigGSM)
+            {    
+                K3L_GSM_CHANNEL_STATUS gsmStatus;
+
+                if (k3lGetDeviceStatus(device, channel + ksoGsmChannel, &gsmStatus, sizeof(gsmStatus)) != ksSuccess)
+                    return;
+
+                const unsigned int sign_numb = (gsmStatus.SignalStrength != 255 ? gsmStatus.SignalStrength : 0);
+
+                const unsigned int full_size = 10;
+                const unsigned int sign_size = std::min((sign_numb * full_size) / 100, full_size);
+
+                std::string tmp_antenna_level;
+
+                for (unsigned int i = 0; i < sign_size; i++) 
+                    tmp_antenna_level += '*'; 
+
+                for (unsigned int i = sign_size; i < full_size; i++) 
+                    tmp_antenna_level += ' '; 
+
+                tmp_chan += " (";
+                tmp_chan += (strlen(gsmStatus.OperName) != 0 ? gsmStatus.OperName : "...");
+                tmp_chan += ")"; 
+
+                K::Logger::Logg2(C_CLI, stream, FMT("| %d,%02d | %8s | %8s | %-23s | %02d%% |%s|")
+                        % device % channel %  pvt->getStateString() % tmp_call % tmp_chan
+                        % sign_numb % tmp_antenna_level);
+            }    
+            else 
+            {    
+                K::Logger::Logg2(C_CLI, stream, FMT("| %d,%02d | %8s | %8s | %-40s |")
+                        % device % channel % pvt->getStateString() % tmp_call % tmp_chan);
+            }    
+        }    
+    }    
+    catch (K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+    }
+    catch (...)
+    {    
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Unexpected error..., skipping");
+    }   
+}
+
+void Cli::_KhompShowChannels::showChannels(unsigned int device, bool concise)
+{
+    for (unsigned int channel = 0; channel < Globals::k3lapi.channel_count(device); channel++)
+    {
+        showChannel(device, concise, channel);
+    }
+}
+
+bool Cli::_KhompShowChannels::execute(int argc, char *argv[])
+{
+    unsigned int dev = UINT_MAX;
+    int concise = 0, verbose = 0; 
+
+    bool onlyShowOneChannel = false;
+    unsigned int channelToShow = 0; 
+
+    if (argc > 5)
+    {
+        Cli::KhompShowChannels.printUsage(stream);
+        return false;
+    }
+
+    concise = ( ((argc == 3) || (argc == 4) || (argc == 5) ) && (ARG_CMP(2, "concise")) ? 1 : 0 ); 
+    verbose = ( ((argc == 3) || (argc == 4) || (argc == 5) ) && (ARG_CMP(2, "verbose")) ? 1 : 0 ); 
+
+    if (argc >= (3 + concise + verbose))
+    {    
+        dev = atoi (argv[2 + concise + verbose]);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {    
+            K::Logger::Logg2(C_CLI, stream, "ERROR: no such device!");
+            return false;
+        }    
+        
+        if (argc == ( 4 + concise + verbose ))
+        {
+            onlyShowOneChannel = true;
+            channelToShow = atoi (argv[3 + concise + verbose]);
+        }    
+    }    
+
+    if (concise == 0)
+    {    
+        K::Logger::Logg2(C_CLI, stream, " -----------------------------------------------------------------------");
+        K::Logger::Logg2(C_CLI, stream, "|-------------------- Khomp Channels and Connections -------------------|");
+        K::Logger::Logg2(C_CLI, stream, "|-----------------------------------------------------------------------|");
+        K::Logger::Logg2(C_CLI, stream, "|  hw  |freeSWITCH|   call   |                   channel                |");
+        K::Logger::Logg2(C_CLI, stream, "|  id  |  status  |  status  |                   status                 |");
+        K::Logger::Logg2(C_CLI, stream, " -----------------------------------------------------------------------");
+    }    
+
+    if ( onlyShowOneChannel )
+    {    
+        if ( channelToShow <  Globals::k3lapi.channel_count(dev) )
+        {    
+            showChannel (dev,(concise == 0 ? false : true), channelToShow);
+        }    
+        else 
+        {    
+            K::Logger::Logg2(C_CLI, stream, "ERROR: no such channel!");
+        }    
+    }    
+    else if (dev == UINT_MAX)
+    {    
+        for (dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+        {
+            showChannels(dev, (concise == 0 ? false : true));
+        }
+    }    
+    else 
+    {    
+        showChannels ( dev, (concise == 0 ? false : true));
+    }
+
+    if (concise == 0)
+        K::Logger::Logg2(C_CLI, stream, " -----------------------------------------------------------------------");
+
+    return true;
+}
+
+void Cli::_KhompShowLinks::showLinks(unsigned int device, bool concise)
+{
+    if (!concise)
+        K::Logger::Logg2(C_CLI, stream, "|------------------------------------------------------------------------|");
+
+    switch (Globals::k3lutil.physicalLinkCount(device, true))
+    {
+        case 1:
+        {
+            std::string str_link0 = Globals::k3lutil.getLinkStatus(device, 0, (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+            if (concise)
+                K::Logger::Logg2(C_MESSAGE, stream, FMT("B%02dL00:%s") % device % str_link0);
+            else
+                K::Logger::Logg2(C_CLI, stream, FMT("| Link '0' on board '%d': %-47s |") % device % str_link0);
+            break;
+        }
+
+        case 2:
+        {
+            std::string str_link0 = Globals::k3lutil.getLinkStatus(device, 0, (concise ? Verbose::EXACT : Verbose::HUMAN));
+            std::string str_link1 = Globals::k3lutil.getLinkStatus(device, 1, (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+            if (concise)
+            {
+                K::Logger::Logg2(C_MESSAGE, stream, FMT("B%02dL00:%s") % device % str_link0);
+                K::Logger::Logg2(C_MESSAGE, stream, FMT("B%02dL01:%s") % device % str_link1);
+            }
+            else
+            {
+                K::Logger::Logg2(C_CLI, stream, FMT("|------ Link '0' on board '%d' ------||------ Link '1' on board '%d' ------|")
+                    % device % device);
+
+                K::Logger::Logg2(C_CLI, stream, FMT("| %-33s || %-33s |") % str_link0 % str_link1);
+            }
+
+            break;
+        }
+        default:
+        {
+            if (concise)
+                K::Logger::Logg2(C_MESSAGE, stream, FMT("B%02dLXX:NoLinksAvailable") % device);
+            else
+                K::Logger::Logg2(C_CLI, stream, FMT("| Board '%d': %-59s |") % device % "No links available.");
+            break;
+        }
+    }
+
+}
+
+void Cli::_KhompShowLinks::showErrors(unsigned int device, bool concise)
+{
+
+    if (!concise)
+        K::Logger::Logg2(C_CLI, stream, "|-----------------------------------------------------------------------|");
+
+    switch (Globals::k3lutil.physicalLinkCount(device, true))
+    {
+        case 2:
+        {
+            K3LUtil::ErrorCountType link0 = Globals::k3lutil.linkErrorCount(
+                    device, 0, (concise ? Verbose::EXACT : Verbose::HUMAN));
+            K3LUtil::ErrorCountType link1 = Globals::k3lutil.linkErrorCount(
+                    device, 1, (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+            if (concise)
+            {
+                for (K3LUtil::ErrorCountType::iterator i = link0.begin(); i != link0.end(); i++)
+                    K::Logger::Logg2(C_CLI, stream, FMT("%d:0:%s:%d") % device % i->first % i->second);
+
+                for (K3LUtil::ErrorCountType::iterator i = link1.begin(); i != link1.end(); i++)
+                    K::Logger::Logg2(C_CLI, stream, FMT("%d:1:%s:%d") % device % i->first % i->second);
+            }
+            else
+            {
+                K::Logger::Logg2(C_CLI, stream, FMT("|----- Link '0' on board '%d' ------| |----- Link '1' on board '%d' ------|") % device % device);
+                K::Logger::Logg2(C_CLI, stream, "|----------------------------------| |----------------------------------|");
+                K::Logger::Logg2(C_CLI, stream, "|       Error type       | Number  | |       Error type       | Number  |");
+                K::Logger::Logg2(C_CLI, stream, "|----------------------------------| |----------------------------------|");
+
+                K3LUtil::ErrorCountType::iterator i = link0.begin();
+                K3LUtil::ErrorCountType::iterator j = link1.begin();
+
+                for (; i != link0.end() && j != link1.end(); i++, j++)
+                {
+                    K::Logger::Logg2(C_CLI, stream, FMT("| %22s | %-7d | | %22s | %-7d |")
+                       % i->first % i->second % j->first % j->second);
+                }
+            }
+
+            break;
+        }
+
+        case 1:
+        {
+            K3LUtil::ErrorCountType link0 = Globals::k3lutil.linkErrorCount(device, 0, (concise ? Verbose::EXACT : Verbose::HUMAN));
+
+            if (concise)
+            {
+                for (K3LUtil::ErrorCountType::iterator i = link0.begin(); i != link0.end(); i++)
+                    K::Logger::Logg2(C_CLI, stream, FMT("%d:0:%s:%d") % device % i->first % i->second);
+            }
+            else
+            {
+                K::Logger::Logg2(C_CLI, stream, FMT("|------------------------ Link '0' on board '%d' ------------------------|") % device);
+                K::Logger::Logg2(C_CLI, stream, "|-----------------------------------------------------------------------|");
+                K::Logger::Logg2(C_CLI, stream, "|                      Error type                      |     Number     |");
+                K::Logger::Logg2(C_CLI, stream, "|-----------------------------------------------------------------------|");
+
+                for (K3LUtil::ErrorCountType::iterator i = link0.begin(); i != link0.end(); i++)
+                    K::Logger::Logg2(C_CLI, stream, FMT("| %52s | %-14d |") % i->first % i->second);
+            }
+
+            break;
+        }
+
+        case 0:
+        {
+            if (!concise)
+                K::Logger::Logg2(C_CLI, stream, FMT("|                     No links detected on board %d!                     |") % device);
+
+            break;
+        }
+    }
+}
+
+bool Cli::_KhompShowLinks::execute(int argc, char *argv[])
+{
+    if(argc < 2 || argc > 5)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    unsigned int dev = UINT_MAX;
+    int concise = 0, verbose = 0, errors = 0;
+
+    errors = ( (argc > 2) && (!strcasecmp(argv[2],"errors")) ? 1 : 0 );
+
+    concise = ( (argc > (2+errors)) && (!strcasecmp(argv[(2+errors)],"concise")) ? 1 : 0 );
+    verbose = ( (argc > (2+errors)) && (!strcasecmp(argv[(2+errors)],"verbose")) ? 1 : 0 );
+
+    if(argc > (2+errors+concise+verbose))
+    {
+        dev = atoi(argv[(2+errors+concise+verbose)]);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            K::Logger::Logg2(C_CLI, stream, "ERROR: no such device!");
+            return false;
+        }
+    }
+
+    if (!concise)
+    {
+        K::Logger::Logg2(C_CLI, stream, " ------------------------------------------------------------------------");
+        if(!errors)
+        {
+            K::Logger::Logg2(C_CLI, stream, "|--------------------------- Khomp Links List ---------------------------|");
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, "|-------------------- Khomp Errors Counters on Links -------------------|");
+        }
+    }
+
+    if (dev == UINT_MAX)
+    {
+        for (dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+        {
+            if(!errors)
+            {
+                showLinks (dev, (concise == 1));
+            }
+            else
+            {
+                showErrors(dev, (concise == 1));
+            }
+        }
+    }
+    else
+    {
+        if(!errors)
+        {
+            showLinks (dev, (concise == 1));
+        }
+        else
+        {
+            showErrors(dev, (concise == 1));
+        }
+    }
+
+    if (!concise)
+    {
+        K::Logger::Logg2(C_CLI, stream, " ------------------------------------------------------------------------");
+    }
+
+    return true;
+}
+
+void Cli::_KhompClearLinks::clearLink(unsigned int device, unsigned int link)
+{
+    try
+    {
+        Globals::k3lapi.command(device, link, CM_CLEAR_LINK_ERROR_COUNTER);
+    }
+    catch(K3LAPI::failed_command & e)
+    {
+        K::Logger::Logg2(C_CLI, stream, 
+                FMT("ERROR: Command has failed with error '%s'") 
+                % Verbose::status((KLibraryStatus)e.rc).c_str());
+    }
+}
+
+bool Cli::_KhompClearLinks::execute(int argc, char *argv[])
+{
+    if(argc < 2 || argc > 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    unsigned int dev = UINT_MAX;
+    unsigned int obj = UINT_MAX;    
+
+    if(argc > 2)
+    {
+        dev = atoi(argv[2]);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                    FMT("ERROR: no such device %d!") % dev);
+            return false;
+        }
+
+        if(argc > 3)
+        {
+            obj = atoi(argv[3]);
+
+            if(!Globals::k3lapi.valid_link(dev, obj))
+            {
+                K::Logger::Logg2(C_CLI, stream, 
+                      FMT("ERROR: No such link %d on device %d!") % obj % dev);
+                return false;
+            }
+        }
+    }
+
+    if(dev == UINT_MAX)
+    {
+        K::Logger::Logg2(C_CLI, stream, 
+                "NOTICE: Reseting error count of all links...");
+
+        for (unsigned int d = 0; d < Globals::k3lapi.device_count(); d++)
+        {
+            unsigned int link_count = Globals::k3lutil.physicalLinkCount(d, true);
+
+            for (unsigned int o = 0; o < link_count; o++)
+                clearLink(d, o);
+        }
+    }
+    else
+    {
+        if (obj == UINT_MAX)
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                FMT("NOTICE: Reseting error count of all links on device %d...")
+                % dev);
+            unsigned int link_count = Globals::k3lutil.physicalLinkCount(dev, true);
+
+            for (unsigned int o = 0; o < link_count; o++)
+                clearLink(dev, o);
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                FMT("NOTICE: Reseting error count of link %d on device %d...") 
+                % obj % dev);
+
+            clearLink(dev, obj);
+        }
+    }
+
+    return true;
+}
+
+bool Cli::_KhompClearStatistics::execute(int argc, char *argv[])
+{
+    if(argc < 2 || argc > 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    try
+    {
+
+    unsigned int dev = UINT_MAX;
+    unsigned int obj = UINT_MAX;    
+
+    if(argc > 2)
+    {
+        dev = atoi(argv[2]);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                    FMT("ERROR: no such device %d!") % dev);
+            return false;
+        }
+
+        if(argc > 3)
+        {
+            obj = atoi(argv[3]);
+
+
+            if(!Globals::k3lapi.valid_channel(dev, obj))
+            {
+                K::Logger::Logg2(C_CLI, stream, 
+                      FMT("ERROR: No such channel %d on device %d!") % obj % dev);
+                return false;
+            }
+        }
+    }
+
+    if(dev == UINT_MAX)
+    {
+        K::Logger::Logg2(C_CLI, stream, "NOTICE: Reseting statistics of all channels...");
+
+        for (unsigned int d = 0; d < Globals::k3lapi.device_count(); d++)
+        {
+            for (unsigned int o = 0; o < Globals::k3lapi.channel_count(d); o++) 
+                Board::get(d, o)->clearStatistics();
+        }
+    }
+    else
+    {
+        if (obj == UINT_MAX)
+        {
+            K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Reseting statistics of all channels from board %d...") % dev);
+            
+            for (unsigned int o = 0; o < Globals::k3lapi.channel_count(dev); o++) 
+                Board::get(dev, o)->clearStatistics();
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Reseting statistics of channel %d from board %d") % obj % dev);
+            Board::get(dev, obj)->clearStatistics();
+        }
+    }
+
+    }
+    catch (K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+        return false;
+    }
+
+    return true;
+}
+
+void Cli::_KhompResetLinks::resetLink(unsigned int device, unsigned int link)
+{
+    try
+    {
+        Globals::k3lapi.command(device, link, CM_RESET_LINK);
+    }
+    catch(K3LAPI::failed_command & e)
+    {
+        K::Logger::Logg2(C_CLI, stream, 
+                FMT("ERROR: Command has failed with error '%s'") 
+                % Verbose::status((KLibraryStatus)e.rc).c_str());
+    }
+}
+
+bool Cli::_KhompResetLinks::execute(int argc, char *argv[])
+{
+    if(argc < 2 || argc > 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    unsigned int dev = UINT_MAX;
+    unsigned int obj = UINT_MAX;    
+
+    if(argc > 2)
+    {
+        dev = atoi(argv[2]);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                    FMT("ERROR: no such device %d!") % dev);
+            return false;
+        }
+
+        if(argc > 3)
+        {
+            obj = atoi(argv[3]);
+
+            if(!Globals::k3lapi.valid_link(dev, obj))
+            {
+                K::Logger::Logg2(C_CLI, stream, 
+                      FMT("ERROR: No such link %d on device %d!") % obj % dev);
+                return false;
+            }
+        }
+    }
+
+    if(dev == UINT_MAX)
+    {
+        K::Logger::Logg2(C_CLI, stream, 
+                "NOTICE: Reseting all links...");
+
+        for (unsigned int d = 0; d < Globals::k3lapi.device_count(); d++)
+        {
+            unsigned int link_count = Globals::k3lutil.physicalLinkCount(d, true);
+
+            for (unsigned int o = 0; o < link_count; o++)
+                resetLink(d, o);
+        }
+    }
+    else
+    {
+        if (obj == UINT_MAX)
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                FMT("NOTICE: Reseting all links on device %d...")
+                % dev);
+            unsigned int link_count = Globals::k3lutil.physicalLinkCount(dev, true);
+
+            for (unsigned int o = 0; o < link_count; o++)
+                resetLink(dev, o);
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                FMT("NOTICE: Reseting link %d on device %d...") 
+                % obj % dev);
+
+            resetLink(dev, obj);
+        }
+    }
+
+    return true;
+}
+
+bool Cli::_KhompSMS::execute(int argc, char *argv[])
+{
+    if(argc < 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    std::string devs(argv[1]);
+    std::string numb(argv[2]);
+    std::string mesg(argv[3]);
+
+    for (unsigned int i = 4; i < (unsigned int)argc; i++)
+    {
+        mesg += " ";
+        mesg += argv[i];
+    }
+
+    Board::KhompPvt * pvt = NULL;
+
+    bool enable_retry = false;
+
+    size_t pos = numb.find('r');
+    if (pos != std::string::npos)
+    {
+        numb.erase(pos,1);
+        enable_retry = true;
+    }
+
+    std::string begin;
+
+    if(devs[0] != 'b' && devs[0] != 'B')
+    {
+        begin = "b";
+    }
+
+    std::string complete = begin + devs + "/" + numb + "/" + mesg;
+    int cause;
+
+    try
+    {
+        for (unsigned int ntry = 0; ntry < 15; ++ntry)
+        {
+            ScopedAllocLock alloc_lock;
+
+            pvt = processSMSString(complete.c_str(), &cause);
+
+            /* NOTE: go directly to the pvt check below! */
+            if (!enable_retry || pvt)
+                break;
+
+            alloc_lock.unlock();
+
+            K::Logger::Logg2(C_CLI, stream, FMT("WARNING: '%s': No available channel, trying again...") % devs);
+            usleep(2500000);
+        }
+
+        if (!pvt)
+        {
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: '%s': No available channel %s") % devs % (enable_retry ? "after 15 retries, giving up!" : ""));
+            return false;
+        }
+
+        ScopedPvtLock lock(pvt);
+
+        if(!pvt->application(SMS_SEND, NULL, complete.c_str()))
+        {
+            K::Logger::Logg2(C_CLI, stream, "ERROR: Message could not be sent");
+            return false;
+        }
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        if(err._fail == ScopedLockFailed::ALLOC_FAILED)
+        {
+            K::Logger::Logg2(C_CLI, stream, "ERROR: unable to global alloc lock");
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: unable to lock: %s!") % err._msg.c_str());
+        }
+        return false;
+    }
+        
+    K::Logger::Logg2(C_CLI, stream, "Message sent successfully!");
+
+    return true;
+}
+
+bool Cli::_KhompLogConsole::execute(int argc, char *argv[])
+{
+    if (argc < 3)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    bool invert = false;
+    bool unique = false;
+
+    std::string extra(argv[2]);
+
+    unsigned int total_args = argc - 2; /* remove "khomp log console" */
+
+    if (extra == "no")
+    {    
+        invert = true;
+        --total_args;
+    }    
+    else if (extra == "just")
+    {    
+        unique = true;
+        --total_args;
+    }    
+
+    unsigned int first_args = argc - total_args;
+
+    std::string options;
+
+    for (unsigned int i = first_args; i < (unsigned int)argc; i++) 
+    {    
+        options += argv[i];
+        options += ","; 
+    }    
+
+    K::Logger::processLogConsole(stream, options, invert, unique);
+    return true;
+}
+
+bool Cli::_KhompLogDisk::execute(int argc, char *argv[])
+{
+    if (argc < 3)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    bool invert = false;
+    bool unique = false;
+
+    std::string extra(argv[2]);
+
+    unsigned int total_args = argc - 2; /* remove "khomp log disk" */
+
+    if (extra == "no")
+    {
+        invert = true;
+        --total_args;
+    }
+    else if (extra == "just")
+    {
+        unique = true;
+        --total_args;
+    }
+
+    unsigned int first_args = argc - total_args;
+
+    std::string options;
+
+    for (unsigned int i = first_args; i < (unsigned int)argc; i++)
+    {
+        options += argv[i];
+        options += ",";
+    }
+
+    K::Logger::processLogDisk(stream, options, invert, unique);
+    return true;
+}
+
+bool Cli::_KhompLogStatus::execute(int argc, char *argv[])
+{
+    if(argc != 2)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    Strings::Merger m1;
+
+    bool flag1_errors   = K::Logger::Logg.classe(C_ERROR).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_warnings = K::Logger::Logg.classe(C_WARNING).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_messages = K::Logger::Logg.classe(C_MESSAGE).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_events   = K::Logger::Logg.classe(C_EVENT).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_commands = K::Logger::Logg.classe(C_COMMAND).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_audio    = K::Logger::Logg.classe(C_AUDIO_EV).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_modem    = K::Logger::Logg.classe(C_MODEM_EV).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_links    = K::Logger::Logg.classe(C_LINK_STT).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+    bool flag1_cas      = K::Logger::Logg.classe(C_CAS_MSGS).get(O_CONSOLE, K::LogManager::Option::ENABLED);
+
+    if (flag1_errors)   m1.add("errors");
+    if (flag1_warnings) m1.add("warnings");
+    if (flag1_messages) m1.add("messages");
+    if (flag1_events)   m1.add("events");
+    if (flag1_commands) m1.add("commands");
+    if (flag1_audio)    m1.add("audio");
+    if (flag1_modem)    m1.add("modem");
+    if (flag1_links)    m1.add("link");
+    if (flag1_cas)      m1.add("cas");
+
+    K::Logger::Logg2(C_CLI, stream, "             ");
+
+    if (!m1.empty()) K::Logger::Logg2(C_CLI, stream, FMT("Enabled console messages: %s.") % m1.merge(", "));
+    else /* ----- */ K::Logger::Logg2(C_CLI, stream, "There are no console messages enabled.");
+
+    bool flag2_errors    = K::Logger::Logg.classe(C_ERROR).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_warnings  = K::Logger::Logg.classe(C_WARNING).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_messages  = K::Logger::Logg.classe(C_MESSAGE).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_events    = K::Logger::Logg.classe(C_EVENT).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_commands  = K::Logger::Logg.classe(C_COMMAND).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_audio     = K::Logger::Logg.classe(C_AUDIO_EV).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_modem     = K::Logger::Logg.classe(C_MODEM_EV).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_links     = K::Logger::Logg.classe(C_LINK_STT).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_cas       = K::Logger::Logg.classe(C_CAS_MSGS).get(O_GENERIC, K::LogManager::Option::ENABLED);
+    bool flag2_functions = K::Logger::Logg.classe(C_DBG_FUNC).enabled();
+    bool flag2_threads   = K::Logger::Logg.classe(C_DBG_THRD).enabled();
+    bool flag2_locks     = K::Logger::Logg.classe(C_DBG_LOCK).enabled();
+    bool flag2_streams   = K::Logger::Logg.classe(C_DBG_STRM).enabled();
+
+    Strings::Merger m2;
+
+    if (flag2_errors)    m2.add("errors");
+    if (flag2_warnings)  m2.add("warnings");
+    if (flag2_messages)  m2.add("messages");
+    if (flag2_events)    m2.add("events");
+    if (flag2_commands)  m2.add("commands");
+    if (flag2_audio)     m2.add("audio");
+    if (flag2_modem)     m2.add("modem");
+    if (flag2_links)     m2.add("link");
+    if (flag2_cas)       m2.add("cas");
+    if (flag2_functions) m2.add("functions");
+    if (flag2_threads)   m2.add("threads");
+    if (flag2_locks)     m2.add("locks");
+    if (flag2_streams)   m2.add("streams");
+
+    if (!m2.empty()) K::Logger::Logg2(C_CLI, stream, FMT("Enabled log-on-disk messages: %s.") % m2.merge(", "));
+    else /* ----- */ K::Logger::Logg2(C_CLI, stream, "There are no log-on-disk messages enabled.");
+   
+    if (Globals::flag_trace_rdsi) K::Logger::Logg2(C_CLI, stream, "The ISDN (RDSI) low-level tracing is enabled.");
+
+    K::Logger::Logg2(C_CLI, stream, "             ");
+
+    return true;
+}
+
+bool Cli::_KhompLogRotate::execute(int argc, char *argv[])
+{
+    if (argc != 2)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    if (!K::Logger::rotate())
+    {    
+        return false;
+    }    
+
+    return true;
+}
+
+bool Cli::_KhompLogTraceK3L::execute(int argc, char *argv[])
+{
+    if (argc != 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    std::string str_on("on");
+    std::string str_off("off");
+
+    bool value = false;
+
+         if (str_on  == argv[3]) value = true;
+    else if (str_off == argv[3]) value = false;
+    else 
+    {    
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Please use 'on' or 'off' to enable or disable.");
+        return false;
+    }    
+
+    K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: %sbling k3l debug messages.") % (value ? "Ena" : "Disa"));
+
+    Logfile logfile;
+
+    K::LogConfig::set(logfile, "K3L", "Value",        value);
+    K::LogConfig::set(logfile, "K3L", "CallProgress", value);
+    K::LogConfig::set(logfile, "K3L", "CallAnalyzer", value);
+    K::LogConfig::set(logfile, "K3L", "CadenceRecog", value);
+    K::LogConfig::set(logfile, "K3L", "CallControl",  value);
+    K::LogConfig::set(logfile, "K3L", "Fax",          value);
+
+    if (K::LogConfig::commit(logfile))
+    {    
+        try
+        {
+            Globals::k3lapi.command(-1, -1, CM_LOG_UPDATE);
+        }
+        catch(...)
+        {
+            LOG(ERROR,"Error while send command CM_LOG_UPDATE");
+        }
+    } 
+
+    return true;
+}
+
+bool Cli::_KhompLogTraceISDN::execute(int argc, char *argv[])
+{
+    if (argc < 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    bool active = true;
+
+    bool change_lapd = false;
+    bool change_q931 = false;
+
+    std::string what;
+
+    for (unsigned int i = 4; i < (unsigned int)argc; i++)
+    {
+        what += argv[i];
+        what += ",";
+    }
+
+    Strings::vector_type values;
+    Strings::tokenize(what, values, ",");
+
+    for (Strings::vector_type::iterator i = values.begin(); i != values.end(); i++)
+    {
+        if ((*i) == "q931") change_q931 = true;
+        if ((*i) == "lapd") change_lapd = true;
+        if ((*i) == "off")  active = false;
+    }
+
+    Logfile logfile;
+
+    K::LogConfig::set(logfile, "ISDN", "Value", active);
+
+    if (change_lapd || !active)
+        K::LogConfig::set(logfile, "ISDN", "Lapd", active);
+
+    if (change_q931 || !active)
+        K::LogConfig::set(logfile, "ISDN", "Q931", active);
+
+    if (K::LogConfig::commit(logfile))
+    {
+        try
+        {
+            Globals::k3lapi.command(-1, -1, CM_LOG_UPDATE);
+
+            if (active)
+            {
+                K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Activating the following ISDN debug option(s): %s") % what);
+                Globals::flag_trace_rdsi = true;
+            }
+            else
+            {
+                K::Logger::Logg2(C_CLI, stream, "NOTICE: Deactivating ISDN debug options");
+                Globals::flag_trace_rdsi = false;
+            }
+        }
+        catch(...)
+        {
+            if (active)
+                K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to activate the following ISDN debug option(s): %s") % what);
+            else
+                K::Logger::Logg2(C_CLI, stream, "ERROR: Unable to deactivate ISDN debug options");
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+bool Cli::_KhompLogTraceR2::execute(int argc, char *argv[])
+{
+    if (argc != 4)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    try
+    {
+        std::string str_off("off");
+        std::string str_on("on" );
+
+        bool enable = false;
+
+        if (str_on   == argv[3]) enable = true;
+        else if (str_off  == argv[3]) enable = false;
+
+        if (enable)
+        {
+            K::Logger::Logg2(C_CLI, stream, "NOTICE: All channels of all devices will be monitored!" );
+        }
+        else
+        {
+            K::Logger::Logg2(C_CLI, stream, "NOTICE: Deactivating R2 debug options" );
+        }
+
+        Logfile logfile;
+
+        K::LogConfig::set(logfile, "R2", "Value",     enable);
+        K::LogConfig::set(logfile, "R2", "Signaling", enable);
+        K::LogConfig::set(logfile, "R2", "States",    enable);
+
+        if (K::LogConfig::commit(logfile))
+        {
+            try
+            {
+                Globals::k3lapi.command(-1, -1, CM_LOG_UPDATE);
+            }
+            catch(...)
+            {
+                LOG(ERROR,"Error while send command CM_LOG_UPDATE");
+            }
+        }
+    }
+    catch (Strings::invalid_value e)
+    {
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Invalid numeric value in arguments.");
+        return false;
+    }
+
+    return true;
+}
+
+bool Cli::_KhompGet::execute(int argc, char *argv[])
+{
+    if (argc < 2) 
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    std::string arg(argv[1]);
+
+    try  
+    {    
+       std::string res = Globals::options.get((const char*) argv[1]);
+       K::Logger::Logg2(C_CLI, stream, FMT("Result for command %s is %s.") % std::string(argv[1]) % res);
+    }catch(ConfigProcessFailure &e){ 
+       K::Logger::Logg2(C_CLI, stream, (char*) e.msg.c_str());
+    }    
+
+    return true;
+}
+
+bool Cli::_KhompSet::execute(int argc, char *argv[])
+{
+    if (argc < 3) 
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    std::string args;
+
+    const unsigned int first = 2; 
+
+    for (unsigned int i = first; i < (unsigned int)argc; i++) 
+    {    
+        if (i != first) { args += " "; }
+
+        args += argv[i];
+    }    
+
+    try  
+    {    
+        Globals::options.process((const char *) argv[1], (const char *) args.c_str());
+    }    
+    catch (ConfigProcessFailure &e)
+    {    
+        K::Logger::Logg2(C_CLI,stream, FMT("config processing error: %s.") % e.msg.c_str());
+    }    
+
+    return true;
+}
+
+bool Cli::_KhompRevision::execute(int argc, char *argv[])
+{
+#ifndef MOD_KHOMP_VERSION
+#define MOD_KHOMP_VERSION "unknown"
+#endif
+
+#ifndef SWITCH_VERSION_FULL
+#define SWITCH_VERSION_FULL "unknown"
+#endif
+
+    std::string khomp_endpoint_rev(MOD_KHOMP_VERSION);
+    std::string freeswitch_rev(SWITCH_VERSION_FULL);
+
+    K::Logger::Logg2(C_CLI, stream, FMT("Khomp Endpoint - %s") % khomp_endpoint_rev);
+    K::Logger::Logg2(C_CLI, stream, FMT("FreeSWITCH - %s") % freeswitch_rev);
+    return true;
+}
+
+bool Cli::_KhompSendCommand::execute(int argc, char *argv[])
+{
+    if (argc < 5 || argc > 6)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    unsigned int dev = atoi (argv[2]);
+
+    if (dev >= Globals::k3lapi.device_count())
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such device: %d!") % dev);
+        return false;
+    }
+
+    unsigned int num = atoi (argv[4]);
+
+    if (num >= 256)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Invalid command number: %d!") % num);
+        return false;
+    }
+
+    unsigned int obj = atoi (argv[3]);
+
+    try
+    {
+        switch (argc)
+        {
+            case 5:    Globals::k3lapi.command(dev,obj, num);         break;
+            case 6:    Globals::k3lapi.command(dev,obj, num,argv[5]); break;
+            default:   /*               what-a-hell ?!             */ break;
+        }
+    }
+    catch(K3LAPI::failed_command &e)
+    {
+        if (K::Logger::Logg.classe(C_WARNING).enabled())
+        {   
+            LOG(WARNING, FMT("Command '%s' has failed with error '%s'.")
+                % Verbose::commandName(e.code) % Verbose::status((KLibraryStatus)e.rc));
+        }   
+
+        return false;
+    }
+
+    return true;
+}
+
+bool Cli::_KhompSendRawCommand::execute(int argc, char *argv[])
+{
+    if (argc < 6) 
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    unsigned int dev = atoi (argv[3]);
+
+    if (dev >= Globals::k3lapi.device_count())
+    {    
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: No such device: %d!") % dev);
+        return false;
+    }    
+
+    unsigned int dsp = atoi (argv[4]);
+
+    if (dsp >= 2)
+    {    
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Invalid DSP number: %d!") % dsp);
+        return false;
+    }    
+
+    const unsigned int base = 5;
+    char commands[(argc - base)];
+
+    for (int i = base, j = 0; i < argc; i++, j++) 
+    {    
+        if (sscanf(argv[i], "%hhx", &(commands[j])) != 1)
+        {    
+            K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Invalid hexadecimal sequence: '%s'!") % argv[i]);
+            return false;
+        }    
+    }    
+
+    try
+    {
+        Globals::k3lapi.raw_command(dev, dsp, commands, (argc - base));
+    }
+    catch(K3LAPI::failed_raw_command &e)
+    {
+        if (K::Logger::Logg.classe(C_WARNING).enabled())
+        {   
+            LOG(WARNING, FMT("(dev=%d,dsp=%d): Raw command '%s' has failed with error '%s'.")
+            % e.dev 
+            % e.dsp 
+            % Strings::hexadecimal(std::string((char*) commands,(argc - base))) 
+            % Verbose::status((KLibraryStatus)e.rc));
+        }   
+
+        return false;
+    }
+
+   return true; 
+}
+
+bool Cli::_KhompSelectSim::execute(int argc, char *argv[])
+{
+    if(argc != 5)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    std::string dev_str(argv[2]);
+    std::string obj_str(argv[3]);
+    std::string num_str(argv[4]);
+
+    try
+    {
+        unsigned int dev = Strings::tolong(dev_str);
+        unsigned int obj = Strings::tolong(obj_str);
+
+        if (!Globals::k3lapi.valid_device(dev))
+        {
+            K::Logger::Logg2(C_CLI, stream, 
+                    FMT("ERROR: no such device %d!") % dev);
+            return false;
+        }
+
+        if (!Globals::k3lapi.valid_channel(dev, obj))
+        {
+            K::Logger::Logg2(C_CLI, stream,
+                    FMT("ERROR: No such channel %d on device %d!") % obj % dev);
+            return false;
+        }
+
+        /* just check for validity */
+        (void)Strings::tolong(num_str);
+
+
+        if(!Board::get(dev, obj)->application(SELECT_SIM_CARD, NULL, num_str.c_str()))
+        {
+            K::Logger::Logg2(C_CLI, stream, "ERROR: Unable to select sim card"); 
+            return false;
+        }
+
+    }
+    catch (Strings::invalid_value & e)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Invalid number '%s'!") % e.value());
+        return false;
+    }
+    catch (K3LAPI::invalid_channel & err)
+    {
+        K::Logger::Logg2(C_CLI, stream, FMT("ERROR: Unable to find channel %d on device %d!") % err.channel % err.device );
+        return false;
+    }
+    catch(...)
+    {
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Unable to select sim card"); 
+        return false;
+    }
+
+    return true;
+}
+
+bool Cli::_KhompKommuterOnOff::execute(int argc, char *argv[])
+{
+    if(argc != 2)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    switch (Board::kommuter._kommuter_count)
+    {
+        case -1: K::Logger::Logg2(C_CLI, stream, "ERROR: libkwd.so required for kommuter could not be found." ); return false;
+        case 0:  K::Logger::Logg2(C_CLI, stream, "ERROR: none Kommuter was found on the system." );              return false;
+    }
+    
+    if (Opt::_kommuter_activation == "auto")
+    {
+        K::Logger::Logg2(C_CLI, stream, "ERROR: Kommuter is set to be started automatically by kommuter-activation configuration.");
+        return false;
+    }
+    
+    bool on_off = ARG_CMP(1, "on") ? true : false;
+
+    int ret = 0;
+    if (on_off)
+    {
+        int timeout = Opt::_kommuter_timeout;
+        K::Logger::Logg2(C_CLI, stream, FMT("NOTICE: Activating Kommuters with timeout of %d seconds .") % timeout);
+        bool start_timer = false;
+
+        std::string param= STG(FMT("timeout=%d") % timeout);
+
+        for (int kommuter = 0; kommuter < Board::kommuter._kommuter_count; kommuter++)
+        {
+            try
+            {
+                Globals::k3lapi.command(-1, kommuter, CM_START_WATCHDOG, (char*) param.c_str());
+                start_timer = true;
+            }
+            catch(K3LAPI::failed_command & e)
+            {
+                switch(e.rc)
+                {
+                case ksInvalidParams:
+                    K::Logger::Logg2(C_CLI,stream,FMT("ERROR: invalid timeout '%d' for Kommuter device '%d' timeout. Mininum is 0, maximum is 255.") 
+                % timeout % kommuter);
+                    break;
+                default:
+                    K::Logger::Logg2(C_CLI,stream,FMT("ERROR: could not start the kommuter device number '%d'.") % kommuter);
+                    break;
+                }
+            } 
+            catch(...)
+            {
+                K::Logger::Logg2(C_CLI, stream, FMT("ERROR: could not start the Kommuter device number '%d'.") % kommuter);
+            }
+        }
+
+        if (timeout == 0)
+        {
+            DBG(FUNC, D("kommuter watchdog timer not created because timeout is 0."));
+            return false;
+        }        
+        
+        if (start_timer)
+        {    
+            if (!Globals::global_timer)
+            {    
+                K::Logger::Logg2(C_CLI, stream , "Error creating the timer for kommuter.");
+                return true;
+            }    
+            else if (Board::kommuter._kwtd_timer_on)
+            {    
+                Globals::global_timer->restart( Board::kommuter._kwtd_timer_index, true );
+                DBG(FUNC, D("kommuter watchdog timer restarted."));
+            }
+            else
+            {
+                Board::kommuter._kwtd_timer_index = Globals::global_timer->add(((timeout < 5) ? (timeout*500) : 2000), &Kommuter::wtdKickTimer);
+                Board::kommuter._kwtd_timer_on = true;
+                DBG(FUNC, D("kommuter watchdog timer created and started."));
+            }
+        }    
+    }    
+    else 
+    {    
+        K::Logger::Logg2(C_CLI, stream, "NOTICE: Deactivating Kommuters.");
+
+        if (Board::kommuter._kwtd_timer_on)
+        {    
+            Globals::global_timer->del( Board::kommuter._kwtd_timer_index);
+            Board::kommuter._kwtd_timer_on = false;
+        }    
+
+        for(int kommuter = 0; kommuter < Board::kommuter._kommuter_count; kommuter++)
+        {    
+            try
+            {
+                Globals::k3lapi.command(-1, kommuter, CM_STOP_WATCHDOG);
+                return true;
+            }
+            catch(K3LAPI::failed_command & e)
+            {
+                K::Logger::Logg2(C_CLI,stream,FMT("ERROR: Kommuter device '%d' was not initialized.") % kommuter);
+            } 
+            catch(...)
+            {
+                K::Logger::Logg2(C_CLI, stream,FMT("ERROR: could not disable kommuter device '%d' for some unknow reason.") % kommuter);
+            }
+        }    
+    }
+
+    return false;
+}
+
+bool Cli::_KhompKommuterCount::execute(int argc, char *argv[])
+{
+    if(argc != 2)
+    {
+        printUsage(stream);
+        return false;
+    }
+
+    if(Board::kommuter._kommuter_count == -1)
+    {
+        K::Logger::Logg2(C_CLI, stream, 
+                "ERROR: libkwd.so required for kommuter could not be found." );
+        return false;
+    }
+
+    K::Logger::Logg2(C_CLI, stream, 
+            FMT("Kommuter devices detected = [%d]") 
+            % Board::kommuter._kommuter_count);
+
+    return true;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/frame.cpp b/src/mod/endpoints/mod_khomp/src/frame.cpp
new file mode 100644 (file)
index 0000000..ea52636
--- /dev/null
@@ -0,0 +1,124 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "frame.h"
+
+#define ALLOC(T,s) ((T*)calloc(1,s))
+
+/* Internal frame manager structure. */
+FrameStorage::FrameStorage(switch_codec_t * codec, int packet_size)
+:  _frames(ALLOC(switch_frame_t, frame_count * sizeof(switch_frame_t))),
+   _buffer(ALLOC(          char, audio_count * packet_size)),
+   _index(0)
+{
+    for (unsigned int i = 0; i < frame_count; i++)
+    {
+        _frames[i].codec      = codec;
+        _frames[i].source     = "mod_khomp";
+
+        _frames[i].packet     = 0;
+        _frames[i].packetlen  = 0;
+        _frames[i].extra_data = 0;
+
+        _frames[i].data       = (char *)0;
+        _frames[i].datalen    = packet_size;
+        _frames[i].buflen     = packet_size;
+
+        _frames[i].samples    = packet_size; // packet_duration * 8
+        _frames[i].rate       = 8000;
+        _frames[i].payload    = 0;
+
+        _frames[i].timestamp  = 0u;
+
+        _frames[i].seq        = 0u;
+        _frames[i].ssrc       = 0u;
+        _frames[i].m          = SWITCH_FALSE;
+        _frames[i].flags      = SFF_NONE;
+    }
+
+    _cng_frame.codec      = codec;
+    _cng_frame.source     = "mod_khomp";
+    _cng_frame.packet     = 0;
+    _cng_frame.packetlen  = 0;
+    _cng_frame.extra_data = 0;
+
+    _cng_frame.data       = (void*)"A";
+    _cng_frame.datalen    = 2;
+    _cng_frame.buflen     = 2;
+
+    _cng_frame.samples    = packet_size;
+    _cng_frame.rate       = 8000;
+    _cng_frame.payload    = 0;
+
+    _cng_frame.timestamp  = 0u;
+
+    _cng_frame.seq        = 0u;
+    _cng_frame.ssrc       = 0u;
+    _cng_frame.m          = SWITCH_FALSE;
+    _cng_frame.flags      = SFF_CNG;
+
+//    if (mlock(&_frames, frames_size) < 0)
+//    {
+//        DBG(CONF, F("Unable to lock ast_frame buffer memory in RAM: %s") % strerror(errno));
+//        std::cerr << "chan_khomp: Unable to lock ast_frame buffer memory in RAM: "
+//            << strerror(errno) << ". "
+//                << "This is not a catastrophic failure, but may cause unpredictable "
+//                << "audio delay under extreme load conditions." << std::endl;
+//    }
+//
+//    if (mlock(&_buffer, buffer_size) < 0)
+//    {
+//        DBG(CONF, F("Unable to lock audio buffer memory in RAM: %s") % strerror(errno));
+//        std::cerr << "chan_khomp: Unable to lock temporary audio buffer memory in RAM: "
+//                << strerror(errno) << ". "
+//                    << "This is not a catastrophic failure, but may cause unpredictable "
+//                    << "audio delay under extreme load conditions." << std::endl;
+//    }
+};
+
+FrameStorage::~FrameStorage()
+{
+    free(_frames);
+    free(_buffer);
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/globals.cpp b/src/mod/endpoints/mod_khomp/src/globals.cpp
new file mode 100644 (file)
index 0000000..cdc20ef
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "globals.h"
+
+K3LAPI                           Globals::k3lapi;
+K3LUtil                          Globals::k3lutil(Globals::k3lapi);
+Verbose                          Globals::verbose(Globals::k3lapi);
+
+/* Global Timer */
+Globals::GlobalTimer           * Globals::global_timer = NULL;
+
+Globals::Mutex                   Globals::khomp_alloc_mutex;
+
+ConfigOptions                    Globals::options;
+
+switch_endpoint_interface_t    * Globals::khomp_endpoint_interface     = NULL;
+switch_endpoint_interface_t    * Globals::khomp_sms_endpoint_interface = NULL;
+switch_endpoint_interface_t    * Globals::khomp_pr_endpoint_interface  = NULL;
+switch_application_interface_t * Globals::khomp_app_inteface           = NULL;
+switch_api_interface_t         * Globals::api_interface                = NULL;
+switch_memory_pool_t           * Globals::module_pool                  = NULL;
+
+volatile bool                    Globals::logs_being_rotated = false;
+
+bool                             Globals::flag_trace_rdsi = false;
diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp
new file mode 100644 (file)
index 0000000..3d1235e
--- /dev/null
@@ -0,0 +1,2516 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "khomp_pvt.h"
+#include "lock.h"
+#include "khomp_pvt_kxe1.h"
+#include "khomp_pvt_gsm.h"
+#include "khomp_pvt_fxo.h"
+#include "khomp_pvt_passive.h"
+#include "utils.h"
+
+Board::VectorBoard  Board::_boards;
+char                Board::_cng_buffer[Globals::cng_buffer_size];
+Kommuter            Board::kommuter;
+
+
+Board::KhompPvt::KhompPvt(K3LAPI::target & target) :
+  _target(target),
+  _mutex(Globals::module_pool),
+  _session(NULL),
+  _caller_profile(NULL),
+  _reader_frames(&_read_codec),
+  _writer_frames(&_write_codec) 
+{    
+    _read_codec.implementation = NULL;
+    _write_codec.implementation = NULL;
+
+    _pvt_statistics = new PvtStatistics(this);
+}
+
+bool Board::initializeK3L(void)
+{
+    LOG(MESSAGE, "starting K3L API ..."); 
+
+    /* Start the API and connect to KServer */
+    k3lSetGlobalParam (klpResetFwOnStartup, 1);
+    k3lSetGlobalParam (klpDisableInternalVoIP, 1);
+
+    try
+    {
+        Globals::k3lapi.start();
+    }
+    catch (K3LAPI::start_failed & e)
+    {
+        LOG(ERROR,FMT("loading K3L API failed: %s") % e.msg);
+        return false;
+    }
+
+    LOG(MESSAGE, "the K3L API have been started!"); 
+    
+    return true;
+}
+
+bool Board::finalizeK3L(void)
+{
+    /* Stop the API and disconnect to KServer */
+    try
+    {
+        Globals::k3lapi.stop();
+    }
+    catch(...)
+    {
+        LOG(ERROR, "K3L not stopped");
+        return false;
+    }
+    LOG(MESSAGE, "K3L stopped.."); 
+    return true;
+}
+
+bool Board::initializeHandlers(void)
+{
+    Globals::global_timer = new Globals::GlobalTimer;
+    Globals::global_timer->start();
+
+    if (Globals::k3lapi.device_count() == 0)
+        return false;
+
+    for (VectorBoard::iterator it_dev = _boards.begin();
+                               it_dev != _boards.end();
+                               it_dev++)
+    {
+        Board * device = *it_dev;
+        device->_event_handler = new ChanEventHandler(device->id(), &eventThread);
+        device->_command_handler = new ChanCommandHandler(device->id(), &commandThread);
+
+        device->_timers.start();
+    }
+
+    k3lRegisterEventHandler( khompEventCallback );
+    k3lRegisterAudioListener( NULL, khompAudioListener );
+
+    LOG(MESSAGE, "K3l event and audio handlers registered."); 
+
+    return true;
+}
+
+bool Board::finalizeHandlers(void)
+{
+    /* if timer still ticks, stop him */
+    if(Globals::global_timer != NULL)
+    {
+        Globals::global_timer->stop();
+        delete Globals::global_timer;
+        Globals::global_timer = NULL;
+    }
+
+    if (Globals::k3lapi.device_count() == 0)
+        return false;
+
+    k3lRegisterEventHandler( NULL );
+    k3lRegisterAudioListener( NULL, NULL );
+
+
+    for (VectorBoard::iterator it_dev = _boards.begin();
+                               it_dev != _boards.end();
+                               it_dev++)
+    {
+        Board * device = *it_dev;        
+        // stop event handler for device
+        ChanEventHandler * evt_handler = device->_event_handler;
+        evt_handler->fifo()->_shutdown = true;
+        evt_handler->signal();
+        delete evt_handler;
+        device->_event_handler = NULL;
+        // stop command handler for device
+        ChanCommandHandler * cmd_handler = device->_command_handler;
+        cmd_handler->fifo()->_shutdown = true;
+        cmd_handler->signal();
+        delete cmd_handler;
+        device->_command_handler = NULL;
+        // stop timer
+        device->_timers.stop();
+    }
+
+    /* wait every thread to finalize */
+    sleep(1);
+
+    LOG(MESSAGE, "K3l event and audio handlers unregistered."); 
+
+    return true;
+
+}
+
+void Board::initializeBoards(void)
+{
+
+    for (unsigned dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+    {
+        LOG(MESSAGE,FMT("loading device %d..." ) % dev); 
+
+        switch(Globals::k3lapi.device_type(dev))
+        {
+            case kdtE1:
+            case kdtE1Spx:
+            case kdtE1GW:
+            case kdtE1IP:
+            case kdtE1FXSSpx:
+            case kdtFXS:
+            case kdtFXSSpx:
+                _boards.push_back(new BoardE1(dev));
+                break;
+            case kdtGSM:
+            case kdtGSMSpx:
+            case kdtGSMUSB:
+            case kdtGSMUSBSpx:
+                _boards.push_back(new BoardGSM(dev));
+                break;
+            case kdtFXO:
+            case kdtFXOVoIP:
+                switch(Globals::k3lapi.device_config(dev).DeviceModel)
+                {
+                case kdmFXO80:
+                    _boards.push_back(new BoardFXO(dev));
+                    break;
+                default:
+                    _boards.push_back(new BoardPassive(dev));
+                    break;
+                }
+                break;
+            case kdtPR:
+                    _boards.push_back(new BoardPassive(dev));
+                    break;
+            default:
+                _boards.push_back(new Board(dev));
+                LOG(ERROR,FMT("device type %d unknown" ) %  Globals::k3lapi.device_type(dev)); 
+                break;
+        }
+        
+        _boards.back()->initializeChannels();
+    }
+}
+
+void Board::initializeChannels(void)
+{
+    LOG(MESSAGE, "loading channels ..."); 
+
+    for (unsigned obj = 0; obj < Globals::k3lapi.channel_count(_device_id); obj++)
+    {
+        K3LAPI::target tgt(Globals::k3lapi, K3LAPI::target::CHANNEL, _device_id, obj);
+
+        KhompPvt * pvt;
+
+               switch(Globals::k3lapi.channel_config(_device_id, obj).Signaling)
+               {
+            case ksigInactive:
+            default:
+                pvt = new Board::KhompPvt(tgt);
+                pvt->_call = new Board::KhompPvt::Call();
+                DBG(FUNC, FMT("signaling %d unknown") % Globals::k3lapi.channel_config(_device_id, obj).Signaling);
+                break;
+        }
+        
+        _channels.push_back(pvt);
+
+        pvt->cleanup();
+    }
+}
+
+void Board::finalizeBoards(void)
+{
+    LOG(MESSAGE, "finalizing boards ..."); 
+
+    for (VectorBoard::iterator it_dev = _boards.begin();
+                               it_dev != _boards.end();
+                               it_dev++)
+    {
+        Board * & device_ref = *it_dev;
+        Board *   device_ptr = device_ref;
+
+        device_ptr->finalizeChannels();
+
+        device_ref = (Board *) NULL;
+
+        delete device_ptr;
+    }
+
+}
+
+void Board::finalizeChannels()
+{
+    LOG(MESSAGE, "finalizing channels ..."); 
+    for (VectorChannel::iterator it_obj = _channels.begin();
+         it_obj != _channels.end();
+         it_obj++)
+    {
+        KhompPvt * & pvt_ref = *it_obj;
+        KhompPvt *   pvt_ptr = pvt_ref;
+
+        if(!pvt_ptr)
+            continue;
+
+        try
+        {
+            ScopedPvtLock lock(pvt_ptr);
+
+            if(pvt_ptr->session())
+            {
+                //TODO: Tratamento para desconectar do canal do FreeSwitch.
+                pvt_ptr->cleanup();
+            }
+
+            delete pvt_ptr->_call;
+            pvt_ptr->_call = NULL;
+
+            pvt_ref = (KhompPvt *) NULL;
+        }
+        catch(...)
+        {
+            /* keep walking! */
+        }
+
+        delete pvt_ptr;
+    }
+}
+
+void Board::initializeCngBuffer(void)
+{
+    bool turn = true;
+
+    for (unsigned int i = 0; i < Globals::cng_buffer_size; i++)
+    {
+        _cng_buffer[i] = (turn ? 0xD5 : 0xD4);
+        turn = !turn;
+    }
+}
+
+bool Board::initialize(void)
+{
+    initializeCngBuffer();
+
+    initializeBoards();
+
+    return true;
+}
+
+bool Board::finalize(void)
+{
+    finalizeBoards();
+
+    return finalizeK3L();
+}
+
+void Board::khomp_add_event_board_data(const K3LAPI::target target, switch_event_t *event)
+{
+
+    //if (!event) {
+        //TODO: RAISE!
+    //}
+
+    try
+    {
+        if (target.type == K3LAPI::target::CHANNEL)
+        {
+            switch_core_session_t * s = get(target.device, target.object)->session();
+            switch_channel_event_set_data(Board::KhompPvt::getFSChannel(s), event);
+        }
+
+        switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Khomp-DeviceId", "%u", target.device);
+        switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Khomp-Object", "%u", target.object);
+    }
+    catch(K3LAPI::invalid_channel & err)
+    {
+        LOG(ERROR, PVT_FMT(target, "Invalid channel"));
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target, "No valid channel: %s") % err._msg.c_str());
+    }
+}
+
+std::string Board::KhompPvt::getStatistics(Statistics::Type type)
+{
+    switch(type)
+    {
+        case Statistics::DETAILED:
+        {
+            return _pvt_statistics->getDetailed();
+        }
+        case Statistics::ROW:
+        {
+            return _pvt_statistics->getRow();
+        }
+        default:
+            return "";
+    }
+}
+
+std::string Board::KhompPvt::PvtStatistics::getDetailedRates()
+{
+    /* skip inactive channels */
+    //if (_pvt->getSignaling() == ksigInactive) return "";
+
+    /* buffer our data to return at the end */
+    std::string strBuffer;
+
+    /* this values come from kserver */
+    unsigned int call_incoming = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiInbound);
+    unsigned int call_outgoing = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiOutbound);
+
+    float occupation_rate = 100.0;
+
+    if (_pvt->call()->statistics()->_total_idle_time > 0)
+    {
+        occupation_rate = 100 * (
+            _pvt->call()->statistics()->_total_time_incoming + 
+            _pvt->call()->statistics()->_total_time_outgoing
+            ) / (
+            _pvt->call()->statistics()->_total_idle_time + 
+            _pvt->call()->statistics()->_total_time_incoming + 
+            _pvt->call()->statistics()->_total_time_outgoing);
+    }
+
+    strBuffer.append(STG(FMT("Occupation rate: \t\t%0.2f%%\n") % occupation_rate));
+
+    if (call_incoming > 0) 
+    {    
+        std::string str_calls_incoming_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_incoming / call_incoming) );
+        strBuffer.append(STG(FMT("Mean duration time of incoming calls: %s\n") % str_calls_incoming_mean));
+    }    
+
+    if (call_outgoing > 0) 
+    {    
+        std::string str_calls_outgoing_mean = timeToString ( (time_t) (_pvt->call()->statistics()->_total_time_outgoing / call_outgoing) );
+        strBuffer.append(STG(FMT("Mean duration time of outgoing calls: %s\n") % str_calls_outgoing_mean));
+    }    
+
+    return strBuffer;
+}
+
+std::string Board::KhompPvt::PvtStatistics::getDetailed()
+{ 
+    /* skip inactive channels */
+    //if (_pvt->getSignaling() == ksigInactive) return "";
+
+    /* buffer our data to return at the end */
+    std::string strBuffer;
+            
+    strBuffer.append(_pvt->call()->statistics()->getDetailed());
+
+    /* this values come from kserver */
+    unsigned int call_incoming = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiInbound);
+    unsigned int call_outgoing = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiOutbound);
+    unsigned int call_fails    = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiOutFailed);
+
+    strBuffer.append(STG(FMT("Number of incoming calls: \t%d\n") % call_incoming));
+    strBuffer.append(STG(FMT("Number of outgoing calls: \t%d\n") % call_outgoing));
+    strBuffer.append(STG(FMT("Number of calls failed: \t%d\n") % call_fails));
+
+    strBuffer.append(getDetailedRates());
+    
+    return strBuffer;
+}
+
+std::string Board::KhompPvt::PvtStatistics::getRow() 
+{
+    /* skip inactive channels */
+    //if (_pvt->getSignaling() == ksigInactive) return "";
+
+    time_t action_time;
+    time (&action_time);
+   
+    action_time -= _pvt->call()->statistics()->_base_time;
+
+    uint32 calls_incoming = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiInbound);
+    uint32 calls_outgoing = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiOutbound);
+    uint32 call_fails     = Globals::k3lapi.channel_stats(
+            _pvt->target().device, _pvt->target().object, kcsiOutFailed);
+    
+    std::string string_time = "  n/a  ";
+    std::string call_type   = "  none  ";
+
+    if (_pvt->call()->_flags.check(Kflags::IS_INCOMING))
+        call_type = "incoming";
+    else if (_pvt->call()->_flags.check(Kflags::IS_OUTGOING))
+        call_type = "outgoing";
+
+    if (_pvt->owner())
+    {    
+        string_time = timeToString(action_time);
+    }    
+
+    return  STG(FMT("| %d,%02d | %8d | %8d | %8d | %7d | %10s | %8s | %8s |")
+            % _pvt->target().device 
+            % _pvt->target().object 
+            % calls_incoming 
+            % calls_outgoing 
+            % _pvt->call()->statistics()->_channel_fails
+            % call_fails 
+            % _pvt->getStateString() 
+            % call_type 
+            % string_time);
+}
+
+switch_status_t Board::KhompPvt::justAlloc(bool is_answering, switch_memory_pool_t **pool)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    if(is_answering)
+    {
+        /* Create a new session on incoming call */
+        call()->_flags.set(Kflags::IS_INCOMING);
+        if(!session())
+        {
+#if SWITCH_LESS_THAN(1,0,6)
+            session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL));
+#else            
+            session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL));
+#endif            
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(target(), "Session already created"));
+        }
+    }
+    else
+    {
+        /* Create a new session on outgoing call */
+        call()->_flags.set(Kflags::IS_OUTGOING);
+#if SWITCH_LESS_THAN(1,0,6)        
+        session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool));
+#else
+        session(switch_core_session_request(Globals::khomp_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, SOF_NONE, pool));
+#endif
+    }
+
+    if(!session())
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (Initilization Error, session not created!)"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    switch_core_session_add_stream(session(), NULL);
+
+    if (switch_core_codec_init(&_read_codec, "PCMA", NULL, 8000, Globals::switch_packet_duration, 1,
+            SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
+                (pool ? *pool : NULL)) != SWITCH_STATUS_SUCCESS)
+    {
+        destroy();
+        LOG(ERROR, PVT_FMT(target(), "r (Error while init read codecs)"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    if (switch_core_codec_init(&_write_codec, "PCMA", NULL, 8000, Globals::switch_packet_duration, 1,
+            SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
+                (pool ? *pool : NULL)) != SWITCH_STATUS_SUCCESS)
+    {
+        destroy();
+        LOG(ERROR, PVT_FMT(target(), "r (Error while init write codecs)"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    //TODO: Retirar daqui
+//    switch_mutex_init(&flag_mutex, SWITCH_MUTEX_NESTED,
+//                switch_core_session_get_pool(_session));
+
+    switch_core_session_set_private(_session, this);
+
+    if((switch_core_session_set_read_codec(_session, &_read_codec) !=
+                SWITCH_STATUS_SUCCESS) ||
+       (switch_core_session_set_write_codec(_session, &_write_codec) !=
+                SWITCH_STATUS_SUCCESS))
+    {
+        destroy();
+        LOG(ERROR, PVT_FMT(target(), "r (Error while set read codecs)"));
+        return SWITCH_STATUS_FALSE;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t Board::KhompPvt::justStart(switch_caller_profile_t *profile)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    try
+    {
+        switch_channel_t *channel = getFSChannel();
+        
+        if(call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            std::string exten("s");
+
+            owner(_session);
+
+            if(call()->_incoming_context.empty())
+            {
+                Board::KhompPvt::ContextListType contexts;
+                std::string context("default");
+
+                if(!validContexts(contexts))
+                {
+                    destroy();
+                    owner(NULL);
+                    LOG(ERROR, PVT_FMT(_target, "r (Invalid context)"));
+                    return SWITCH_STATUS_FALSE;
+                }
+
+                switch(findExtension(exten, context, contexts, _call->_dest_addr, _call->_orig_addr)) 
+                {
+                    case MATCH_NONE:
+                        destroy();
+                        owner(NULL);
+                        LOG(ERROR, PVT_FMT(_target, "r (unable to find exten/context on incoming call %s/%s)")
+                                % _call->_dest_addr % (contexts.size() >= 1 ? contexts[0] : "default"));
+                        return SWITCH_STATUS_FALSE; 
+                    default:
+                        DBG(FUNC, PVT_FMT(_target, "our: context '%s', exten '%s'") % context % exten);
+                        break;
+                }
+
+                call()->_incoming_context = context;
+            }
+            else
+            {
+                exten = call()->_dest_addr;
+                DBG(FUNC, PVT_FMT(target(), "already found our: context '%s', exten '%s'") % call()->_incoming_context % exten);
+            }
+            
+            _caller_profile = switch_caller_profile_new(switch_core_session_get_pool(_session),
+                    "Khomp",                           //username
+                    "XML",                             //dialplan
+                    NULL,                              //caller_id_name
+                    _call->_orig_addr.c_str(),         //caller_id_number
+                    NULL,                              //network_addr
+                    _call->_orig_addr.c_str(),         //ani
+                    NULL,                              //aniii
+                    NULL,                              //rdnis
+                    (char *) "mod_khomp",              //source
+                    call()->_incoming_context.c_str(), //context
+                    exten.c_str());                    //destination_number
+
+            if(!_caller_profile)
+            {
+                destroy();
+                owner(NULL);
+                LOG(ERROR, PVT_FMT(_target, "r (Cannot create caller profile)"));
+                return SWITCH_STATUS_FALSE;
+            }
+
+            std::string name = STG(FMT("Khomp/%hu/%hu/%s")
+                    % target().device
+                    % target().object
+                    % _call->_dest_addr);
+
+            DBG(FUNC, PVT_FMT(target(), "Connect inbound channel %s") % name.c_str());
+
+            switch_channel_set_name(channel, name.c_str());
+            switch_channel_set_caller_profile(channel, _caller_profile);
+
+            switch_channel_set_state(channel, CS_INIT);
+
+            setSpecialVariables();
+
+            if (switch_core_session_thread_launch(_session) != SWITCH_STATUS_SUCCESS)
+            {
+                destroy();
+                owner(NULL);
+                LOG(ERROR, PVT_FMT(target(), "r (Error spawning thread)"));
+                return SWITCH_STATUS_FALSE;
+            }
+        }
+        else if(call()->_flags.check(Kflags::IS_OUTGOING))
+        {
+            if(_call->_orig_addr.empty())
+                _call->_orig_addr = profile->caller_id_number;
+
+            switch_channel_set_name(channel, STG(FMT("Khomp/%hu/%hu/%s")
+                        % target().device
+                        % target().object
+                        % (!_call->_dest_addr.empty() ? _call->_dest_addr.c_str() : "")).c_str());
+            _caller_profile = switch_caller_profile_clone(_session, profile);
+            switch_channel_set_caller_profile(channel, _caller_profile);
+
+            switch_channel_set_flag(channel, CF_OUTBOUND);
+            switch_channel_set_state(channel, CS_INIT);
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(target(), "r (Not INCOMING or OUTGOING)"));
+            return SWITCH_STATUS_FALSE;
+        }
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        destroy();
+        owner(NULL);
+        DBG(FUNC, PVT_FMT(target(), "r (%s)") % err._msg.c_str()); 
+        return SWITCH_STATUS_FALSE;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return SWITCH_STATUS_SUCCESS;
+}
+        
+int Board::KhompPvt::makeCall(std::string params)
+{
+    DBG(FUNC, PVT_FMT(target(), "Dialing to %s from %s")
+        % _call->_dest_addr.c_str()
+        % _call->_orig_addr.c_str());
+
+    /* Lets make the call! */
+    std::string full_params;
+    
+    if(!_call->_dest_addr.empty())
+        full_params += STG(FMT(" dest_addr=\"%s\"")
+                % _call->_dest_addr);
+
+    if(!params.empty())
+        full_params += STG(FMT(" %s")
+                % params);
+
+    DBG(FUNC, PVT_FMT(target(), "We are calling with params: %s.") % full_params.c_str());
+
+    int ret = commandState(KHOMP_LOG, CM_MAKE_CALL, (full_params != "" ? full_params.c_str() : NULL));
+
+    if(ret != ksSuccess)
+    {
+        destroy();
+        cleanup(CLN_FAIL);
+    }
+
+    return ret;
+}
+
+bool Board::KhompPvt::signalDTMF(char d)
+{
+    DBG(FUNC, PVT_FMT(target(), "c (dtmf=%c)") % d);
+
+    try
+    {
+        switch_dtmf_t dtmf = { (char) d, switch_core_default_dtmf_duration(0) };
+        switch_channel_queue_dtmf(getFSChannel(), &dtmf);
+    }
+    catch (Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (Received a DTMF, but %s)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+
+    return true;
+}
+
+bool Board::KhompPvt::indicateBusyUnlocked(int cause, bool sent_signaling)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    /* already playing! */
+    if (call()->_indication != INDICA_NONE)
+    {
+        if (call()->_indication == INDICA_RING)
+        {
+            DBG(FUNC, PVT_FMT(target(), "ringback being disabled"));
+
+            if(call()->_cadence == PLAY_RINGBACK)
+                stopCadence();
+
+            try
+            {
+                call()->_flags.clear(Kflags::GEN_PBX_RING);
+                call()->_flags.clear(Kflags::GEN_CO_RING);
+
+                Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
+                Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
+            }
+            catch (K3LAPI::invalid_device & err)
+            {
+                LOG(ERROR, PVT_FMT(_target, "Unable to get device: %d!") % err.device);
+            }
+
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+            call()->_indication = INDICA_NONE;
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(target(), "r (already playing something: %d)") 
+                    % call()->_indication);
+            return false;
+        }
+    }
+
+    setHangupCause(cause, false);
+
+    call()->_indication = INDICA_BUSY;
+        
+    DBG(FUNC, PVT_FMT(target(), "r"));
+
+    return true;
+}
+
+void Board::KhompPvt::destroy(switch_core_session_t * s)
+{
+    switch_core_session_t * tmp_session;
+
+    if(!s)
+    {
+        if(!_session)
+            return;
+    
+        tmp_session = _session;
+    }
+    else
+    {
+        tmp_session = s;
+        
+    }
+
+    switch_core_session_destroy(&tmp_session);
+}
+
+void Board::KhompPvt::destroyAll()
+{
+    if(_session)
+    {
+        switch_core_session_set_private(_session, NULL);
+        _session = NULL;
+    }
+
+    if(_caller_profile)
+    {
+        //DBG(FUNC, PVT_FMT(target(), "Profile != NULL"));
+        //TODO: Destruir
+        _caller_profile = NULL;
+    }
+
+    if (switch_core_codec_ready(&_read_codec)) {
+        //if(session())
+        //    switch_core_session_lock_codec_read(_session);
+        switch_core_codec_destroy(&_read_codec);
+        _read_codec.implementation = NULL;
+        //if(session())
+        //    switch_core_session_unlock_codec_read(_session);
+    }
+
+    if (switch_core_codec_ready(&_write_codec)) {
+        //if(session())
+        //    switch_core_session_lock_codec_write(_session);
+        switch_core_codec_destroy(&_write_codec);
+        _write_codec.implementation = NULL;
+        //if(session())
+        //    switch_core_session_unlock_codec_write(_session);
+    }
+
+}
+
+void Board::KhompPvt::doHangup()
+{
+    owner(NULL);
+
+    try
+    {
+        switch_channel_t *channel = getFSChannel();
+
+        int cause_from_freeswitch = switch_channel_get_cause(channel);
+        if(cause_from_freeswitch != SWITCH_CAUSE_NONE)
+        {
+            DBG(FUNC, PVT_FMT(_target, "cause already set to %s from freeswitch") % switch_channel_cause2str((switch_call_cause_t)cause_from_freeswitch));
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(target(), "Hangup channel \"%s\"") % switch_channel_get_name(channel));
+
+            switch_channel_hangup(channel, (switch_call_cause_t)call()->_hangup_cause);
+        }
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        //DBG(FUNC, PVT_FMT(target(), "Hangup channel already done"));
+    }
+}
+
+bool Board::KhompPvt::cleanup(CleanupType type)
+{
+//    flags = 0;
+
+    _reader_frames.clear();
+    _writer_frames.clear();
+    
+    call()->_flags.clear(Kflags::CONNECTED);
+    
+    //call()->_flags.clear(Kflags::BRIDGED);
+    
+    call()->_flags.clear(Kflags::DROP_COLLECT);
+    
+    call()->_flags.clear(Kflags::OUT_OF_BAND_DTMFS);
+
+    call()->_flags.clear(Kflags::WAIT_SEND_DTMF);
+    
+    call()->_flags.clear(Kflags::GEN_PBX_RING);
+    call()->_flags.clear(Kflags::GEN_CO_RING);
+
+    try
+    {
+        Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
+        Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "Unable to get device: %d!") % err.device);
+    }
+        
+    call()->_idx_pbx_ring.reset();
+    call()->_idx_co_ring.reset();
+
+    switch (type)
+    {
+    case CLN_HARD:
+    case CLN_FAIL:
+        call()->_flags.clear(Kflags::KEEP_DTMF_SUPPRESSION);
+        call()->_flags.clear(Kflags::KEEP_ECHO_CANCELLATION);
+        call()->_flags.clear(Kflags::KEEP_AUTO_GAIN_CONTROL);
+
+        stopStream();
+        stopListen();
+        doHangup();
+        call()->_flags.clear(Kflags::IS_INCOMING);
+        call()->_flags.clear(Kflags::IS_OUTGOING);
+        call()->_flags.clear(Kflags::REALLY_CONNECTED);
+        call()->_flags.clear(Kflags::HAS_PRE_AUDIO);
+        call()->_flags.clear(Kflags::HAS_CALL_FAIL);
+
+        /* pára cadências e limpa estado das flags */
+        stopCadence();
+
+        if (call()->_indication != INDICA_NONE)
+        {
+            call()->_indication = INDICA_NONE;
+
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+        }
+
+        if(call()->_input_volume >= -10 && call()->_input_volume <= 10)
+            setVolume("input" , Opt::_input_volume);
+
+        if(call()->_output_volume >= -10 && call()->_output_volume <= 10)
+            setVolume("output", Opt::_output_volume);        
+
+        return _call->clear();
+    case CLN_SOFT:
+        if(call()->_cadence != PLAY_FASTBUSY)
+        {    
+            /* pára cadências e limpa estado das flags */
+            stopCadence();
+        }
+
+        if (call()->_indication == INDICA_RING)
+        {
+            call()->_indication = INDICA_NONE;
+
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+        }
+        break;
+    }
+
+    return true;
+}
+
+bool Board::KhompPvt::isFree(bool just_phy)
+{
+    //DBG(FUNC, DP(this, "c"));
+       try
+       {
+        bool is_physical_free = isPhysicalFree();
+
+               /* if we got here, is physically free */
+               if (!is_physical_free || just_phy)
+                       return is_physical_free;
+
+        ScopedPvtLock lock(this);
+
+        if(session())
+            return false;
+
+        /*
+               if (!is_gsm())
+               {
+                       if (calls.at(0).owner != NULL)
+                       {
+                               DBG(FUNC, DP(this, "we have owner, not free!"));
+                               return false;
+                       }
+               }
+               else
+               {
+                       for (int i = 0; i < 6; i++)
+                       {
+
+                               call_data_type & data = calls.at(i);
+
+                               if (data.owner != NULL)
+                                       return false;
+                       }
+               }
+        */
+
+               bool free_state = !(_call->_flags.check(Kflags::IS_INCOMING) || _call->_flags.check(Kflags::IS_OUTGOING));
+
+               DBG(FUNC, PVT_FMT(target(), "[free = %s]") % (free_state ? "yes" : "no"));
+               return free_state;
+       }
+    catch (ScopedLockFailed & err)
+       {
+               DBG(FUNC, PVT_FMT(target(), "unable to obtain lock: %s") % err._msg.c_str());
+       }
+
+       return false;
+}
+
+Board::KhompPvt * Board::queueFindFree(PriorityCallQueue &pqueue)
+{
+    for (PriorityCallQueue::iterator i = pqueue.begin(); i != pqueue.end(); i++)
+    {
+        KhompPvt *pvt = (*i);
+        if (pvt && pvt->isFree())
+        {
+            return pvt;
+        }
+    }
+
+    DBG(FUNC, D("found no free channel for fair allocation!"));
+    return NULL;
+}
+
+void Board::queueAddChannel(PriorityCallQueue &pqueue, unsigned int board, unsigned int object)
+{
+    try
+    {
+        KhompPvt * pvt = get(board, object);
+        pqueue.insert(pvt);
+    }
+    catch(K3LAPI::invalid_channel & err)
+    {
+        //...
+    }
+}
+
+Board::KhompPvt * Board::findFree(unsigned int board, unsigned int object, bool fully_available)
+{
+    try
+    {
+        KhompPvt * pvt = get(board, object);
+        return ((fully_available ? pvt->isFree() : pvt->isOK()) ? pvt : NULL);
+    }
+    catch(K3LAPI::invalid_channel & err)
+    {
+    }
+    return NULL;
+}
+
+void Board::applyGlobalVolume(void)
+{
+    DBG(FUNC, "c");
+
+    for (unsigned int dev = 0; dev < Globals::k3lapi.device_count(); dev++)
+    {    
+        for (unsigned int obj = 0; obj < Globals::k3lapi.channel_count(dev); obj++)
+        {
+            try
+            {
+                Board::get(dev,obj)->setVolume("input", Opt::_input_volume);
+                Board::get(dev,obj)->setVolume("output",Opt::_output_volume);
+            }
+            catch(K3LAPI::invalid_channel & err)
+            {
+                DBG(FUNC, OBJ_FMT(dev, obj, "Channel not found"));
+            }
+        }    
+    }    
+    
+    DBG(FUNC, "r");
+}
+
+bool Board::KhompPvt::startCadence(CadencesType type) 
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    std::string tone("");
+
+    /**/ if (type == PLAY_VM_TONE)  tone = "vm-dialtone";
+    else if (type == PLAY_PBX_TONE) tone = "pbx-dialtone";
+    else if (type == PLAY_PUB_TONE) tone = "co-dialtone";
+    else if (type == PLAY_RINGBACK) tone = "ringback";
+    else if (type == PLAY_FASTBUSY) tone = "fast-busy";
+
+
+    if (tone != "")
+    {    
+        call()->_cadence = type;
+
+        Opt::CadencesMapType::iterator i = Opt::_cadences.find(tone);
+        std::string cmd_params;
+
+        if (i != Opt::_cadences.end())
+        {    
+            CadenceType cadence = (*i).second;
+
+            if (cadence.ring == 0 && cadence.ring_s == 0)
+            {    
+                cmd_params = "cadence_times=\"continuous\" mixer_track=1";
+            }    
+            else if (cadence.ring_ext == 0 && cadence.ring_ext_s == 0)
+            {    
+                cmd_params = STG(FMT("cadence_times=\"%d,%d\" mixer_track=1")
+                    % cadence.ring % cadence.ring_s);
+            }    
+            else 
+            {    
+                cmd_params = STG(FMT("cadence_times=\"%d,%d,%d,%d\" mixer_track=1")
+                    % cadence.ring % cadence.ring_s % cadence.ring_ext % cadence.ring_ext_s);
+            }    
+
+            command(KHOMP_LOG,CM_START_CADENCE,cmd_params.c_str());
+        }
+        else
+        {
+            LOG(ERROR, PVT_FMT(_target, "r (cadence '%s' not found)") % tone);
+            return false;
+        }
+    }
+    else
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unknown cadence requested )"));
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return true;
+}
+
+/* Helper functions - based on code from chan_khomp */
+bool Board::KhompPvt::startStream(bool enable_mixer)
+{
+    if (call()->_flags.check(Kflags::STREAM_UP))
+        return true;
+
+    if(enable_mixer)
+    {
+        if(!mixer(KHOMP_LOG, 0, kmsPlay, _target.object))
+            return false;
+    }
+
+    if(!command(KHOMP_LOG, CM_START_STREAM_BUFFER))
+        return false;
+
+    call()->_flags.set(Kflags::STREAM_UP);
+
+    return true;
+}
+
+bool Board::KhompPvt::stopStream(bool enable_mixer)
+{
+    if (!call()->_flags.check(Kflags::STREAM_UP))
+        return true;
+
+    call()->_flags.clear(Kflags::STREAM_UP);
+
+    if(enable_mixer)
+    {
+        if(!mixer(KHOMP_LOG, 0, kmsGenerator, kmtSilence))
+            return false;
+    }
+
+    if(!command(KHOMP_LOG, CM_STOP_STREAM_BUFFER))
+        return false;
+
+    return true;
+}
+
+bool Board::KhompPvt::startListen(bool conn_rx)
+{
+    if(call()->_flags.check(Kflags::LISTEN_UP))
+        return true;
+
+    const size_t buffer_size = Globals::boards_packet_duration;
+
+    if(conn_rx)
+    {
+        if(!obtainRX(false)) //no delay, by default..
+            return false;
+    }
+
+    if(!command(KHOMP_LOG, CM_LISTEN, (const char *) &buffer_size))
+        return false;
+
+    call()->_flags.set(Kflags::LISTEN_UP);
+
+    return true;
+}
+
+bool Board::KhompPvt::stopListen(void)
+{
+    if(!call()->_flags.check(Kflags::LISTEN_UP))
+        return true;
+
+    call()->_flags.clear(Kflags::LISTEN_UP);
+
+    if(!command(KHOMP_LOG, CM_STOP_LISTEN))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool Board::KhompPvt::obtainRX(bool with_delay)
+{
+    try
+    {
+        Globals::k3lapi.mixerRecord(_target, 0, (with_delay ? kmsChannel : kmsNoDelayChannel), target().object);
+        Globals::k3lapi.mixerRecord(_target, 1, kmsGenerator, kmtSilence);
+    }
+    catch(K3LAPI::failed_raw_command & e)
+    {
+        LOG(ERROR, PVT_FMT(target(), "ERROR sending mixer record command!"));
+        return false;
+    }    
+    return true;
+}
+
+bool Board::KhompPvt::obtainTX()
+{
+    /* estes buffers *NAO PODEM SER ESTATICOS*! */
+    char cmd1[] = { 0x3f, 0x03, 0xff, 0x00, 0x00, 0xff };
+    char cmd2[] = { 0x3f, 0x03, 0xff, 0x01, 0x09, 0x0f };
+
+    cmd1[2] = cmd1[5] = cmd2[2] = _target.object;
+
+    try
+    {
+        int dsp = Globals::k3lapi.get_dsp(_target.device, K3LAPI::DSP_AUDIO);
+
+        Globals::k3lapi.raw_command(_target.device, dsp, cmd1, sizeof(cmd1));
+
+        Globals::k3lapi.raw_command(_target.device, dsp, cmd2, sizeof(cmd2));
+
+    }
+    catch(K3LAPI::failed_raw_command & e)
+    {
+        LOG(ERROR, PVT_FMT(target(), "ERROR sending mixer command!"));
+        return false;
+    }    
+
+    return true;
+}
+
+bool Board::KhompPvt::sendDtmf(std::string digit)
+{
+    if(!call()->_flags.check(Kflags::STREAM_UP))
+    {
+        DBG(FUNC, PVT_FMT(target(), "stream down, not sending dtmf"));
+        return false;
+    }
+
+    if(!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS))
+    {
+        DBG(FUNC, PVT_FMT(target(), "dtmf suppression disabled, not generating dtmf"));
+        return false;
+    }
+
+    if(digit.empty())
+    {
+        DBG(FUNC, PVT_FMT(target(), "not sending dtmf (there is nothing to send)"));
+        return false;
+    }
+
+    if(call()->_flags.check(Kflags::WAIT_SEND_DTMF))
+    {
+        DBG(FUNC, PVT_FMT(target(), "queueing dtmf (%s)") % digit);
+        call()->_queued_digits_buffer += digit;
+        return true;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "sending dtmf (%s)") % digit);
+    
+    call()->_flags.set(Kflags::WAIT_SEND_DTMF);
+
+    return command(KHOMP_LOG, CM_DIAL_DTMF, digit.c_str());
+}
+
+bool Board::KhompPvt::setVolume(const char * type, int volume)
+{
+    std::string arg = STG(FMT("volume=\"%d\" type=\"%s\"") % volume % type);
+    DBG(FUNC, PVT_FMT(_target, "%s") % arg);
+    return command(KHOMP_LOG,CM_SET_VOLUME,arg.c_str());
+}
+
+std::string Board::KhompPvt::getStateString(void)
+{
+    try
+    {
+        switch_channel_t *c = getFSChannel();
+        if(!c) return "unused";
+
+        switch_channel_state_t state = switch_channel_get_state(c);
+
+        /* shortcut */
+        typedef std::string S;
+
+        switch (state)
+        {    
+            case CS_NEW:               return S("new");
+            case CS_INIT:              return S("init");
+            case CS_ROUTING:           return S("routing");
+            case CS_SOFT_EXECUTE:      return S("sf_exec");
+            case CS_EXECUTE:           return S("execute");
+            case CS_EXCHANGE_MEDIA:    return S("ex_media");
+            case CS_PARK:              return S("park");
+            case CS_CONSUME_MEDIA:     return S("cs_media");
+            case CS_HIBERNATE:         return S("hibernat");
+            case CS_RESET:             return S("reset");
+            case CS_HANGUP:            return S("hangup");
+            case CS_REPORTING:         return S("reportg");
+            case CS_DESTROY:           return S("destroy");
+            case CS_NONE:              return S("none");
+            default:
+                return STG(FMT("none (%d)") % state);
+        }    
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        return "unused";
+    }
+}
+
+bool Board::KhompPvt::dtmfSuppression(bool enable)
+{
+    if (!command(KHOMP_LOG, (enable ? CM_ENABLE_DTMF_SUPPRESSION : CM_DISABLE_DTMF_SUPPRESSION)))
+        return false;
+
+    if (enable) call()->_flags.set(Kflags::OUT_OF_BAND_DTMFS);
+    else        call()->_flags.clear(Kflags::OUT_OF_BAND_DTMFS);
+
+    DBG(FUNC, PVT_FMT(_target, "flag OUT_OF_BAND_DTMFS is : %s") % 
+        (call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS) ? "true" : "false"));
+    
+    return true;
+}
+
+bool Board::KhompPvt::echoCancellation(bool enable)
+{
+    K3L_DEVICE_CONFIG & devCfg = Globals::k3lapi.device_config(_target.device);
+
+    /* echo canceller should not be used for non-echo cancellable channels */
+    switch (devCfg.EchoConfig)
+    {
+        case keccFail:
+            if (!enable)
+                return true;
+
+            LOG(ERROR, PVT_FMT(_target, "unable to activate echo cancellation"));
+            return false;
+
+        case keccNotPresent:
+            DBG(FUNC, PVT_FMT(_target, "echo cancellation not present, not %s.") % (enable ? "enabling" : "disabling"));
+            return true;
+
+        default:
+            return command(KHOMP_LOG,(enable ? CM_ENABLE_ECHO_CANCELLER : CM_DISABLE_ECHO_CANCELLER));
+    }
+}
+
+bool Board::KhompPvt::autoGainControl(bool enable)
+{
+    bool ret = command(KHOMP_LOG,(enable ? CM_ENABLE_AGC : CM_DISABLE_AGC));//, SCE_SHOW_DEBUG);
+    return ret;
+}
+
+void Board::KhompPvt::pbxRingGen(Board::KhompPvt * pvt)
+{
+    DBG(FUNC, PVT_FMT(pvt->target(), "Generating pbx ring"));
+
+    try 
+    {   
+        ScopedPvtLock lock(pvt);
+
+        if (!pvt->call()->_flags.check(Kflags::GEN_PBX_RING))
+            return;
+
+        if (!pvt->obtainTX())
+            return;
+
+        pvt->startCadence(PLAY_RINGBACK);
+    }   
+    catch (...)
+    {
+        LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock!"));
+    }
+}
+
+void Board::KhompPvt::coRingGen(Board::KhompPvt * pvt)
+{
+    DBG(FUNC, PVT_FMT(pvt->target(), "Generating co ring"));
+
+    try 
+    {   
+        ScopedPvtLock lock(pvt);
+
+        if (!pvt->call()->_flags.check(Kflags::GEN_CO_RING))
+            return;
+
+        pvt->startCadence(PLAY_RINGBACK);
+    }   
+    catch (...)
+    {
+        LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock the pvt !"));
+    }  
+}
+
+int Board::KhompPvt::getActiveChannel(bool invalid_as_not_found)
+{
+    // AT CONSTRUCTION
+    return 0;
+}
+
+MatchType Board::KhompPvt::matchExtension(std::string & context, std::string & exten,
+                                                           std::string & callerid, bool match_only)
+{
+    if(!canMatch(context,exten,callerid))
+    {
+        DBG(FUNC, "context/extension cannot match");
+        return MATCH_NONE;
+    }
+
+    if(match_only)
+    {
+        DBG(FUNC, "for now we want know if it matches...");
+        return MATCH_MORE;
+    }
+
+    if(!canMatch(context,exten,callerid,true))
+    {
+        DBG(FUNC, "it match exact!");
+        return MATCH_EXACT;
+    }
+
+    return MATCH_MORE;
+}
+
+MatchType Board::KhompPvt::findExtension(std::string & ref_extension, 
+                                         std::string & ref_context,
+                                         ContextListType & contexts,
+                                         std::string & extension,
+                                         std::string & caller_id,
+                                         bool default_ctx,
+                                         bool default_ext)
+{
+    Board::KhompPvt::ExtenListType extens;
+
+    if(!extension.empty())
+    {
+        extens.push_back(extension);
+    }
+
+    if(default_ext)
+    {
+        if (extension != "s")
+        {
+            extens.push_back("s");
+        }
+
+        extens.push_back("i");
+    }
+
+    if(default_ctx)
+    {
+        contexts.push_back("default");
+    }
+
+    for(Board::KhompPvt::ContextListType::iterator itc = contexts.begin(); itc != contexts.end(); itc++)
+    {
+        for(Board::KhompPvt::ExtenListType::iterator ite = extens.begin(); ite != extens.end(); ite++)
+        {
+            DBG(FUNC, FMT("trying context '%s' with exten '%s'...") % *itc % *ite);
+
+            MatchType m = matchExtension(*itc, *ite, caller_id, false);
+
+            switch (m)
+            {    
+                case MATCH_NONE:
+                    continue;
+
+                case MATCH_MORE:
+                case MATCH_EXACT:
+                {    
+                    ref_context = *itc;
+                    ref_extension = *ite;
+
+                    DBG(FUNC, ".... can match context/extension (some way)!");
+
+                    return m;
+                }    
+            } 
+        }
+    }
+
+    DBG(FUNC, D("... no context/extension found!"));
+    return MATCH_NONE;
+}
+
+bool Board::KhompPvt::setCollectCall()
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+    // NEEDS LOCK !?
+
+    std::vector< TriState > confvalues;
+    // temporary!
+    const char * tmp_var = NULL;
+
+    // get option configuration value
+    confvalues.push_back(Opt::_drop_collect_call ? T_TRUE : T_FALSE);
+    DBG(FUNC, PVT_FMT(_target, "option drop collect call is '%s'") % (Opt::_drop_collect_call ? "yes" : "no"));
+
+    // get global filter configuration value
+    tmp_var = switch_core_get_variable("KDropCollectCall");
+    confvalues.push_back(getTriStateValue(tmp_var));
+    DBG(FUNC, PVT_FMT(_target, "global KDropCollectCall was '%s'") % (tmp_var ? tmp_var : "(empty)"));
+
+    try 
+    {
+        // get local filter configuration value
+        tmp_var = switch_channel_get_variable(getFSChannel(), "KDropCollectCall");
+        confvalues.push_back(getTriStateValue(tmp_var));
+        DBG(FUNC, PVT_FMT(_target, "local KDropCollectCall was '%s'") % (tmp_var ? tmp_var : "(empty)"));
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "Cannot obtain the channel variable: %s") % err._msg.c_str()); 
+    }
+
+    // store last state assigned
+    bool last_state = false;
+
+    // validate the states
+    std::vector< TriState >::const_iterator end = confvalues.end();
+    for (std::vector< TriState >::const_iterator i = confvalues.begin(); i != end; ++i)
+    {
+        switch(*i)
+        {
+            case T_TRUE:
+                last_state = true;
+                break;
+            case T_FALSE:
+                last_state = false;
+                break;
+            case T_UNKNOWN:
+            default:
+                break;
+        }
+    }
+
+    if (last_state)
+        call()->_flags.set(Kflags::DROP_COLLECT);
+    else
+        call()->_flags.clear(Kflags::DROP_COLLECT);
+
+    DBG(FUNC, PVT_FMT(_target, "drop collect call flag: %s.") % (last_state ? "set" : "unset"));
+
+    return last_state;
+}
+
+bool Board::KhompPvt::onChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (e->Code == EV_CHANNEL_FAIL)
+        {
+            call()->statistics()->incrementChannelFail();
+            _has_fail = true;
+            setHangupCause(SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
+            cleanup(CLN_HARD);
+        }
+        else
+        {
+            if(call()->_flags.check(Kflags::REALLY_CONNECTED))
+            {
+                call()->statistics()->incrementHangup();
+            }
+
+            setHangupCause(SWITCH_CAUSE_NORMAL_CLEARING);
+            cleanup(CLN_HARD);
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return true;
+}
+
+//TODO: This method must return more information about the channel allocation
+bool Board::KhompPvt::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    std::string orig_addr, dest_addr;
+
+    Globals::k3lapi.get_param(e, "orig_addr", orig_addr);
+    Globals::k3lapi.get_param(e, "dest_addr", dest_addr);
+
+    if(dest_addr.empty())
+    {
+        dest_addr="s";
+    }
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        _call->_orig_addr = orig_addr;
+        _call->_dest_addr = dest_addr;
+
+        if (justAlloc(true) != SWITCH_STATUS_SUCCESS)
+        {
+            int fail_code = callFailFromCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
+            setHangupCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
+            cleanup(CLN_FAIL);
+            reportFailToReceive(fail_code);
+
+            LOG(ERROR, PVT_FMT(target(), "r (Initilization Error on alloc!)"));
+            return false;
+        }
+
+        if (justStart() != SWITCH_STATUS_SUCCESS)
+        {
+            int fail_code = callFailFromCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+            setHangupCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+            cleanup(CLN_FAIL);
+            reportFailToReceive(fail_code);
+            
+            LOG(ERROR, PVT_FMT(target(), "r (Initilization Error on start!)"));
+            return false;
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        cleanup(CLN_FAIL);
+        LOG(ERROR, PVT_FMT(target(), "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        cleanup(CLN_FAIL);
+        LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return true;
+}
+
+bool Board::KhompPvt::onDisconnect(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));   
+
+/*
+    try
+    {
+        ScopedPvtLock lock(this);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+*/
+
+    DBG(FUNC, PVT_FMT(_target, "r"));   
+    return true;
+}
+
+bool Board::KhompPvt::onAudioStatus(K3L_EVENT *e)
+{
+    try
+    {
+        if(e->AddInfo != kmtSilence)
+        {
+            if(call()->_flags.check(Kflags::GEN_PBX_RING))
+            {
+                DBG(FUNC, PVT_FMT(_target, "PBX ringback being disabled..."));   
+                ScopedPvtLock lock(this);
+
+                call()->_flags.clear(Kflags::GEN_PBX_RING);
+                Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
+
+                if(call()->_cadence != PLAY_VM_TONE)
+                {    
+                    stopCadence();
+                }
+
+                if (!call()->_flags.check(Kflags::CONNECTED))
+                {
+                    obtainRX(Opt::_suppression_delay);
+            
+                    //Marcar para o Freeswitch que jah tem audio passando
+                    if (call()->_flags.check(Kflags::IS_OUTGOING))
+                        switch_channel_mark_pre_answered(getFSChannel());
+
+                }
+            }
+            
+            if (!call()->_is_progress_sent && call()->_flags.check(Kflags::HAS_CALL_FAIL))
+            {
+
+                ScopedPvtLock lock(this);
+
+                DBG(FUNC, PVT_FMT(_target, "Audio status progress"));   
+
+                call()->_is_progress_sent = true;
+                //Sinaliza para o Freeswitch PROGRESS
+
+                DBG(FUNC, PVT_FMT(_target, "Pre answer"));   
+
+                //pvt->signal_state(AST_CONTROL_PROGRESS);
+                switch_channel_pre_answer(getFSChannel());
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+
+    }
+    catch (Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        cleanup(CLN_FAIL);
+        LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+
+    return true;
+}
+
+bool Board::KhompPvt::onCollectCall(K3L_EVENT *e)
+{
+    try  
+    {    
+        ScopedPvtLock lock(this);
+
+        //TODO: AMI ? 
+        //K::internal::ami_event(pvt, EVENT_FLAG_CALL, "CollectCall",
+          //      STG(FMT("Channel: Khomp/B%dC%d\r\n") % pvt->boardid % pvt->objectid));
+
+        if (Opt::_drop_collect_call || _call->_flags.check(Kflags::DROP_COLLECT))
+        {     
+            /* disconnect! */
+            //TODO: SCE_HIDE !?
+            command(KHOMP_LOG,CM_DISCONNECT);
+//           command(KHOMP_LOG,CM_DISCONNECT,SCE_HIDE);
+
+        }    
+    }    
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return true;
+}
+
+bool Board::KhompPvt::onSeizureStart(K3L_EVENT *e)
+{
+/*
+    try
+    {
+        ScopedPvtLock lock(this);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+*/
+    return true;
+}
+
+bool Board::KhompPvt::setupConnection()
+{
+    if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        DBG(FUNC, PVT_FMT(_target, "Channel already disconnected"));   
+        return false;
+    }
+
+    if(call()->_cadence != PLAY_VM_TONE)
+    {    
+        stopCadence();
+    }
+        
+    if (call()->_indication != INDICA_NONE)
+    {
+        call()->_indication = INDICA_NONE;
+
+        mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+    }
+
+    if(call()->_flags.check(Kflags::GEN_PBX_RING))
+    {
+        call()->_flags.clear(Kflags::GEN_PBX_RING);
+        Board::board(_target.device)->_timers.del(call()->_idx_pbx_ring);
+    }
+
+    if(call()->_flags.check(Kflags::GEN_CO_RING))
+    {
+        call()->_flags.clear(Kflags::GEN_CO_RING);
+        Board::board(_target.device)->_timers.del(call()->_idx_co_ring);
+    }
+
+    if (!call()->_flags.check(Kflags::CONNECTED))
+        call()->_flags.set(Kflags::CONNECTED);
+
+    if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
+        call()->_flags.set(Kflags::REALLY_CONNECTED);
+
+    /* Sinalizar para o Freeswitch o atendimento */
+
+    DBG(FUNC, PVT_FMT(_target, "Call will be answered."));   
+
+    if(call()->_flags.check(Kflags::IS_INCOMING))
+    {
+        switch_channel_answer(getFSChannel());
+    }   
+    else if(call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        switch_channel_mark_answered(getFSChannel());
+    }
+
+    call()->statistics()->incrementNewCall();
+
+    return true;
+}
+
+
+bool Board::KhompPvt::onConnect(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+    
+        return setupConnection();
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "r"));
+
+    return true;
+}
+
+bool Board::KhompPvt::onCallSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));   
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        switch_channel_mark_ring_ready(getFSChannel());
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (%s)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "r"));
+
+    return true;
+}
+
+bool Board::KhompPvt::onCallFail(K3L_EVENT *e)
+{
+   DBG(FUNC, PVT_FMT(_target, "c"));
+   try
+   {
+       ScopedPvtLock lock(this);
+
+        call()->_flags.set(Kflags::HAS_CALL_FAIL);
+    
+       //TODO: Notificar o Freeswitch: call fail
+
+        cleanup(CLN_SOFT);
+   }
+   catch (ScopedLockFailed & err)
+   {
+       LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+       return false;
+   }
+   
+   DBG(FUNC, PVT_FMT(_target, "r"));
+
+   return true;
+}
+
+bool Board::KhompPvt::onNoAnswer(K3L_EVENT *e)
+{
+    /* TODO: Destroy sessions and channels */
+    DBG(FUNC, PVT_FMT(_target, "No one answered the call."));   
+
+    // TODO: Set channel variable if we get this event 
+    // TODO: Fire an event so ESL can get it? 
+    // Call Analyser has to be enabled on k3lconfig 
+    DBG(FUNC, PVT_FMT(_target, "Detected: \"%s\"") %  Verbose::callStartInfo((KCallStartInfo)e->AddInfo).c_str());   
+
+    // Fire a custom event about this 
+    switch_event_t * event;
+    if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, KHOMP_EVENT_MAINT) == SWITCH_STATUS_SUCCESS)
+    {
+        Board::khomp_add_event_board_data(_target, event);
+        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM,
+                "EV_CALL_ANSWER_INFO",
+                Verbose::callStartInfo((KCallStartInfo)e->AddInfo).c_str());
+
+        switch_event_fire(&event);
+    }
+    return true;
+}
+
+bool Board::KhompPvt::onDtmfDetected(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "c (dtmf=%c)") % (char) e->AddInfo);
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::IS_INCOMING) || call()->_flags.check(Kflags::IS_OUTGOING)) /* is a valid call? */
+        {    
+            char digit = (char) e->AddInfo;
+
+            //TODO: WTHeck ? 
+            //if (!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS) && !call()->_flags.check(Kflags::BRIDGED))
+            if (!call()->_flags.check(Kflags::OUT_OF_BAND_DTMFS))
+            {    
+                /* we do not queue dtmfs as we do not need to resend them */
+                DBG(FUNC, PVT_FMT(_target, "r (not queueing dtmf, not needed.)"));
+                return true;
+            }    
+
+            if (Opt::_ignore_letter_dtmfs)
+            {    
+                switch (e->AddInfo)
+                {    
+                    case 'A': case 'a': 
+                    case 'B': case 'b': 
+                    case 'C': case 'c': 
+                    case 'D': case 'd': 
+                        DBG(FUNC, PVT_FMT(_target, "r (not queueing dtmf, letter digit ignored!)"));
+                        return true;
+                    default:
+                        break;
+                }    
+            }
+            
+            signalDTMF(e->AddInfo);
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "r"));
+    return true;
+}
+
+bool Board::KhompPvt::onDtmfSendFinish(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::WAIT_SEND_DTMF))
+        {
+            if(!call()->_queued_digits_buffer.empty())
+            {
+                DBG(FUNC, PVT_FMT(target(), "sending dtmf (%s)") 
+                        % call()->_queued_digits_buffer);
+
+                command(KHOMP_LOG, CM_DIAL_DTMF, 
+                        call()->_queued_digits_buffer.c_str());
+
+                /* clear the buffer that has been send */
+                call()->_queued_digits_buffer.clear();
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), 
+                        "finished sending some digits, cleaning up!"));
+                call()->_flags.clear(Kflags::WAIT_SEND_DTMF);
+            }
+        } 
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "r"));
+
+    return true;
+}
+
+bool Board::KhompPvt::onEvUntreated(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "New Event has just arrived with untreated code \"%d\" \"%s\"") % e->Code % Globals::verbose.event(_target.object, e));
+
+    return false;
+}
+
+bool Board::KhompPvt::eventHandler(K3L_EVENT *e)
+{
+    DBG(STRM, D("c"));
+
+    bool ret = true;
+
+    switch(e->Code)
+    {
+    case EV_CHANNEL_FREE:
+    case EV_CHANNEL_FAIL:
+        ret = onChannelRelease(e);
+        break;
+    
+    case EV_NEW_CALL:
+        ret = onNewCall(e);
+        break;
+
+    case EV_CALL_SUCCESS:
+        ret = onCallSuccess(e);
+        break;
+
+    case EV_CALL_FAIL:
+        ret = onCallFail(e);
+        break;
+
+    case EV_CONNECT:
+        ret = onConnect(e);
+        break;
+
+    case EV_DISCONNECT:
+        ret = onDisconnect(e);
+        break;
+    
+    case EV_AUDIO_STATUS:
+        ret = onAudioStatus(e);
+        break;
+
+    case EV_NO_ANSWER:
+        ret = onNoAnswer(e);
+        break;
+
+    case EV_DTMF_DETECTED:
+        ret = onDtmfDetected(e);
+        break;
+
+    case EV_DTMF_SEND_FINISH:
+        ret = onDtmfSendFinish(e);
+        break;
+
+    case EV_COLLECT_CALL:
+        ret = onCollectCall(e);
+        break;
+
+    case EV_SEIZURE_START:
+        ret = onSeizureStart(e);
+        break;
+
+    case EV_CADENCE_RECOGNIZED:
+        break;
+
+    default:
+        ret = onEvUntreated(e);
+        break;
+    }
+
+    DBG(STRM, D("r"));
+
+    return ret;
+}
+
+bool Board::KhompPvt::indicateProgress()
+{
+    DBG(FUNC, PVT_FMT(_target, "c")); 
+    
+    int ret = false;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (!call()->_flags.check(Kflags::CONNECTED))
+        {
+            bool has_audio = sendPreAudio(RingbackDefs::RB_SEND_NOTHING);
+
+            if (has_audio)
+            {
+                /* start grabbing audio */
+                startListen();
+                /* start stream if it is not already */
+                startStream();
+
+                ret = true;
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "r"));
+
+    return ret;
+}
+
+bool Board::KhompPvt::indicateRinging()
+{
+    DBG(FUNC, PVT_FMT(_target, "c")); 
+
+    bool ret = false;
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        /* already playing! */
+        if (call()->_indication != INDICA_NONE)
+        {    
+            DBG(FUNC, PVT_FMT(_target, "r (already playing something: %d)") 
+                    % call()->_indication);
+            return false;
+        }    
+
+        // any collect calls ?
+        setCollectCall();
+
+        call()->_indication = INDICA_RING;
+
+        bool send_ringback = true;
+
+        if (!call()->_flags.check(Kflags::CONNECTED))
+        {    
+            int ringback_value = RingbackDefs::RB_SEND_DEFAULT;
+
+            bool do_drop_call = Opt::_drop_collect_call
+                                        || call()->_flags.check(Kflags::DROP_COLLECT);
+
+            if (do_drop_call && call()->_collect_call)
+            {
+                ringback_value = kq931cCallRejected;
+                DBG(FUNC, PVT_FMT(_target, "ringback value adjusted to refuse collect call: %d") % ringback_value);
+            }
+
+            // send ringback too? 
+            send_ringback = sendPreAudio(ringback_value);
+
+            if (!send_ringback)
+            {
+                // warn the developer which may be debugging some "i do not have ringback!" issue. 
+                DBG(FUNC, PVT_FMT(_target, " not sending pre connection audio"));
+            }
+
+        }
+
+        if (send_ringback)
+        {    
+            call()->_flags.set(Kflags::GEN_CO_RING);
+            call()->_idx_co_ring = Board::board(_target.device)->_timers.add(Opt::_ringback_co_delay, &Board::KhompPvt::coRingGen,this);
+
+            /* start grabbing audio */
+            startListen();
+
+            /* start stream if it is not already */
+            startStream();
+
+            ret = true; 
+        }   
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+
+    
+    DBG(FUNC, PVT_FMT(_target, "r"));
+    return ret;
+}
+
+bool Board::KhompPvt::doChannelAnswer(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        call()->_flags.set(Kflags::CONNECTED);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "r"));
+    return true;
+}
+
+bool Board::KhompPvt::doChannelHangup(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "c"));
+
+    bool answered     = true;
+    bool disconnected = false;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "disconnecting incoming channel"));   
+
+            //disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+        }
+        else if (call()->_flags.check(Kflags::IS_OUTGOING))
+        {
+            if(call()->_cleanup_upon_hangup)
+            {
+                DBG(FUNC, PVT_FMT(_target, "disconnecting not allocated outgoing channel..."));   
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+                cleanup(KhompPvt::CLN_HARD);
+                answered = false;
+
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(_target, "disconnecting outgoing channel..."));   
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+            }
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(_target, "already disconnected"));
+            return true;
+        }
+
+        if(answered)
+        {
+            indicateBusyUnlocked(SWITCH_CAUSE_USER_BUSY, disconnected);
+        }
+
+        if (call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "disconnecting incoming channel..."));
+            disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+        }
+
+        stopStream();
+
+        stopListen();
+        
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+
+    DBG(FUNC, PVT_FMT(_target, "r"));
+    return true;
+}
+
+bool Board::KhompPvt::commandHandler(CommandRequest &cmd)
+{
+    DBG(STRM, PVT_FMT(target(), "c"));
+
+    bool ret = true;
+
+    switch(cmd.type())
+    {
+    case CommandRequest::COMMAND:
+        switch(cmd.code())
+        {
+        case CommandRequest::CMD_CALL:
+            break;
+        case CommandRequest::CMD_ANSWER:
+            ret = doChannelAnswer(cmd);
+            break;
+        case CommandRequest::CMD_HANGUP:
+            ret = doChannelHangup(cmd);
+            break;
+        default:
+            ret = false;
+        }
+        break;
+
+    case CommandRequest::ACTION:
+        break;
+    
+    default:
+        ret = false;
+    }
+    
+    DBG(STRM, PVT_FMT(target(), "r"));
+    return ret;
+}
+
+int Board::eventThread(void *void_evt)
+{
+    EventRequest evt(false);
+    EventFifo * fifo = static_cast < ChanEventHandler * >(void_evt)->fifo();
+    int devid = fifo->_device;
+
+    for(;;)
+    {
+        DBG(THRD, D("(d=%d) c") % devid);
+        while(1)
+        {
+            try
+            {
+                evt = fifo->_buffer.consumer_start();
+                break;
+            }
+            catch(...) //BufferEmpty & e
+            {
+                DBG(THRD, D("(d=%d) buffer empty") % devid);
+
+                fifo->_cond.wait();
+
+                if (fifo->_shutdown)
+                    return 0;
+
+                DBG(THRD, D("(d=%d) waked up!") % devid);
+            }
+        }
+
+        /*while (!fifo->_buffer.consume(evt))
+        {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(d=%d) buffer empty\n", fifo->_device);
+
+            fifo->_cond.wait();
+
+            if (fifo->_shutdown)
+                return 0;
+
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(d=%d) waked up!\n", fifo->_device);
+        }*/
+
+        DBG(THRD, D("(d=%d) processing buffer...") % devid);
+
+        try
+        {
+            if(!board(devid)->eventHandler(evt.obj(), evt.event()))
+            {
+                LOG(ERROR, D("(d=%d) Error on event (%d) \"%s\"") 
+                        % devid 
+                        % evt.event()->Code
+                        % Globals::verbose.event(evt.obj(), evt.event()));
+            }
+        }
+        catch (K3LAPI::invalid_device & invalid)
+        {
+            LOG(ERROR, D("invalid device on event '%s'") 
+                % Verbose::eventName(evt.event()->Code).c_str());
+        }
+
+        fifo->_buffer.consumer_commit();
+
+    }
+
+    return 0;
+}
+
+int Board::commandThread(void *void_evt)
+{
+    CommandFifo * fifo = static_cast < ChanCommandHandler * >(void_evt)->fifo();
+    int devid = fifo->_device;
+
+    for(;;)
+    {
+        CommandRequest cmd;
+
+        DBG(THRD, D("(d=%d) Command c") % devid);
+
+        while (!fifo->_buffer.consume(cmd))
+        {
+            DBG(THRD, D("(d=%d) Command buffer empty") % devid);
+            fifo->_cond.wait();
+
+            if (fifo->_shutdown)
+                return 0;
+
+            DBG(THRD, D("(d=%d) Command waked up!") % devid);
+        }
+
+        DBG(THRD, D("(d=%d) Command processing buffer...") % devid);
+
+
+        try
+        {
+            if(!get(devid, cmd.obj())->commandHandler(cmd))
+            {
+                LOG(ERROR, D("(d=%d) Error on command(%d)") % devid % cmd.code());
+            }
+        }
+        catch (K3LAPI::invalid_channel & invalid)
+        {
+            LOG(ERROR, OBJ_FMT(devid,cmd.obj(), "invalid device on command '%d'") %  cmd.code());
+        }
+
+    }
+
+
+    return 0;
+}
+
+/* This is the callback function for API events. It selects the event *
+ * on a switch and forwards to the real implementation.               */
+extern "C" int32 Kstdcall khompEventCallback(int32 obj, K3L_EVENT * e)
+{
+    //if (K::Logger::Logg.classe(C_EVENT).enabled())
+    //    std::string msg = Globals::verbose.event (obj, e) + "."; 
+    LOGC(EVENT, FMT("%s.") % Globals::verbose.event(obj, e));
+
+    switch(e->Code)
+    {
+    case EV_WATCHDOG_COUNT: 
+        Board::kommuter.initialize(e);
+        break;
+    case EV_HARDWARE_FAIL:
+    case EV_DISK_IS_FULL:
+    case EV_CLIENT_RECONNECT:
+    case EV_CLIENT_BUFFERED_AUDIOLISTENER_OVERFLOW:
+        LOG(ERROR, D("Audio client buffered overflow"));
+        break;
+    case EV_CLIENT_AUDIOLISTENER_TIMEOUT:
+        LOG(ERROR, "Timeout on audio listener, registering audio listener again");
+        k3lRegisterAudioListener( NULL, khompAudioListener );
+        break;
+    default:
+        try
+        {
+            EventRequest e_req(obj, e);
+            Board::board(e->DeviceId)->chanEventHandler()->write(e_req);
+        }
+        catch (K3LAPI::invalid_device & err)
+        {
+            LOG(ERROR, D("Unable to get device: %d!") % err.device);
+            return ksFail;
+        }
+        break;
+    }
+
+    return ksSuccess;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt_fxo.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt_fxo.cpp
new file mode 100644 (file)
index 0000000..1383f5c
--- /dev/null
@@ -0,0 +1,791 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "khomp_pvt_fxo.h"
+#include "lock.h"
+#include "logger.h"
+
+int BoardFXO::KhompPvtFXO::makeCall(std::string params)
+{
+    DBG(FUNC,PVT_FMT(_target, "(FXO) c"));
+
+    int ret = ksSuccess;
+
+    /* we always have audio */
+    call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+    
+    if(callFXO()->_call_info_drop == 0 && !callFXO()->_call_info_report)
+    {
+        command(KHOMP_LOG, CM_DISABLE_CALL_ANSWER_INFO);
+    }
+
+    if (!callFXO()->_pre_digits.empty())
+    {
+        /* Seize the line at local PABX. */
+
+        callFXO()->_flags.set(Kflags::CALL_WAIT_SEIZE);
+
+        if (!command(KHOMP_LOG, CM_SEIZE, call()->_orig_addr.c_str()))
+            return ksFail;            
+
+        int timeout = 150;
+
+        if(!loopWhileFlagTimed(Kflags::CALL_WAIT_SEIZE, timeout))
+            return ksFail;
+
+        if (callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE) || (timeout <= 0))
+            return ksFail;
+
+        /* Grab line from local PABX. */
+
+        callFXO()->_flags.set(Kflags::WAIT_SEND_DTMF);
+
+        if (!command(KHOMP_LOG, CM_DIAL_DTMF, callFXO()->_pre_digits.c_str()))
+            return ksFail;            
+        
+        if(!loopWhileFlagTimed(Kflags::WAIT_SEND_DTMF, timeout))
+            return ksFail;
+
+        if (callFXO()->_flags.check(Kflags::WAIT_SEND_DTMF) || (timeout <= 0))
+            return ksFail;
+
+        /* Seize line from public central (works because the     *
+        * continuous cadence is always detected by the k3l api. */
+
+        callFXO()->_flags.set(Kflags::CALL_WAIT_SEIZE);
+
+        if (!command(KHOMP_LOG, CM_SEIZE, call()->_orig_addr.c_str()))
+            return ksFail;
+
+        if(!loopWhileFlagTimed(Kflags::CALL_WAIT_SEIZE, timeout))
+            return ksFail;
+
+        if (callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE) || (timeout <= 0))
+            return ksFail;
+
+        /* we want the audio as soon as dialing ends */
+        callFXO()->_flags.set(Kflags::EARLY_RINGBACK);
+    
+        if (!command(KHOMP_LOG, CM_DIAL_DTMF, call()->_dest_addr.c_str()))
+            return ksFail;
+    }
+    else
+    {
+        /* we want the audio as soon as dialing ends */
+        callFXO()->_flags.set(Kflags::EARLY_RINGBACK);
+
+
+        if(!call()->_orig_addr.empty())
+            params += STG(FMT(" orig_addr=\"%s\"") % _call->_orig_addr);
+
+
+        ret = KhompPvt::makeCall(params);
+
+        if(ret != ksSuccess)
+        {
+            LOG(ERROR, PVT_FMT(target(), "Fail on make call"));
+        }
+
+        call()->_cleanup_upon_hangup = (ret == ksInvalidParams);
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(FXO) r"));
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::doChannelAnswer(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        // is this a collect call?
+        bool has_recv_collect_call = _call->_collect_call;
+
+        if(has_recv_collect_call)
+            DBG(FUNC, PVT_FMT(target(), "receive a collect call"));
+
+        if(call()->_flags.check(Kflags::DROP_COLLECT))
+            DBG(FUNC, PVT_FMT(target(), "flag DROP_COLLECT == true"));
+
+        // do we have to drop collect calls?
+        bool has_drop_collect_call = call()->_flags.check(Kflags::DROP_COLLECT);
+
+        // do we have to drop THIS call?
+        bool do_drop_call = has_drop_collect_call && has_recv_collect_call;
+
+        if(!do_drop_call)
+        {
+            command(KHOMP_LOG, CM_CONNECT);
+        }
+
+        if(has_drop_collect_call)
+        {
+            if(has_recv_collect_call)
+            {
+                usleep(75000);
+
+                DBG(FUNC, PVT_FMT(target(), "disconnecting collect call doChannelAnswer FXO"));
+                command(KHOMP_LOG,CM_DISCONNECT);
+
+                // thou shalt not talk anymore!
+                stopListen();
+                stopStream();
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), "dropping collect call at doChannelAnswer FXO"));
+                command(KHOMP_LOG, CM_DROP_COLLECT_CALL);
+            }
+        }
+
+        ret = KhompPvt::doChannelAnswer(cmd);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target,"(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC,PVT_FMT(_target,"(FXO) c"));
+   
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        /* we always have audio */
+        call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+
+        ret = KhompPvt::onNewCall(e);
+
+        if(!ret)
+            return false;
+
+        startListen();
+        startStream();
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onDisconnect(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        command(KHOMP_LOG, CM_DISCONNECT);
+
+        ret = KhompPvt::onDisconnect(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::FAX_SENDING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "stopping fax tx"));
+            _fax->stopFaxTX();
+        }
+        else if (call()->_flags.check(Kflags::FAX_RECEIVING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "stopping fax rx"));
+            _fax->stopFaxRX();
+        }
+
+        command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
+   
+        ret = KhompPvt::onChannelRelease(e);
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));   
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onCallSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onCallSuccess(e);
+
+        if (call()->_pre_answer)
+        {
+            dtmfSuppression(Opt::_out_of_band_dtmfs && !call()->_flags.check(Kflags::FAX_DETECTED));
+
+            startListen();
+            startStream();
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+        
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onCallFail(K3L_EVENT *e)
+{
+    bool ret = true; 
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        command(KHOMP_LOG, CM_DISCONNECT);
+
+        setHangupCause(causeFromCallFail(e->AddInfo), true);
+
+        ret = KhompPvt::onCallFail(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onAudioStatus(K3L_EVENT *e)
+{
+    DBG(STRM, PVT_FMT(_target, "(FXO) c"));
+
+    try
+    {
+        //ScopedPvtLock lock(this);
+
+        if(e->AddInfo == kmtFax)
+        {
+            DBG(FUNC, PVT_FMT(_target, "Fax detected"));
+
+            bool already_detected = call()->_flags.check(Kflags::FAX_DETECTED);  
+            BEGIN_CONTEXT
+            {
+                if(already_detected)
+                    break;
+
+                ScopedPvtLock lock(this);
+
+                if (callFXO()->_call_info_drop != 0 || callFXO()->_call_info_report)
+                {
+                    /* we did not detected fax yet, send answer info! */
+                    setAnswerInfo(Board::KhompPvt::CI_FAX);
+
+                    if (callFXO()->_call_info_drop & Board::KhompPvt::CI_FAX)
+                    {
+                        /* fastest way to force a disconnection */
+                        command(KHOMP_LOG,CM_DISCONNECT);//,SCE_HIDE);
+                    }
+                }
+
+                if (Opt::_auto_fax_adjustment)
+                {
+                    DBG(FUNC, PVT_FMT(_target, "communication will be adjusted for fax!"));
+                    _fax->adjustForFax();
+                }
+            }
+            END_CONTEXT
+
+            if (!already_detected)
+            {
+                ScopedPvtLock lock(this);
+
+                /* adjust the flag */
+                call()->_flags.set(Kflags::FAX_DETECTED);
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    bool ret = KhompPvt::onAudioStatus(e);
+
+    DBG(STRM, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onSeizeSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        callFXO()->_flags.clear(Kflags::CALL_WAIT_SEIZE);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return true;
+}
+
+bool BoardFXO::KhompPvtFXO::onDtmfDetected(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (callFXO()->_flags.check(Kflags::WAIT_SEND_DTMF) ||
+                callFXO()->_flags.check(Kflags::CALL_WAIT_SEIZE))
+        {
+            /* waiting digit or seize means DEADLOCK if we try to 
+             *  queue something below. */
+            DBG(FUNC, PVT_FMT(_target, "not queueing dtmf, waiting stuff!"));
+            return true;
+        }
+
+        ret = KhompPvt::onDtmfDetected(e);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onDtmfSendFinish(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onDtmfSendFinish(e);
+
+        if (callFXO()->_flags.check(Kflags::EARLY_RINGBACK))
+        {
+            callFXO()->_flags.clear(Kflags::EARLY_RINGBACK);
+
+            /* start grabbing */
+            startListen();
+
+            /* activate resources early... */
+            bool fax_detected = callFXO()->_flags.check(Kflags::FAX_DETECTED);
+
+            bool res_out_of_band_dtmf = Opt::_suppression_delay && Opt::_out_of_band_dtmfs && !fax_detected;
+            bool res_echo_cancellator = Opt::_echo_canceller && !fax_detected;
+            bool res_auto_gain_cntrol = Opt::_auto_gain_control && !fax_detected;
+
+            if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
+                dtmfSuppression(res_out_of_band_dtmf);
+
+            if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
+                echoCancellation(res_echo_cancellator);
+
+            if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
+                autoGainControl(res_auto_gain_cntrol);
+
+            /* start sending audio if wanted so */
+            if (Opt::_fxo_send_pre_audio)
+                startStream();
+
+            //TODO: Verificar isso aqui
+            if (call()->_pre_answer)
+            {
+                /* tell the user we are answered! */
+                switch_channel_mark_answered(getFSChannel());
+                //pvt->signal_state(AST_CONTROL_ANSWER);
+            }
+            else
+            {
+                /* are we ringing, now? lets try this way! */
+                switch_channel_mark_ring_ready(getFSChannel());
+                //pvt->signal_state(AST_CONTROL_RINGING);
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXO) r (no valid channel: %s)") % err._msg.c_str());
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::onCallAnswerInfo(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        int info_code = -1;
+
+        switch (e->AddInfo)
+        {
+            case kcsiCellPhoneMessageBox:
+                info_code = CI_MESSAGE_BOX;
+                break;
+            case kcsiHumanAnswer:
+                info_code = CI_HUMAN_ANSWER;
+                break;
+            case kcsiAnsweringMachine:
+                info_code = CI_ANSWERING_MACHINE;
+                break;
+            case kcsiCarrierMessage:
+                info_code = CI_CARRIER_MESSAGE;
+                break;
+            case kcsiUnknown:
+                info_code = CI_UNKNOWN;
+                break;
+            default:
+                DBG(FUNC, PVT_FMT(_target, "got an unknown call answer info '%d', ignoring...") % e->AddInfo);
+                break;
+        }
+
+        if (info_code != -1)
+        {
+            if (callFXO()->_call_info_report)
+            {
+                //TODO: HOW WE TREAT THAT 
+                // make the channel export this 
+                setAnswerInfo(info_code);
+            }
+
+            if (callFXO()->_call_info_drop & info_code)
+            {
+                command(KHOMP_LOG,CM_DISCONNECT);
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target,"(FXO) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXO) r"));
+    return true;
+}
+
+bool BoardFXO::KhompPvtFXO::application(ApplicationType type, switch_core_session_t * session, const char *data)
+{
+    switch(type)
+    {
+        case FAX_ADJUST:
+            return _fax->adjustForFax();
+        case FAX_SEND:
+            return _fax->sendFax(session, data);
+        case FAX_RECEIVE:
+            return _fax->receiveFax(session, data);
+        case USER_TRANSFER:
+            return _transfer->userTransfer(session, data);
+        default:
+            return KhompPvt::application(type, session, data);
+    }
+
+    return true;
+}
+
+bool BoardFXO::KhompPvtFXO::setupConnection()
+{
+    if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        DBG(FUNC,PVT_FMT(_target, "Channel already disconnected"));
+        return false;
+    }
+
+    callFXO()->_flags.clear(Kflags::CALL_WAIT_SEIZE);
+    callFXO()->_flags.clear(Kflags::WAIT_SEND_DTMF);
+
+    /* if received some disconnect from 'drop collect call'
+       feature of some pbx, then leave the call rock and rolling */
+    //Board::board(_target.device)->_timers.del(callFXO()->_idx_disconnect);
+
+    bool fax_detected = callFXO()->_flags.check(Kflags::FAX_DETECTED) || (callFXO()->_var_fax_adjust == T_TRUE);
+
+    bool res_out_of_band_dtmf = (call()->_var_dtmf_state == T_UNKNOWN || fax_detected ?
+        Opt::_suppression_delay && Opt::_out_of_band_dtmfs && !fax_detected : (call()->_var_dtmf_state == T_TRUE));
+
+    bool res_echo_cancellator = (call()->_var_echo_state == T_UNKNOWN || fax_detected ?
+        Opt::_echo_canceller && !fax_detected : (call()->_var_echo_state == T_TRUE));
+
+    bool res_auto_gain_cntrol = (call()->_var_gain_state == T_UNKNOWN || fax_detected ?
+        Opt::_auto_gain_control && !fax_detected : (call()->_var_gain_state == T_TRUE));
+
+    if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
+    {
+        obtainRX(res_out_of_band_dtmf);
+
+        /* esvazia buffers de leitura/escrita */
+        cleanupBuffers();
+
+        if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
+            dtmfSuppression(res_out_of_band_dtmf);
+
+        if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
+            echoCancellation(res_echo_cancellator);
+
+        if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
+            autoGainControl(res_auto_gain_cntrol);
+
+        startListen(false);
+
+        startStream();
+
+        DBG(FUNC, PVT_FMT(_target, "(FXO) Audio callbacks initialized successfully"));
+    }
+
+    return KhompPvt::setupConnection();
+}
+
+bool BoardFXO::KhompPvtFXO::autoGainControl(bool enable)
+{
+    bool ret = KhompPvt::autoGainControl(enable);
+    
+    /* enable this AGC also, can be very useful */
+    ret &= command(KHOMP_LOG, (enable ? CM_ENABLE_PLAYER_AGC : CM_DISABLE_PLAYER_AGC));
+    return ret;
+}
+
+void BoardFXO::KhompPvtFXO::setAnswerInfo(int answer_info)
+{
+    const char * value = answerInfoToString(answer_info);
+
+    if (value == NULL)
+    {
+        DBG(FUNC, PVT_FMT(_target,"signaled unknown call answer info '%d', using 'Unknown'...") % answer_info);
+        value = "Unknown";
+    }
+   
+    DBG(FUNC,PVT_FMT(_target,"KCallAnswerInfo: %s") % value);
+
+    try
+    {
+        setFSChannelVar("KCallAnswerInfo", value);
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target,"Cannot obtain the channel variable: %s") % err._msg.c_str());
+    }
+}
+
+bool BoardFXO::KhompPvtFXO::indicateBusyUnlocked(int cause, bool sent_signaling)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXO) c"));
+
+    if(!KhompPvt::indicateBusyUnlocked(cause, sent_signaling))
+    {
+        DBG(FUNC, PVT_FMT(_target, "(FXO) r (false)"));
+        return false;
+    }
+
+    if(call()->_flags.check(Kflags::IS_INCOMING))
+    {
+        if(!call()->_flags.check(Kflags::CONNECTED) && !sent_signaling)
+        {
+            //we are talking about branches, not trunks 
+            command(KHOMP_LOG, CM_CONNECT);
+            command(KHOMP_LOG, CM_DISCONNECT);
+        }
+        else
+        {
+            //already connected or sent signaling... 
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+        }
+    }
+    else if(call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        //already connected or sent signaling... 
+        mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(FXO) r"));
+    
+    return true; 
+}
+
+void BoardFXO::KhompPvtFXO::reportFailToReceive(int fail_code)
+{
+    KhompPvt::reportFailToReceive(fail_code);
+
+    command(KHOMP_LOG, CM_CONNECT);
+
+    command(KHOMP_LOG, CM_DISCONNECT);
+
+}
+
+bool BoardFXO::KhompPvtFXO::validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context)
+{
+    DBG(FUNC,PVT_FMT(_target,"(FXO) c"));
+
+    contexts.push_back(Opt::_context_fxo);
+    contexts.push_back(Opt::_context2_fxo);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++)
+    {
+        replaceTemplate((*i), "CC", _target.object);
+    }
+
+    bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
+
+    DBG(FUNC,PVT_FMT(_target,"(FXO) r"));
+
+    return ret;
+}
+
+bool BoardFXO::KhompPvtFXO::isOK()
+{
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false;
+
+        return (status.AddInfo == kfcsEnabled);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+    }
+
+    return false;
+}
+
+bool BoardFXO::KhompPvtFXO::sendDtmf(std::string digit)
+{
+    if(_transfer->checkUserXferUnlocked(digit))
+    {
+        DBG(FUNC, PVT_FMT(target(), "started (or waiting for) an user xfer"));
+        return true;
+    }
+
+    bool ret = KhompPvt::sendDtmf(callFXO()->_digits_buffer);
+
+    callFXO()->_digits_buffer.clear();
+
+    return ret;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt_gsm.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt_gsm.cpp
new file mode 100644 (file)
index 0000000..2f24c60
--- /dev/null
@@ -0,0 +1,565 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "khomp_pvt_gsm.h"
+#include "lock.h"
+#include "logger.h"
+
+bool BoardGSM::KhompPvtGSM::isOK()
+{
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false;
+
+        switch (status.AddInfo)
+        {
+            case kgsmModemError:
+            case kgsmSIMCardError:
+            case kgsmNetworkError:
+            case kgsmNotReady:
+                return false;
+            default:
+                return true;
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+    }
+
+    return false;
+}
+
+bool BoardGSM::KhompPvtGSM::onChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        call()->_flags.clear(Kflags::HAS_PRE_AUDIO);
+        command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
+   
+        ret = KhompPvt::onChannelRelease(e);
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));   
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::onCallSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onCallSuccess(e);
+
+        if (call()->_pre_answer)
+        {
+            dtmfSuppression(Opt::_out_of_band_dtmfs);
+
+            startListen();
+            startStream();
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+        
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));
+
+    return ret;
+}
+
+void BoardGSM::KhompPvtGSM::setAnswerInfo(int answer_info)
+{
+    const char * value = answerInfoToString(answer_info);
+
+    if (value == NULL)
+    {
+        DBG(FUNC, PVT_FMT(_target,"signaled unknown call answer info '%d', using 'Unknown'...") % answer_info);
+        value = "Unknown";
+    }
+   
+    DBG(FUNC,PVT_FMT(_target,"KCallAnswerInfo: %s") % value);
+
+    try
+    {
+        setFSChannelVar("KCallAnswerInfo",value);
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target,"Cannot obtain the channel variable: %s") % err._msg.c_str());
+    }
+}
+
+bool BoardGSM::KhompPvtGSM::onCallAnswerInfo(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        int info_code = -1;
+
+        switch (e->AddInfo)
+        {
+            case kcsiCellPhoneMessageBox:
+                info_code = CI_MESSAGE_BOX;
+                break;
+            case kcsiHumanAnswer:
+                info_code = CI_HUMAN_ANSWER;
+                break;
+            case kcsiAnsweringMachine:
+                info_code = CI_ANSWERING_MACHINE;
+                break;
+            case kcsiCarrierMessage:
+                info_code = CI_CARRIER_MESSAGE;
+                break;
+            case kcsiUnknown:
+                info_code = CI_UNKNOWN;
+                break;
+            default:
+                DBG(FUNC, PVT_FMT(_target, "got an unknown call answer info '%d', ignoring...") % e->AddInfo);
+                break;
+        }
+
+        if (info_code != -1)
+        {
+            if (callGSM()->_call_info_report)
+            {
+                //TODO: HOW WE TREAT THAT 
+                // make the channel export this 
+                setAnswerInfo(info_code);
+            }
+
+            if (callGSM()->_call_info_drop & info_code)
+            {
+                command(KHOMP_LOG, CM_SEND_TO_MODEM, "ATH");
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target,"(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));
+    return true;
+}
+
+/*
+bool BoardGSM::KhompPvtGSM::onDtmfDetected(K3L_EVENT *e)
+{
+    bool ret = KhompPvt::onDtmfDetected(e);
+
+    try
+    {
+        ScopedPvtLock lock(this);
+        
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC,PVT_FMT(_target,"(GSM) c"));
+    
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        bool ret = KhompPvtGSM::onNewCall(e); 
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));
+
+    return ret;
+}
+*/
+
+
+
+bool BoardGSM::KhompPvtGSM::onCallFail(K3L_EVENT *e)
+{
+    bool ret = true; 
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        //K::internal::gsm_cleanup_and_restart(pvt, owner_nr, true);
+        setHangupCause(causeFromCallFail(e->AddInfo), true);
+
+        ret = KhompPvt::onCallFail(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::onDisconnect(K3L_EVENT *e)
+{
+    bool ret = true;
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        //gsm_cleanup_and_restart(pvt, (int)evt.gsm_call_ref);
+
+        ret = KhompPvt::onDisconnect(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(GSM) unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return ret;
+}
+
+int BoardGSM::KhompPvtGSM::makeCall(std::string params)
+{
+    DBG(FUNC,PVT_FMT(_target, "(GSM) c"));
+    
+    if(callGSM()->_call_info_drop == 0 && !callGSM()->_call_info_report)
+    {
+        command(KHOMP_LOG, CM_DISABLE_CALL_ANSWER_INFO);
+    }
+
+    int ret = KhompPvt::makeCall(params);
+
+    if(ret != ksSuccess)
+    {
+        LOG(ERROR, PVT_FMT(target(), "Fail on make call"));
+    }
+
+    call()->_cleanup_upon_hangup = (ret == ksInvalidParams || ret == ksInvalidState);
+
+    DBG(FUNC,PVT_FMT(_target, "(GSM) r"));
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::doChannelAnswer(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        command(KHOMP_LOG, CM_CONNECT);
+
+        ret = KhompPvt::doChannelAnswer(cmd);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target,"(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));
+
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::doChannelHangup(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        int owner_nr = 0;
+
+        command(KHOMP_LOG, CM_DISCONNECT, 
+                STG(FMT("gsm_call_ref=%d") % (int)owner_nr).c_str());
+
+
+        //ret = KhompPvt::doChannelHangup(cmd);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target,"(GSM) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(GSM) r"));
+
+    return ret;
+}
+
+bool BoardGSM::KhompPvtGSM::application(ApplicationType type, switch_core_session_t * session, const char *data)
+{
+    switch(type)
+    {
+        case SMS_CHECK:
+            return true;
+        case SMS_SEND:
+            return _sms->sendSMS(session, data);
+        case SELECT_SIM_CARD:
+            return selectSimCard(data);
+        default:
+            return KhompPvt::application(type, session, data);
+    }
+
+    return true;
+}
+
+bool BoardGSM::KhompPvtGSM::setupConnection()
+{
+    if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        DBG(FUNC,PVT_FMT(_target, "Channel already disconnected"));
+        return false;
+    }
+
+    bool res_out_of_band_dtmf = (call()->_var_dtmf_state == T_UNKNOWN ?
+        Opt::_suppression_delay && Opt::_out_of_band_dtmfs : (call()->_var_dtmf_state == T_TRUE));
+
+    bool res_echo_cancellator = (call()->_var_echo_state == T_UNKNOWN ?
+        Opt::_echo_canceller : (call()->_var_echo_state == T_TRUE));
+
+
+    bool res_auto_gain_cntrol = (call()->_var_gain_state == T_UNKNOWN ?
+        Opt::_auto_gain_control : (call()->_var_gain_state == T_TRUE));
+
+
+    if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
+    {
+        obtainRX(res_out_of_band_dtmf);
+
+        /* esvazia buffers de leitura/escrita */
+        cleanupBuffers();
+
+        if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
+            dtmfSuppression(res_out_of_band_dtmf);
+
+        if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
+            echoCancellation(res_echo_cancellator);
+
+        if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
+            autoGainControl(res_auto_gain_cntrol);
+
+        startListen(false);
+
+        startStream();
+
+        DBG(FUNC, PVT_FMT(_target, "(GSM) Audio callbacks initialized successfully"));
+    }
+
+    return Board::KhompPvt::setupConnection();
+}
+
+bool BoardGSM::KhompPvtGSM::indicateBusyUnlocked(int cause, bool sent_signaling)
+{
+    DBG(FUNC, PVT_FMT(_target, "(GSM) c"));
+
+    if(!KhompPvt::indicateBusyUnlocked(cause, sent_signaling))
+    {
+        DBG(FUNC, PVT_FMT(_target, "(GSM) r (false)"));
+        return false;
+    }
+
+    if(call()->_flags.check(Kflags::IS_INCOMING))
+    {
+        if(!call()->_flags.check(Kflags::CONNECTED) && !sent_signaling)
+        {
+            /* we are talking about branches, not trunks */
+            command(KHOMP_LOG, CM_DISCONNECT);
+        }
+        else
+        {
+            /* already connected or sent signaling... */
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+        }
+    }
+    else if(call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        /* already connected or sent signaling... */
+        mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(GSM) r"));
+    
+    return true; 
+}
+
+void BoardGSM::KhompPvtGSM::reportFailToReceive(int fail_code)
+{
+    KhompPvt::reportFailToReceive(fail_code);
+
+    command(KHOMP_LOG, CM_CONNECT);
+
+    /* K3L may fail depending on its configuration (GsmModem) */
+    if (!command(KHOMP_LOG, CM_DISCONNECT))
+    {
+        int owner_nr = 0;
+        command(KHOMP_LOG, CM_DISCONNECT,
+                STG(FMT("gsm_call_ref=\"%d\"") % owner_nr).c_str());
+    }
+
+}
+
+int BoardGSM::KhompPvtGSM::causeFromCallFail(int fail)
+{
+    int switch_cause = SWITCH_CAUSE_USER_BUSY;
+
+    if (fail <= 127) 
+        switch_cause = fail;
+    else 
+        switch_cause = SWITCH_CAUSE_INTERWORKING;
+
+    return switch_cause;
+}
+
+int BoardGSM::KhompPvtGSM::callFailFromCause(int cause)
+{
+    int k3l_fail = -1; // default
+
+    if (cause <= 127) 
+        k3l_fail = cause;
+    else
+        k3l_fail = kgccInterworking; 
+
+    return k3l_fail;
+}
+
+bool BoardGSM::KhompPvtGSM::validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context)
+{
+    DBG(FUNC,PVT_FMT(_target,"(GSM) c"));
+
+    if (!extra_context.empty())
+    {    
+        if (!_group_context.empty())
+        {    
+            std::string pvt_context(_group_context);
+            pvt_context += "-"; 
+            pvt_context += extra_context;
+            contexts.push_back(pvt_context);
+        }    
+
+        if (!Opt::_context_gsm_call.empty())
+        {    
+            std::string context(Opt::_context_gsm_call);
+            context += "-"; 
+            context += extra_context;
+            contexts.push_back(_group_context);
+        }
+
+        if (!Opt::_context2_gsm_call.empty())
+        {    
+            std::string context(Opt::_context2_gsm_call);
+            context += "-"; 
+            context += extra_context;
+            contexts.push_back(_group_context);
+        }    
+
+        if (!Opt::_context2_gsm_call.empty())
+        {    
+            std::string context(Opt::_context2_gsm_call);
+            context += "-"; 
+            context += extra_context;
+            contexts.push_back(_group_context);
+        }    
+    }  
+
+    contexts.push_back(Opt::_context_gsm_call);
+    contexts.push_back(Opt::_context2_gsm_call);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++) 
+        replaceTemplate((*i), "CC", _target.object);
+
+    bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
+
+    DBG(FUNC,PVT_FMT(_target,"(GSM) r"));
+
+    return ret;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt_kxe1.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt_kxe1.cpp
new file mode 100644 (file)
index 0000000..4dec540
--- /dev/null
@@ -0,0 +1,3425 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "khomp_pvt_kxe1.h"
+#include "lock.h"
+#include "logger.h"
+
+
+bool BoardE1::KhompPvtE1::isOK()
+{
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false;
+
+        return   ((status.AddInfo == kecsFree) ||
+                (!(status.AddInfo & kecsLocalFail) &&
+                 !(status.AddInfo & kecsRemoteLock)));
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+    }
+
+    return false;
+}
+
+bool BoardE1::KhompPvtE1::onChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::FAX_SENDING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "stopping fax tx"));
+            _fax->stopFaxTX();
+        }
+        else if (call()->_flags.check(Kflags::FAX_RECEIVING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "stopping fax rx"));
+            _fax->stopFaxRX();
+        }
+
+        call()->_flags.clear(Kflags::HAS_PRE_AUDIO);
+
+        command(KHOMP_LOG, CM_ENABLE_CALL_ANSWER_INFO);
+
+        ret = KhompPvt::onChannelRelease(e);
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(E1) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(E1) r"));   
+    return ret;
+}
+
+bool BoardE1::KhompPvtE1::onCallSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+
+    bool ret;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onCallSuccess(e);
+
+        if (call()->_pre_answer)
+        {
+            dtmfSuppression(Opt::_out_of_band_dtmfs && !call()->_flags.check(Kflags::FAX_DETECTED));     
+
+            startListen();
+            startStream();
+        }
+        else
+        {
+            call()->_flags.set(Kflags::GEN_PBX_RING);
+            call()->_idx_pbx_ring = Board::board(_target.device)->_timers.add(Opt::_ringback_pbx_delay,
+                                             &Board::KhompPvt::pbxRingGen,this, TM_VAL_CALL);
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(E1) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(E1) r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(E1) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtE1::onAudioStatus(K3L_EVENT *e)
+{
+    //DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+
+    try
+    {
+        //ScopedPvtLock lock(this);
+
+        if(e->AddInfo == kmtFax)
+        {
+            DBG(FUNC, PVT_FMT(_target, "Fax detected"));
+
+            bool already_detected = call()->_flags.check(Kflags::FAX_DETECTED);            
+            BEGIN_CONTEXT
+            {
+                if(already_detected)
+                    break;
+                    
+                ScopedPvtLock lock(this);
+
+                if (callE1()->_call_info_drop != 0 || callE1()->_call_info_report)
+                {    
+                    /* we did not detected fax yet, send answer info! */
+                    setAnswerInfo(Board::KhompPvt::CI_FAX);
+
+                    if (callE1()->_call_info_drop & Board::KhompPvt::CI_FAX)
+                    {    
+                        /* fastest way to force a disconnection */
+                        command(KHOMP_LOG,CM_DISCONNECT);//,SCE_HIDE);
+                    }    
+                }
+
+                if (Opt::_auto_fax_adjustment)
+                {
+                    DBG(FUNC, PVT_FMT(_target, "communication will be adjusted for fax!"));
+                    _fax->adjustForFax();
+                }
+            }
+            END_CONTEXT
+
+            if (!already_detected)
+            {
+                ScopedPvtLock lock(this);
+
+                /* adjust the flag */
+                call()->_flags.set(Kflags::FAX_DETECTED);
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    bool ret = KhompPvt::onAudioStatus(e);
+    
+    //DBG(FUNC, PVT_FMT(_target, "(E1) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtE1::onCallAnswerInfo(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+    try  
+    {    
+        ScopedPvtLock lock(this);
+
+        int info_code = -1;
+
+        switch (e->AddInfo)
+        {    
+            case kcsiCellPhoneMessageBox:
+                info_code = CI_MESSAGE_BOX;
+                break;
+            case kcsiHumanAnswer:
+                info_code = CI_HUMAN_ANSWER;
+                break;
+            case kcsiAnsweringMachine:
+                info_code = CI_ANSWERING_MACHINE;
+                break;
+            case kcsiCarrierMessage:
+                info_code = CI_CARRIER_MESSAGE;
+                break;
+            case kcsiUnknown:
+                info_code = CI_UNKNOWN;
+                break;
+            default:
+                DBG(FUNC, PVT_FMT(_target, "got an unknown call answer info '%d', ignoring...") % e->AddInfo);
+                break;
+        }    
+
+        if (info_code != -1)
+        {    
+            if (callE1()->_call_info_report)
+            {    
+                //TODO: HOW WE TREAT THAT 
+                // make the channel export this 
+                setAnswerInfo(info_code);
+            }    
+
+            if (callE1()->_call_info_drop & info_code)
+            {    
+                // fastest way to force a disconnection 
+                //K::util::sendCmd(pvt->boardid, pvt->objectid, CM_DISCONNECT, true, false);
+                command(KHOMP_LOG,CM_DISCONNECT/*,SCE_HIDE ?*/);
+            }    
+        }    
+    }    
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(E1) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(E1) r"));
+    return true;
+}
+
+bool BoardE1::KhompPvtE1::onDisconnect(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::IS_OUTGOING) ||
+            call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            if(Opt::_disconnect_delay == 0)
+            {
+                DBG(FUNC, PVT_FMT(_target, "queueing disconnecting outgoing channel!"));
+                command(KHOMP_LOG, CM_DISCONNECT);       
+            }
+            else
+            {
+                callE1()->_idx_disconnect = Board::board(_target.device)->_timers.add(
+                    1000 * Opt::_disconnect_delay,&BoardE1::KhompPvtE1::delayedDisconnect,this);
+            }
+        }
+        else
+        {
+            /* in the case of a disconnect confirm is needed and a call 
+            was not started e.g. just after a ev_seizure_start */
+            command(KHOMP_LOG, CM_DISCONNECT);
+        }
+        
+        ret = KhompPvt::onDisconnect(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(E1) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(E1) r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(E1) r"));
+    return ret;
+}
+
+void BoardE1::KhompPvtE1::delayedDisconnect(Board::KhompPvt * pvt)
+{
+    DBG(FUNC,PVT_FMT(pvt->target(), "Delayed disconnect"));
+
+    try  
+    {    
+        ScopedPvtLock lock(pvt);
+
+        DBG(FUNC, PVT_FMT(pvt->target(), "queueing disconnecting outgoing channel after delaying!"));
+
+        pvt->command(KHOMP_LOG,CM_DISCONNECT);
+        pvt->cleanup(CLN_HARD);
+    }        
+    catch (...)
+    {
+        LOG(ERROR, PVT_FMT(pvt->target(), "r (unable to lock the pvt !)"));
+    }       
+}
+
+bool BoardE1::onLinkStatus(K3L_EVENT *e)
+{
+    DBG(FUNC, D("Link %02d on board %02d changed") % e->AddInfo % e->DeviceId);
+
+    /* Fire a custom event about this */
+    /*
+    switch_event_t * event;
+    if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, KHOMP_EVENT_MAINT) == SWITCH_STATUS_SUCCESS)
+    {
+        //khomp_add_event_board_data(e->AddInfo, event);
+        Board::khomp_add_event_board_data(K3LAPI::target(Globals::k3lapi, K3LAPI::target::LINK, e->DeviceId, e->AddInfo), event);
+
+        switch_event_add_header(event, SWITCH_STACK_BOTTOM, "EV_LINK_STATUS", "%d", e->AddInfo);
+        switch_event_fire(&event);
+    }
+    */
+
+    return true;
+}
+
+bool BoardE1::KhompPvtISDN::onSyncUserInformation(K3L_EVENT *e)
+{
+    KUserInformation * info = (KUserInformation *) (((char*)e) + sizeof(K3L_EVENT));
+
+    callISDN()->_uui_descriptor = info->ProtocolDescriptor;
+
+    /* clean string */
+    callISDN()->_uui_information.clear();
+
+    if (info->UserInfoLength)
+    {    
+        /* append to a clean string */
+        callISDN()->_uui_information.append((const char *)info->UserInfo, info->UserInfoLength);
+    }    
+
+    return true;
+}
+
+bool BoardE1::KhompPvtISDN::onIsdnProgressIndicator(K3L_EVENT *e)
+{
+    //TODO: Do we need return something ?
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        switch (e->AddInfo)
+        {
+            case kq931pTonesMaybeAvailable:
+            case kq931pTonesAvailable:
+                if (!call()->_is_progress_sent)
+                {
+                    call()->_is_progress_sent = true;
+
+                    //Sinaliza para o Freeswitch PROGRESS
+                    DBG(FUNC, PVT_FMT(_target, "Pre answer"));
+
+                    //pvt->signal_state(SWITCH_CONTROL_PROGRESS);
+                    //switch_channel_pre_answer(channel);
+                    switch_channel_mark_pre_answered(getFSChannel());
+
+                }
+                break;
+            case kq931pDestinationIsNonIsdn:
+            case kq931pOriginationIsNonIsdn:
+            case kq931pCallReturnedToIsdn:
+            default:
+                break;
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "No valid channel: %s") % err._msg.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtISDN::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC,PVT_FMT(_target, "(ISDN) c"));   
+
+    bool isdn_reverse_charge = false;
+    std::string isdn_reverse_charge_str;
+    bool ret;
+    
+    try
+    {
+        isdn_reverse_charge_str = Globals::k3lapi.get_param(e, "isdn_reverse_charge");
+        isdn_reverse_charge = Strings::toboolean(isdn_reverse_charge_str);
+    }
+    catch(K3LAPI::get_param_failed & err)
+    {
+        /* do nothing, maybe the parameter is not sent */
+    }
+    catch (Strings::invalid_value & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to get param '%s'") % err.value().c_str());
+    }
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(session())
+        {
+            bool pvt_locked = true;
+            bool is_ok = false;
+        
+            DBG(FUNC, PVT_FMT(_target, "Session has not been destroyed yet, waiting for khompDestroy"));
+
+            for(unsigned int sleeps = 0; sleeps < 20; sleeps++)
+            {
+                /* unlock our pvt struct */
+                if(pvt_locked)
+                {
+                    _mutex.unlock();
+                    pvt_locked = false;
+                }
+
+                /* wait a little while (100ms is good?) */
+                usleep (100000);
+
+                /* re-lock pvt struct */
+                switch (_mutex.lock())
+                {
+                case SimpleLock::ISINUSE:
+                case SimpleLock::FAILURE:
+                    LOG(ERROR, PVT_FMT(_target, "unable to lock pvt_mutex, trying again."));
+                    sched_yield();
+                    continue;
+
+                default:
+                    break;
+                }
+
+                pvt_locked = true;
+            
+                if(!session())
+                {
+                    is_ok = true;
+                    break;
+                }
+            }
+
+            if(is_ok)
+            {
+                DBG(FUNC, PVT_FMT(_target, "Session destroyed properly"));
+            }
+            else
+            {
+                LOG(ERROR, PVT_FMT(target(), "(ISDN) r (Session was not destroyed, stopping to wait)"));
+                return false;
+            }
+        }
+
+        if(isdn_reverse_charge)
+        { 
+            call()->_collect_call = true;
+        }
+
+        ret = KhompPvtE1::onNewCall(e); 
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(ISDN) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(ISDN) r"));   
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtISDN::onCallSuccess(K3L_EVENT *e)
+{
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(e->AddInfo > 0)
+        {
+            callISDN()->_isdn_cause = e->AddInfo;
+            setFSChannelVar("KISDNGotCause", Verbose::isdnCause((KQ931Cause)callISDN()->_isdn_cause).c_str());
+        }
+
+        ret = KhompPvtE1::onCallSuccess(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "%s") % err._msg.c_str());
+        return false;
+    }
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtISDN::onCallFail(K3L_EVENT *e)
+{
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(e->AddInfo > 0)
+        {
+            callISDN()->_isdn_cause = e->AddInfo;
+            setFSChannelVar("KISDNGotCause", Verbose::isdnCause((KQ931Cause)callISDN()->_isdn_cause).c_str());
+        }
+
+        setHangupCause(causeFromCallFail(e->AddInfo),true);
+
+        ret = KhompPvtE1::onCallFail(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "%s") % err._msg.c_str());
+        return false;
+    }
+
+    return ret;
+}
+
+RingbackDefs::RingbackStType BoardE1::KhompPvtISDN::sendRingBackStatus(int rb_value)
+{
+    DBG(FUNC, PVT_FMT(target(), "this is the rdsi ringback procedure"));
+
+
+    std::string cause = (rb_value == -1 ? "" : STG(FMT("isdn_cause=\"%d\"") % rb_value));
+    return (command(KHOMP_LOG, CM_RINGBACK, cause.c_str()) ?
+            RingbackDefs::RBST_SUCCESS : RingbackDefs::RBST_FAILURE);
+}
+
+bool BoardE1::KhompPvtISDN::sendPreAudio(int rb_value)
+{
+    if(!KhompPvtE1::sendPreAudio(rb_value))
+        return false;
+
+
+    DBG(FUNC,PVT_FMT(_target, "doing the ISDN pre_connect"));   
+
+    if (call()->_flags.check(Kflags::HAS_PRE_AUDIO))
+    {
+        DBG(FUNC, PVT_FMT(target(), "already pre_connect"));
+        return true;
+    }
+    else
+    {
+        bool result = command(KHOMP_LOG, CM_PRE_CONNECT);
+
+        if (result)
+            call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+
+        return result;
+    }
+}
+
+bool BoardE1::KhompPvtISDN::application(ApplicationType type, switch_core_session_t * session, const char *data)
+{
+    switch(type)
+    {
+        case USER_TRANSFER:
+            return _transfer->userTransfer(session, data);
+        default:
+            return KhompPvtE1::application(type, session, data);
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtISDN::sendDtmf(std::string digit)
+{
+    if(_transfer->checkUserXferUnlocked(digit))
+    {
+        DBG(FUNC, PVT_FMT(target(), "started (or waiting for) an user xfer"));
+        return true;
+    }
+
+    bool ret = KhompPvtE1::sendDtmf(callISDN()->_digits_buffer);
+        
+    callISDN()->_digits_buffer.clear();
+
+    return ret;
+}
+
+int BoardE1::KhompPvtE1::makeCall(std::string params)
+{
+    if(callE1()->_call_info_drop == 0 && !callE1()->_call_info_report)
+    {
+        command(KHOMP_LOG, CM_DISABLE_CALL_ANSWER_INFO);
+    }
+
+    if(!_call->_orig_addr.empty())
+        params += STG(FMT(" orig_addr=\"%s\"") % _call->_orig_addr);
+
+    int ret = KhompPvt::makeCall(params);
+
+    if(ret == ksSuccess)
+    {
+        startListen();
+    }
+    else
+    {
+        LOG(ERROR, PVT_FMT(target(), "Fail on make call"));
+    }   
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtE1::indicateBusyUnlocked(int cause, bool sent_signaling)
+{
+    DBG(FUNC, PVT_FMT(_target, "(E1) c"));
+
+    if(!KhompPvt::indicateBusyUnlocked(cause, sent_signaling))
+    {
+        DBG(FUNC, PVT_FMT(_target, "(E1) r (false)"));
+        return false;
+    }
+
+    if(call()->_flags.check(Kflags::IS_INCOMING))
+    {
+        if(!call()->_flags.check(Kflags::CONNECTED) && !sent_signaling)
+        {
+            if(!call()->_flags.check(Kflags::HAS_PRE_AUDIO))
+            {
+                int rb_value = callFailFromCause(call()->_hangup_cause);
+                DBG(FUNC, PVT_FMT(target(), "sending the busy status"));
+
+                if (sendRingBackStatus(rb_value) == RingbackDefs::RBST_UNSUPPORTED)
+                {
+                    DBG(FUNC, PVT_FMT(target(), "falling back to audio indication!"));
+                    /* stop the line audio */
+                    stopStream();
+
+                    /* just pre connect, no ringback */
+                    if (!sendPreAudio())
+                        DBG(FUNC, PVT_FMT(target(), "everything else failed, just sending audio indication..."));
+
+                    /* be very specific about the situation. */
+                    mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+                }
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), "going to play busy"));
+
+                /* stop the line audio */
+                stopStream();
+
+                /* be very specific about the situation. */
+                mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+
+            }
+        }
+        else
+        {
+            /* already connected or sent signaling... */
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+        }
+
+    }
+    else if(call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        /* already connected or sent signaling... */
+        mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(E1) r"));
+    
+    return true; 
+}
+
+void BoardE1::KhompPvtE1::setAnswerInfo(int answer_info)
+{
+    const char * value = answerInfoToString(answer_info);
+
+    if (value == NULL)
+    {    
+        DBG(FUNC, PVT_FMT(_target, "signaled unknown call answer info '%d', using 'Unknown'...") % answer_info);
+        value = "Unknown";
+    }   
+    
+    DBG(FUNC,PVT_FMT(_target, "KCallAnswerInfo: %s") % value);
+
+    try
+    {
+        setFSChannelVar("KCallAnswerInfo",value);
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "%s") % err._msg.c_str()); 
+    }
+}
+
+bool BoardE1::KhompPvtE1::setupConnection()
+{
+    if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        DBG(FUNC,PVT_FMT(_target, "Channel already disconnected"));
+        return false;
+    }
+
+    /* if received some disconnect from 'drop collect call'
+       feature of some pbx, then leave the call rock and rolling */
+    Board::board(_target.device)->_timers.del(callE1()->_idx_disconnect);
+
+    bool fax_detected = callE1()->_flags.check(Kflags::FAX_DETECTED) || (callE1()->_var_fax_adjust == T_TRUE);
+    
+    bool res_out_of_band_dtmf = (call()->_var_dtmf_state == T_UNKNOWN || fax_detected ?
+        Opt::_suppression_delay && Opt::_out_of_band_dtmfs && !fax_detected : (call()->_var_dtmf_state == T_TRUE));
+    
+    bool res_echo_cancellator = (call()->_var_echo_state == T_UNKNOWN || fax_detected ?
+        Opt::_echo_canceller && !fax_detected : (call()->_var_echo_state == T_TRUE));
+
+    bool res_auto_gain_cntrol = (call()->_var_gain_state == T_UNKNOWN || fax_detected ?
+        Opt::_auto_gain_control && !fax_detected : (call()->_var_gain_state == T_TRUE));
+
+    if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
+    {
+        obtainRX(res_out_of_band_dtmf);
+
+        /* esvazia buffers de leitura/escrita */ 
+        cleanupBuffers();
+
+        if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
+            dtmfSuppression(res_out_of_band_dtmf);
+
+        if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
+            echoCancellation(res_echo_cancellator);
+
+        if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
+            autoGainControl(res_auto_gain_cntrol);
+
+        startListen(false);
+
+        startStream();
+
+        DBG(FUNC, PVT_FMT(_target, "(E1) Audio callbacks initialized successfully"));  
+    }
+
+    return Board::KhompPvt::setupConnection();
+}
+
+bool BoardE1::KhompPvtE1::application(ApplicationType type, switch_core_session_t * session, const char *data)
+{
+    switch(type)
+    {
+        case FAX_ADJUST:
+            return _fax->adjustForFax();
+        case FAX_SEND:
+            return _fax->sendFax(session, data);
+        case FAX_RECEIVE:
+            return _fax->receiveFax(session, data);
+        default:
+            return KhompPvt::application(type, session, data);
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtE1::validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context)
+{
+    DBG(FUNC,PVT_FMT(_target, "(E1) c"));
+
+    contexts.push_back(Opt::_context_digital);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++) 
+    {    
+        replaceTemplate((*i), "LL", ((_target.object)/30));
+        replaceTemplate((*i), "CCC", _target.object);
+    }
+
+    bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
+
+    DBG(FUNC,PVT_FMT(_target, "(E1) r"));
+
+    return ret;
+}
+
+int BoardE1::KhompPvtISDN::makeCall(std::string params)
+{
+    DBG(FUNC,PVT_FMT(_target, "(ISDN) c"));   
+
+    CallISDN * call = callISDN();
+
+    if(call->_uui_descriptor != -1)
+    {
+        DBG(FUNC,PVT_FMT(_target, "got userinfo"));   
+
+        /* grab this information first, avoiding latter side-effects */
+        const char * info_data = call->_uui_information.c_str();
+        size_t       info_size = std::min(call->_uui_information.size(), (size_t)KMAX_USER_USER_LEN);
+
+        KUserInformation info;
+
+        info.ProtocolDescriptor = call->_uui_descriptor;
+        info.UserInfoLength = info_size;
+
+        memcpy((void *) info.UserInfo, (const void *) info_data, info_size);
+
+        if (!command(KHOMP_LOG, CM_USER_INFORMATION, (const char *)&info))
+        {
+            LOG(ERROR,PVT_FMT(_target, "UUI could not be sent before dialing!"));   
+        }
+
+        call->_uui_descriptor = -1;
+        call->_uui_information.clear();
+    }
+
+    int ret = KhompPvtE1::makeCall(params);
+
+    call->_cleanup_upon_hangup = (ret == ksInvalidParams || ret == ksBusy);
+    
+    DBG(FUNC,PVT_FMT(_target, "(ISDN) r"));   
+
+    return ret;
+}
+
+void BoardE1::KhompPvtISDN::reportFailToReceive(int fail_code)
+{
+    KhompPvt::reportFailToReceive(fail_code);
+
+    if(fail_code != -1)
+    {
+        DBG(FUNC,PVT_FMT(_target, "sending a 'unknown number' message/audio")); 
+
+        if(sendRingBackStatus(fail_code) == RingbackDefs::RBST_UNSUPPORTED)
+        {
+            sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+            startCadence(PLAY_FASTBUSY);
+        }
+    }
+    else
+    {
+        DBG(FUNC, PVT_FMT(_target, "sending fast busy audio directly"));
+
+        sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+        startCadence(PLAY_FASTBUSY);
+    }
+}
+
+bool BoardE1::KhompPvtISDN::doChannelAnswer(CommandRequest &cmd)
+{
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        // is this a collect call?
+        bool has_recv_collect_call = _call->_collect_call;
+
+        if(has_recv_collect_call)
+            DBG(FUNC, PVT_FMT(target(), "receive a collect call"));
+
+        if(call()->_flags.check(Kflags::DROP_COLLECT))
+            DBG(FUNC, PVT_FMT(target(), "flag DROP_COLLECT == true"));
+
+        // do we have to drop collect calls?
+        bool has_drop_collect_call = call()->_flags.check(Kflags::DROP_COLLECT);
+
+        // do we have to drop THIS call?
+        bool do_drop_call = has_drop_collect_call && has_recv_collect_call;
+
+        if(!do_drop_call)
+        {
+            command(KHOMP_LOG, CM_CONNECT);
+        }
+        else
+        {
+            usleep(75000);
+
+            DBG(FUNC, PVT_FMT(target(), "disconnecting collect call doChannelAnswer ISDN"));
+            command(KHOMP_LOG,CM_DISCONNECT);
+
+            // thou shalt not talk anymore!
+            stopListen();
+            stopStream();
+        }
+
+        ret = KhompPvtE1::doChannelAnswer(cmd);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return ret;
+}
+
+int BoardE1::KhompPvtR2::makeCall(std::string params)
+{
+    DBG(FUNC,PVT_FMT(_target, "(R2) c"));   
+
+    if (callR2()->_r2_category != -1)
+        params += STG(FMT(" r2_categ_a=\"%ld\"")
+                % callR2()->_r2_category);
+
+    int ret = KhompPvtE1::makeCall(params);
+
+    call()->_cleanup_upon_hangup = (ret == ksInvalidParams);
+    
+    DBG(FUNC,PVT_FMT(_target, "(R2) r"));   
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtR2::doChannelAnswer(CommandRequest &cmd)
+{
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        // is this a collect call?
+        bool has_recv_collect_call = _call->_collect_call;
+
+        if(has_recv_collect_call)
+            DBG(FUNC, PVT_FMT(target(), "receive a collect call"));
+
+        if(call()->_flags.check(Kflags::DROP_COLLECT))
+            DBG(FUNC, PVT_FMT(target(), "flag DROP_COLLECT == true"));
+        
+        // do we have to drop collect calls?
+        bool has_drop_collect_call = call()->_flags.check(Kflags::DROP_COLLECT);
+
+        // do we have to drop THIS call?
+        bool do_drop_call = has_drop_collect_call && has_recv_collect_call;
+
+        bool do_send_ring = call()->_flags.check(Kflags::NEEDS_RINGBACK_CMD);
+
+        // do we have to send ringback? yes we need !!!
+        if(do_send_ring)
+        {       
+            call()->_flags.clear(Kflags::NEEDS_RINGBACK_CMD);
+            std::string cause = ( do_drop_call ? STG(FMT("r2_cond_b=\"%d\"") % kgbBusy) : "" );
+            command(KHOMP_LOG,CM_RINGBACK,cause.c_str());
+
+            usleep(75000);
+        }
+
+        if(!(do_drop_call && do_send_ring))
+        {
+            command(KHOMP_LOG, CM_CONNECT);
+        }
+
+        if(has_drop_collect_call && !do_send_ring) 
+        {
+            if(has_recv_collect_call)
+            {
+                usleep(75000);
+
+                DBG(FUNC, PVT_FMT(target(), "disconnecting collect call doChannelAnswer R2"));
+                command(KHOMP_LOG,CM_DISCONNECT);
+
+                // thou shalt not talk anymore!
+                stopListen();
+                stopStream();
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), "dropping collect call at doChannelAnswer"));
+                command(KHOMP_LOG, CM_DROP_COLLECT_CALL);
+            }
+        }
+
+        ret = KhompPvtE1::doChannelAnswer(cmd);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtR2::doChannelHangup(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(R2) c"));
+
+    bool answered     = true;
+    bool disconnected = false;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            DBG(FUNC,PVT_FMT(_target, "disconnecting incoming channel"));
+
+            //disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+        }
+        else if (call()->_flags.check(Kflags::IS_OUTGOING))
+        {
+            if(call()->_cleanup_upon_hangup)
+            {
+                DBG(FUNC,PVT_FMT(_target, "disconnecting not allocated outgoing channel..."));
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+                cleanup(KhompPvt::CLN_HARD);
+                answered = false;
+
+            }
+            else
+            {
+                DBG(FUNC,PVT_FMT(_target, "disconnecting outgoing channel...")); 
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+            }
+        }
+        else
+        {
+            DBG(FUNC,PVT_FMT(_target, "already disconnected"));
+            return true;
+        }
+
+        if(answered)
+        {
+            indicateBusyUnlocked(SWITCH_CAUSE_USER_BUSY, disconnected);
+        }
+
+        if (call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::NEEDS_RINGBACK_CMD))
+        {
+            DBG(FUNC,PVT_FMT(_target, "disconnecting incoming channel..."));
+            disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+        }
+
+        stopStream();
+
+        stopListen();
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(R2) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+
+    DBG(FUNC, PVT_FMT(_target, "(R2) r"));
+    return true;
+}
+
+int BoardE1::KhompPvtISDN::causeFromCallFail(int fail)
+{
+    int switch_cause = SWITCH_CAUSE_USER_BUSY;
+
+    if (fail <= 127) 
+        switch_cause = fail;
+    else 
+        switch_cause = SWITCH_CAUSE_INTERWORKING;
+
+    return switch_cause;
+}
+
+void BoardE1::KhompPvtR2::reportFailToReceive(int fail_code)
+{
+    KhompPvt::reportFailToReceive(fail_code);
+
+    if (Opt::_r2_strict_behaviour && fail_code != -1)
+    {
+        DBG(FUNC,PVT_FMT(_target, "sending a 'unknown number' message/audio")); 
+
+        if(sendRingBackStatus(fail_code) == RingbackDefs::RBST_UNSUPPORTED)
+        {
+            sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+            startCadence(PLAY_FASTBUSY);
+        }
+    }
+    else
+    {
+        DBG(FUNC, PVT_FMT(_target, "sending fast busy audio directly"));
+
+        sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+        startCadence(PLAY_FASTBUSY);
+    }
+}
+
+int BoardE1::KhompPvtR2::causeFromCallFail(int fail)
+{
+    int switch_cause = SWITCH_CAUSE_USER_BUSY;
+
+    try
+    {
+        bool handled = false;
+
+        switch (_r2_country)
+        {
+            case Verbose::R2_COUNTRY_ARG:
+                switch (fail)
+                {
+                    case kgbArBusy:
+                        switch_cause = SWITCH_CAUSE_USER_BUSY;
+                        break;
+                    case kgbArNumberChanged:
+                        switch_cause = SWITCH_CAUSE_NUMBER_CHANGED;
+                        break;
+                    case kgbArCongestion:
+                        switch_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                        break;
+                    case kgbArInvalidNumber:
+                        switch_cause = SWITCH_CAUSE_UNALLOCATED_NUMBER;
+                        break;
+                    case kgbArLineOutOfOrder:
+                        switch_cause = SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+                        break;
+                }
+                handled = true;
+                break;
+
+            case Verbose::R2_COUNTRY_BRA:
+                switch (fail)
+                {
+                    case kgbBrBusy:
+                        switch_cause = SWITCH_CAUSE_USER_BUSY;
+                        break;
+                    case kgbBrNumberChanged:
+                        switch_cause = SWITCH_CAUSE_NUMBER_CHANGED;
+                        break;
+                    case kgbBrCongestion:
+                        switch_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                        break;
+                    case kgbBrInvalidNumber:
+                        switch_cause = SWITCH_CAUSE_UNALLOCATED_NUMBER;
+                        break;
+                    case kgbBrLineOutOfOrder:
+                        switch_cause = SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+                        break;
+                }
+                handled = true;
+                break;
+            case Verbose::R2_COUNTRY_CHI:
+                    switch (fail)
+                    {
+                        case kgbClBusy:
+                            switch_cause = SWITCH_CAUSE_USER_BUSY;
+                            break;
+                        case kgbClNumberChanged:
+                            switch_cause = SWITCH_CAUSE_NUMBER_CHANGED;
+                            break;
+                        case kgbClCongestion:
+                            switch_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                            break;
+                        case kgbClInvalidNumber:
+                            switch_cause = SWITCH_CAUSE_UNALLOCATED_NUMBER;
+                            break;
+                        case kgbClLineOutOfOrder:
+                            switch_cause = SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+                            break;
+                    }
+                handled = true;
+                break;
+
+            case Verbose::R2_COUNTRY_MEX:
+                switch (fail)
+                {
+                    case kgbMxBusy:
+                        switch_cause = SWITCH_CAUSE_USER_BUSY;
+                        break;
+                }
+                handled = true;
+                break;
+
+            case Verbose::R2_COUNTRY_URY:
+                switch (fail)
+                {
+                    case kgbUyBusy:
+                        switch_cause = SWITCH_CAUSE_USER_BUSY;
+                        break;
+                    case kgbUyNumberChanged:
+                        switch_cause = SWITCH_CAUSE_NUMBER_CHANGED;
+                        break;
+                    case kgbUyCongestion:
+                        switch_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                        break;
+                    case kgbUyInvalidNumber:
+                        switch_cause = SWITCH_CAUSE_UNALLOCATED_NUMBER;
+                        break;
+                    case kgbUyLineOutOfOrder:
+                        switch_cause = SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL;
+                        break;
+                }
+                handled = true;
+                break;
+            case Verbose::R2_COUNTRY_VEN:
+                switch (fail)
+                {
+                    case kgbVeBusy:
+                        switch_cause = SWITCH_CAUSE_USER_BUSY;
+                        break;
+                    case kgbVeNumberChanged:
+                        switch_cause = SWITCH_CAUSE_NUMBER_CHANGED;
+                        break;
+                    case kgbVeCongestion:
+                        switch_cause = SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                        break;
+                    case kgbVeLineBlocked:
+                        switch_cause = SWITCH_CAUSE_OUTGOING_CALL_BARRED;
+                        break;
+                }
+                handled = true;
+                break;
+        }
+
+        if (!handled)
+            throw std::runtime_error("");
+    }
+    catch (...)
+    {
+        LOG(ERROR,
+                PVT_FMT(_target, "country signaling not found, unable to report R2 hangup code.."));
+    }
+
+    return switch_cause;
+
+}
+
+int BoardE1::KhompPvtR2::callFailFromCause(int cause)
+{
+    int k3l_fail = -1; // default
+
+    try  
+    {    
+        bool handled = false;
+
+        switch (_r2_country)
+        {    
+            case Verbose::R2_COUNTRY_ARG:
+                switch (cause)
+                {    
+                    case SWITCH_CAUSE_UNALLOCATED_NUMBER:
+                    case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+                    case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+                    case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+                    case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
+                    case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+
+                    case SWITCH_CAUSE_INCOMING_CALL_BARRED: /* ?? */
+                    case SWITCH_CAUSE_OUTGOING_CALL_BARRED: /* ?? */
+                        k3l_fail = kgbArInvalidNumber;
+                        break;
+
+                    case SWITCH_CAUSE_USER_BUSY:
+                    case SWITCH_CAUSE_NO_USER_RESPONSE:
+                    case SWITCH_CAUSE_CALL_REJECTED:
+                        k3l_fail = kgbArBusy;
+                        break;
+
+                    case SWITCH_CAUSE_NUMBER_CHANGED:
+                        k3l_fail = kgbArNumberChanged;
+                        break;
+
+                    case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                    case SWITCH_CAUSE_SWITCH_CONGESTION:
+
+                    case SWITCH_CAUSE_NORMAL_CLEARING:
+                    case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+                    case SWITCH_CAUSE_CALL_AWARDED_DELIVERED: /* ?? */
+                        // this preserves semantics..
+                        k3l_fail = kgbArCongestion;
+                        break;
+
+                    case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+                    case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
+                    case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_FACILITY_REJECTED:
+                    case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+                    case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
+                    default:
+                        k3l_fail = kgbArLineOutOfOrder;
+                        break;
+                }    
+                handled = true;
+                break;
+
+            case Verbose::R2_COUNTRY_BRA:
+                switch (cause)
+                {    
+                    case SWITCH_CAUSE_UNALLOCATED_NUMBER:
+                    case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+                    case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+                    case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+                    case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
+                    case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+
+                    case SWITCH_CAUSE_INCOMING_CALL_BARRED: /* ?? */
+                    case SWITCH_CAUSE_OUTGOING_CALL_BARRED: /* ?? */
+                        k3l_fail = kgbBrInvalidNumber;
+                        break;
+
+                    case SWITCH_CAUSE_USER_BUSY:
+                    case SWITCH_CAUSE_NO_USER_RESPONSE:
+                    case SWITCH_CAUSE_CALL_REJECTED:
+                        k3l_fail = kgbBrBusy;
+                        break;
+
+                    case SWITCH_CAUSE_NUMBER_CHANGED:
+                        k3l_fail = kgbBrNumberChanged;
+                        break;
+
+                    case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                    case SWITCH_CAUSE_SWITCH_CONGESTION:
+
+                    case SWITCH_CAUSE_NORMAL_CLEARING:
+                    case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+                    case SWITCH_CAUSE_CALL_AWARDED_DELIVERED: /* ?? */
+                        // this preserves semantics..
+                        k3l_fail = kgbBrCongestion;
+                        break;
+
+                    case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+                    case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
+                    case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_FACILITY_REJECTED:
+                    case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+                    case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
+                    default:
+                        k3l_fail = kgbBrLineOutOfOrder;
+                        break;
+                }
+                handled = true;
+                break;
+
+            case Verbose::R2_COUNTRY_CHI:
+                switch (cause)
+                {
+                    case SWITCH_CAUSE_UNALLOCATED_NUMBER:
+                    case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+                    case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+                    case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+                    case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
+                    case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+
+                    case SWITCH_CAUSE_INCOMING_CALL_BARRED: /* ?? */
+                    case SWITCH_CAUSE_OUTGOING_CALL_BARRED: /* ?? */
+                        k3l_fail = kgbClInvalidNumber;
+                        break;
+
+                    case SWITCH_CAUSE_USER_BUSY:
+                    case SWITCH_CAUSE_NO_USER_RESPONSE:
+                    case SWITCH_CAUSE_CALL_REJECTED:
+                        k3l_fail = kgbClBusy;
+                        break;
+
+                    case SWITCH_CAUSE_NUMBER_CHANGED:
+                        k3l_fail = kgbClNumberChanged;
+                        break;
+
+                    case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                    case SWITCH_CAUSE_SWITCH_CONGESTION:
+
+                    case SWITCH_CAUSE_NORMAL_CLEARING:
+                    case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+                    case SWITCH_CAUSE_CALL_AWARDED_DELIVERED: /* ?? */
+                        // this preserves semantics..
+                        k3l_fail = kgbClCongestion;
+                        break;
+
+                    case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+                    case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
+                    case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_FACILITY_REJECTED:
+                    case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+                    case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
+                    default:
+                        k3l_fail = kgbClLineOutOfOrder;
+                        break;
+                }
+                handled = true;
+                break;
+
+
+            case Verbose::R2_COUNTRY_MEX:
+                k3l_fail = kgbMxBusy;
+                handled = true;
+                break;
+
+
+            case Verbose::R2_COUNTRY_URY:
+                switch (cause)
+                {
+                    case SWITCH_CAUSE_UNALLOCATED_NUMBER:
+                    case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+                    case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+                    case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+                    case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
+                    case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+
+                    case SWITCH_CAUSE_INCOMING_CALL_BARRED: /* ?? */
+                    case SWITCH_CAUSE_OUTGOING_CALL_BARRED: /* ?? */
+                        k3l_fail = kgbUyInvalidNumber;
+                        break;
+
+                    case SWITCH_CAUSE_USER_BUSY:
+                    case SWITCH_CAUSE_NO_USER_RESPONSE:
+                    case SWITCH_CAUSE_CALL_REJECTED:
+                        k3l_fail = kgbUyBusy;
+                        break;
+
+                    case SWITCH_CAUSE_NUMBER_CHANGED:
+                        k3l_fail = kgbUyNumberChanged;
+                        break;
+
+                    case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                    case SWITCH_CAUSE_SWITCH_CONGESTION:
+
+                    case SWITCH_CAUSE_NORMAL_CLEARING:
+                    case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+                    case SWITCH_CAUSE_CALL_AWARDED_DELIVERED: /* ?? */
+                        // this preserves semantics..
+                        k3l_fail = kgbUyCongestion;
+                        break;
+
+                    case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+                    case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
+                    case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_FACILITY_REJECTED:
+                    case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+                    case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
+                    default:
+                        k3l_fail = kgbUyLineOutOfOrder;
+                        break;
+                }
+                handled = true;
+                break;
+
+
+            case Verbose::R2_COUNTRY_VEN:
+                switch (cause)
+                {
+                    case SWITCH_CAUSE_INCOMING_CALL_BARRED:
+                    case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
+                        k3l_fail = kgbVeLineBlocked;
+                        break;
+
+                    case SWITCH_CAUSE_NUMBER_CHANGED:
+                        k3l_fail = kgbVeNumberChanged;
+                        break;
+
+                    case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+                    case SWITCH_CAUSE_SWITCH_CONGESTION:
+
+                    case SWITCH_CAUSE_NORMAL_CLEARING:
+                    case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+                    case SWITCH_CAUSE_CALL_AWARDED_DELIVERED: /* ?? */
+                        // this preserves semantics..
+                        k3l_fail = kgbVeCongestion;
+                        break;
+
+                    case SWITCH_CAUSE_UNALLOCATED_NUMBER:
+                    case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+                    case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+                    case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+                    case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED:
+                    case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+
+                    case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+                    case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE:
+                    case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+                    case SWITCH_CAUSE_FACILITY_REJECTED:
+                    case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+                    case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED:
+
+                    case SWITCH_CAUSE_USER_BUSY:
+                    case SWITCH_CAUSE_NO_USER_RESPONSE:
+                    case SWITCH_CAUSE_CALL_REJECTED:
+                    default:
+                        k3l_fail = kgbVeBusy;
+                        break;
+                }
+
+                handled = true;
+                break;
+
+        }
+    
+        if (!handled)
+            throw std::runtime_error("");
+    }
+    catch(...)
+    {
+        LOG(ERROR,PVT_FMT(_target, "country signaling not found, unable to report R2 hangup code."));
+    }
+
+    return k3l_fail;
+}
+
+int BoardE1::KhompPvtISDN::callFailFromCause(int cause)
+{
+    int k3l_fail = -1; // default
+
+    if (cause <= 127) 
+        k3l_fail = cause;
+    else 
+        k3l_fail = kq931cInterworking;
+
+    return k3l_fail;
+}
+
+RingbackDefs::RingbackStType BoardE1::KhompPvtR2::sendRingBackStatus(int rb_value)
+{
+    DBG(FUNC,PVT_FMT(_target, "(p=%p) this is the r2 ringback procedure") % this);   
+
+    std::string cause = (rb_value == -1 ? "" : STG(FMT("r2_cond_b=\"%d\"") % rb_value));
+    return (command(KHOMP_LOG, CM_RINGBACK, cause.c_str()) ?
+            RingbackDefs::RBST_SUCCESS : RingbackDefs::RBST_FAILURE);
+}
+
+bool BoardE1::KhompPvtR2::sendPreAudio(int rb_value)
+{
+    DBG(FUNC,PVT_FMT(_target, "must send R2 preaudio ?"));   
+    if(!KhompPvtE1::sendPreAudio(rb_value))
+        return false;
+
+
+    DBG(FUNC,PVT_FMT(_target, "doing the R2 pre_connect wait..."));   
+
+    /* wait some ms, just to be sure the command has been sent. */
+    usleep(Opt::_r2_preconnect_wait * 1000);
+
+    if (call()->_flags.check(Kflags::HAS_PRE_AUDIO))
+    {
+        DBG(FUNC, PVT_FMT(target(), "(p=%p) already pre_connect") % this);
+        return true;
+    }
+    else
+    {
+        bool result = command(KHOMP_LOG, CM_PRE_CONNECT);
+
+        if (result)
+            call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+
+        return result;
+    }
+}
+
+void BoardE1::KhompPvtR2::numberDialTimer(Board::KhompPvt * pvt)
+{
+    try 
+    {   
+        ScopedPvtLock lock(pvt);
+
+        if (!pvt->call()->_flags.check(Kflags::NUMBER_DIAL_ONGOING) ||
+             pvt->call()->_flags.check(Kflags::NUMBER_DIAL_FINISHD))
+        {   
+            return;
+        }   
+
+        pvt->call()->_flags.set(Kflags::NUMBER_DIAL_FINISHD);
+
+        static_cast<BoardE1::KhompPvtR2*>(pvt)->callR2()->_incoming_exten.clear();
+        pvt->command(KHOMP_LOG, CM_END_OF_NUMBER);
+    }   
+    catch (...)
+    {   
+        // TODO: log something.
+    }   
+}
+
+bool BoardE1::KhompPvtR2::indicateRinging()
+{
+    DBG(FUNC, PVT_FMT(_target, "(R2) c")); 
+
+    bool ret = false;
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        /* already playing! */
+        if (call()->_indication != INDICA_NONE)
+        {    
+            DBG(FUNC, PVT_FMT(_target, "(R2) r (already playing something: %d)") % call()->_indication);
+            return false;
+        }    
+
+        // any collect calls ?
+        setCollectCall();
+
+        call()->_indication = INDICA_RING;
+
+        bool send_ringback = true;
+
+        if (!call()->_flags.check(Kflags::CONNECTED))
+        {    
+            int ringback_value = RingbackDefs::RB_SEND_DEFAULT;
+
+            bool do_drop_call = Opt::_drop_collect_call
+                                        || call()->_flags.check(Kflags::DROP_COLLECT);
+
+            if (do_drop_call && call()->_collect_call)
+            {
+                ringback_value = kgbBusy;
+                DBG(FUNC, PVT_FMT(_target, "ringback value adjusted to refuse collect call: %d") % ringback_value);
+            }
+
+            const char *condition_string = getFSChannelVar("KR2SendCondition");
+
+            try  
+            {    
+                if (condition_string)
+                {    
+                    ringback_value = Strings::toulong(condition_string);
+                    DBG(FUNC, PVT_FMT(_target, "KR2SendCondition adjusted ringback value to %d") % ringback_value);
+                }    
+            }    
+            catch (Strings::invalid_value e)
+            {    
+                LOG(ERROR, PVT_FMT(_target, "invalid value '%s', adjusted in KR2SendCondition: not a valid number.")
+                        % condition_string);
+            }    
+
+            if (Opt::_r2_strict_behaviour)
+            {
+                /* send ringback too? */
+                send_ringback = sendPreAudio(ringback_value);
+
+                if (!send_ringback)
+                {
+                    /* warn the developer which may be debugging some "i do not have ringback!" issue. */
+                    DBG(FUNC, PVT_FMT(_target, "not sending pre connection audio"));
+                }
+
+                call()->_flags.clear(Kflags::NEEDS_RINGBACK_CMD);
+            }
+
+        }
+
+        if (send_ringback)
+        {             
+            DBG(FUNC, PVT_FMT(_target, "Send ringback!"));
+
+            call()->_flags.set(Kflags::GEN_CO_RING);
+            call()->_idx_co_ring = Board::board(_target.device)->_timers.add(Opt::_ringback_co_delay, &Board::KhompPvt::coRingGen,this);
+
+            /* start grabbing audio */
+            startListen();
+
+            /* start stream if it is not already */
+            startStream();
+
+            ret = true; 
+        }   
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(R2) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "(R2) r (%s)") % err._msg.c_str());
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(R2) r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(R2) r"));
+    return ret;
+}
+
+bool BoardE1::KhompPvtR2::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC,PVT_FMT(_target, "(R2) c"));   
+
+    std::string r2_categ_a;
+
+    int status = Globals::k3lapi.get_param(e, "r2_categ_a", r2_categ_a);
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (status == ksSuccess && !r2_categ_a.empty())
+        {
+
+            try 
+            { 
+                callR2()->_r2_category = Strings::toulong(r2_categ_a); 
+            }
+            catch (Strings::invalid_value e) 
+            { 
+                /* do nothing */ 
+            };
+
+            /* channel will know if is a collect call or not */
+            if (callR2()->_r2_category == kg2CollectCall)
+            {
+                call()->_collect_call = true;
+            }
+        }
+
+        bool ret = KhompPvtE1::onNewCall(e);
+
+        if(!ret)
+            return false;
+
+        if (!Opt::_r2_strict_behaviour)
+        {
+            bool do_drop_collect = Opt::_drop_collect_call;
+            const char* drop_str = getFSGlobalVar("KDropCollectCall");
+
+            if(checkTrueString(drop_str))
+            {
+                do_drop_collect = true;
+                call()->_flags.set(Kflags::DROP_COLLECT);
+                DBG(FUNC,PVT_FMT(_target, "Setting DROP_COLLECT flag"));
+            }
+
+            // keeping the hardcore mode
+            if (do_drop_collect && call()->_collect_call)
+            {
+                // kill, kill, kill!!!
+                DBG(FUNC,PVT_FMT(_target, "dropping collect call at onNewCall"));
+                sendRingBackStatus(callFailFromCause(SWITCH_CAUSE_CALL_REJECTED));
+                usleep(75000);
+            }
+            else
+            {
+                // send ringback too! 
+                sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+                startStream();
+            }
+        }
+        else
+        {
+            _call->_flags.set(Kflags::NEEDS_RINGBACK_CMD);
+        }
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(R2) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(R2) r"));   
+
+    return true;
+}
+
+bool BoardE1::KhompPvtR2::onCallSuccess(K3L_EVENT *e)
+{
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(e->AddInfo > 0)
+        {
+            callR2()->_r2_condition = e->AddInfo;
+            setFSChannelVar("KR2GotCondition", Verbose::signGroupB((KSignGroupB)callR2()->_r2_condition).c_str());
+        }
+
+        KhompPvtE1::onCallSuccess(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "%s") % err._msg.c_str()); 
+        return false;
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtR2::onCallFail(K3L_EVENT *e)
+{
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(e->AddInfo > 0)
+        {
+            callR2()->_r2_condition = e->AddInfo;
+            setFSChannelVar("KR2GotCondition", Verbose::signGroupB((KSignGroupB)callR2()->_r2_condition).c_str());
+        }
+
+        setHangupCause(causeFromCallFail(e->AddInfo),true);
+
+        ret = KhompPvtE1::onCallFail(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "%s") % err._msg.c_str());
+        return false;
+    }
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtR2::onNumberDetected(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(digit=%d) c") % e->AddInfo);
+
+    try  
+    {    
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::NUMBER_DIAL_FINISHD))
+            return false;
+
+        if (!call()->_flags.check(Kflags::NUMBER_DIAL_ONGOING))
+        {    
+            DBG(FUNC, PVT_FMT(_target, "incoming number start..."));
+
+            call()->_flags.set(Kflags::NUMBER_DIAL_ONGOING);
+            callR2()->_incoming_exten.clear();
+
+            callR2()->_idx_number_dial = Board::board(_target.device)->_timers.add(4000,
+                &BoardE1::KhompPvtR2::numberDialTimer, this, TM_VAL_CALL);
+        }    
+        else 
+        {    
+            Board::board(_target.device)->_timers.restart(callR2()->_idx_number_dial);
+        }    
+
+        callR2()->_incoming_exten += e->AddInfo;
+
+        DBG(FUNC, PVT_FMT(_target, "incoming exten %s") % callR2()->_incoming_exten);
+
+        /* begin context adjusting + processing */
+        Board::KhompPvt::ContextListType contexts;
+
+        validContexts(contexts);
+
+        /* temporary */
+        std::string tmp_exten("s");
+        std::string tmp_context("default");
+        std::string tmp_orig("");
+
+        switch (findExtension(tmp_exten, tmp_context, contexts, callR2()->_incoming_exten,tmp_orig, false, false))
+        {    
+            case MATCH_EXACT:
+            case MATCH_NONE:
+                call()->_flags.set(Kflags::NUMBER_DIAL_FINISHD);
+
+                DBG(FUNC,FMT("incoming exten matched: %s") % callR2()->_incoming_exten);
+
+                callR2()->_incoming_exten.clear();
+                command(KHOMP_LOG,CM_END_OF_NUMBER);
+                break;
+
+            case MATCH_MORE:
+                DBG(FUNC, "didn't match exact extension, waiting...");
+                // cannot say anything exact about the number, do nothing...
+                break;
+        }    
+    }    
+    catch (ScopedLockFailed & err)
+    {    
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+        return false;
+    }    
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to get device: %d!") % err.device);
+        return false;
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtFlash::application(ApplicationType type, switch_core_session_t * session, const char *data)
+{
+    switch(type)
+    {
+        case USER_TRANSFER:
+            return _transfer->userTransfer(session, data);
+        default:
+            return KhompPvtR2::application(type, session, data);
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtFlash::sendDtmf(std::string digit)
+{
+    if(_transfer->checkUserXferUnlocked(digit))
+    {
+        DBG(FUNC, PVT_FMT(target(), "started (or waiting for) an user xfer"));
+        return true;
+    }
+
+    bool ret = KhompPvtR2::sendDtmf(callFlash()->_digits_buffer);
+
+    callFlash()->_digits_buffer.clear();
+
+    return ret;
+}
+
+Opt::OrigToNseqMapType BoardE1::KhompPvtFXS::generateNseqMap()
+{
+    Opt::OrigToNseqMapType fxs_nseq; /* sequence numbers on FXS */
+
+    fxs_nseq.insert(Opt::OrigToNseqPairType("", 0)); /* global sequence */
+
+    for (Opt::BoardToOrigMapType::iterator i = Opt::_fxs_orig_base.begin(); i != Opt::_fxs_orig_base.end(); i++)
+    {
+        fxs_nseq.insert(Opt::OrigToNseqPairType((*i).second, 0));
+    }
+
+    return fxs_nseq;
+}
+
+
+void BoardE1::KhompPvtFXS::load(Opt::OrigToNseqMapType & fxs_nseq)
+{
+    Opt::BoardToOrigMapType::iterator it1 = Opt::_fxs_orig_base.find(_target.device);
+    Opt::OrigToNseqMapType::iterator  it2;
+
+    std::string orig_base("invalid"); /* will have orig base */
+
+    if (it1 == Opt::_fxs_orig_base.end())
+    {
+        it2 = fxs_nseq.find("");
+        orig_base = Opt::_fxs_global_orig_base;
+    }
+    else
+    {
+        it2 = fxs_nseq.find((*it1).second);
+        orig_base = (*it1).second;
+    }
+
+    if (it2 == fxs_nseq.end())
+    {
+        LOG(ERROR, PVT_FMT(_target, "could not find sequence number for FXS channel"));
+
+        /* Ok, load the default options */
+        loadOptions();
+    }
+    else
+    {
+        try
+        {
+            /* generate orig_addr, padding to the original size (adding zeros at left) */
+            _fxs_fisical_addr = padOrig(orig_base, (*it2).second);
+
+            /* Set this branch options to get right callerid before mapping */
+            loadOptions();
+
+            /* makes a "reverse mapping" for Dial using 'r' identifiers */
+            Opt::_fxs_branch_map.insert(Opt::BranchToObjectPairType(_fxs_orig_addr,
+                Opt::ObjectIdType(_target.device, _target.object)));
+
+            /* increment sequence number */
+            ++((*it2).second);
+        }
+        catch (Strings::invalid_value e)
+        {
+            LOG(ERROR, PVT_FMT(_target, "expected an integer, got string '%s'")
+                % e.value() );
+        }
+    }
+}
+
+void BoardE1::KhompPvtFXS::loadOptions()
+{
+    /* the fxs_orig_addr can be reset on parse_branch_options */
+    _fxs_orig_addr = _fxs_fisical_addr;
+
+    /* Initialize fxs default options */
+    _calleridname.clear();
+    _amaflags = Opt::_amaflags;
+    _callgroup = Opt::_callgroup;
+    _pickupgroup = Opt::_pickupgroup;
+    _context.clear();
+    _input_volume = Opt::_input_volume;
+    _output_volume = Opt::_output_volume;
+    _mohclass = Opt::_global_mohclass;
+    _language = Opt::_global_language;
+    _accountcode = Opt::_accountcode;
+    _mailbox.clear();
+
+    Opt::BranchToOptMapType::iterator it3 = Opt::_branch_options.find(_fxs_orig_addr);
+
+    if (it3 != Opt::_branch_options.end())
+    {
+        parseBranchOptions(it3->second);
+    }
+
+    //TODO: Implementar o setVolume para levar em consideracao que o 
+    //       padrao pode ser o da FXS
+    if (_input_volume != Opt::_input_volume)
+        setVolume("input", _input_volume);
+    if (_output_volume != Opt::_output_volume)
+        setVolume("output", _output_volume);
+}
+
+bool BoardE1::KhompPvtFXS::parseBranchOptions(std::string options_str)
+{
+    Strings::vector_type options;
+    Strings::tokenize(options_str, options, "|/");
+
+    if (options.size() < 1)
+    {
+        DBG(FUNC, PVT_FMT(_target, "[fxs-options] no options are set for branch %s.") %
+                _fxs_orig_addr.c_str());
+        return false;
+    }
+
+    try
+    {
+        for (Strings::vector_type::iterator it = options.begin(); it != options.end(); it++)
+        {
+            Strings::vector_type par;
+            Strings::tokenize(Strings::trim(*it), par, ":");
+
+            if ( par.size() != 2 )
+            {
+                LOG(WARNING, PVT_FMT(_target, "[fxs-options] error on parsing options for branch %s.") % _fxs_orig_addr.c_str());
+                return false;
+            }
+
+            std::string opt_name = Strings::trim(par.at(0));
+            std::string opt_value = Strings::trim(par.at(1));
+
+            if (opt_name == "pickupgroup")
+            {
+               _pickupgroup = opt_value;//ast_get_group(opt_value.c_str());
+            }
+            else if (opt_name == "callgroup")
+            {
+               _callgroup = opt_value;//ast_get_group(opt_value.c_str());
+            }
+            /*
+               else if (opt_name == "amaflags")
+               {
+               int amaflags = ast_cdr_amaflags2int(opt_value.c_str());
+
+               if (amaflags < 0)
+               DBG(FUNC, PVT_FMT(_target, "[fxs-options] invalid AMA flags on branch %s.") % _fxs_orig_addr.c_str());
+               else
+               _amaflags = amaflags;
+               }
+            */
+            else if (opt_name == "context")
+            {
+                _context = opt_value;
+            }
+            else if (opt_name == "input-volume")
+            {
+                long long volume = Strings::tolong(opt_value);
+
+                if ( (volume < -10) || (volume > 10) )
+                {
+                    DBG(FUNC, PVT_FMT(_target, "[fxs-options] input-volume on branch %s.") % _fxs_orig_addr.c_str());
+                }
+                else
+                {
+                    _input_volume = volume;
+                }
+            }
+            else if (opt_name == "output-volume")
+            {
+                long long volume = Strings::tolong(opt_value);
+
+                if ( (volume < -10) || (volume > 10) )
+                {
+                    DBG(FUNC, PVT_FMT(_target, "[fxs-options] ouput-volume on branch %s.") % _fxs_orig_addr.c_str());
+                }
+                else
+                {
+                    _output_volume = volume;
+                }
+            }
+            else if (opt_name == "language")
+            {
+                _language = opt_value;
+            }
+            else if (opt_name == "mohclass")
+            {
+                _mohclass = opt_value;
+            }
+            else if (opt_name == "accountcode")
+            {
+                _accountcode = opt_value;
+            }
+            else if (opt_name == "calleridnum") // conscious ultra chuncho!
+            {
+                Opt::BranchToOptMapType::iterator it3 = Opt::_branch_options.find(_fxs_orig_addr);
+
+                if (it3 != Opt::_branch_options.end())
+                {
+                    Opt::_branch_options.insert(Opt::BranchToOptPairType(opt_value, it3->second));
+
+                    Opt::_branch_options.erase(it3);
+                }
+
+                _fxs_orig_addr = opt_value;
+            }
+            else if (opt_name == "calleridname")
+            {
+                _calleridname = opt_value;
+            }
+            else if (opt_name == "mailbox")
+            {
+                _mailbox = opt_value;
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(_target, "[fxs-options] invalid option on branch %s: \"%s\".") % _fxs_orig_addr.c_str() % opt_name.c_str());
+            }
+        }
+    }
+    catch (Strings::invalid_value e)
+    {
+        LOG(WARNING, PVT_FMT(_target, "[fxs-options] number expected on Khomp configuration file, got '%s'.") % e.value().c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool BoardE1::KhompPvtFXS::alloc()
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    callFXS()->_flags.set(Kflags::FXS_DIAL_FINISHD);
+
+    if(justStart(/*need_context*/) != SWITCH_STATUS_SUCCESS)
+    {
+        int fail_code = callFailFromCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+        setHangupCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+        cleanup(CLN_FAIL);
+        reportFailToReceive(fail_code);
+        LOG(ERROR, PVT_FMT(target(), "(FXS) r (Initilization Error on start!)"));
+        return false;
+    }
+
+    startListen();
+    startStream();
+
+    /* do this procedures early (as audio is already being heard) */
+    dtmfSuppression(Opt::_out_of_band_dtmfs && !callFXS()->_flags.check(Kflags::FAX_DETECTED));
+    echoCancellation(Opt::_echo_canceller && !callFXS()->_flags.check(Kflags::FAX_DETECTED));
+    autoGainControl(Opt::_auto_gain_control && !callFXS()->_flags.check(Kflags::FAX_DETECTED));
+
+    /* if it does not need context, probably it's a pickupcall and will
+       not pass throw setup_connection, so we start recording here*/
+    //if (!need_context && K::opt::recording && !pvt->is_recording)
+    //startRecord();
+
+    DBG(FUNC, "(FXS) r");
+    return true;
+}
+
+
+bool BoardE1::KhompPvtFXS::onSeizureStart(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+    
+        /* we always have audio */
+        call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+
+        ret = KhompPvt::onSeizureStart(e);
+
+        if (justAlloc(true) != SWITCH_STATUS_SUCCESS)
+        {
+            int fail_code = callFailFromCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
+            setHangupCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);            
+            cleanup(CLN_FAIL);
+            reportFailToReceive(fail_code);
+            LOG(ERROR,PVT_FMT(_target, "(FXS) r (Initilization Error on alloc!)"));
+            return false;
+        }
+
+        /* desabilita para evitar problemas de detecção de DTMF */
+        echoCancellation(false);
+        autoGainControl(false);
+
+        call()->_orig_addr = _fxs_orig_addr;
+
+        Opt::OrigToDestMapType::iterator i = Opt::_fxs_hotline.find(_fxs_orig_addr);
+
+        if (i != Opt::_fxs_hotline.end())
+        {
+            /* make it burn! */
+            call()->_dest_addr = (*i).second;
+            alloc();
+        }
+        else
+        {
+            /* normal line */
+            if (!_mailbox.empty() /*&& (ast_app_has_voicemail(pvt->fxs_opt.mailbox.c_str(), NULL) == 1)*/)
+                startCadence(PLAY_VM_TONE);
+            else
+                startCadence(PLAY_PBX_TONE);
+
+            call()->_flags.clear(Kflags::FXS_DIAL_ONGOING);
+            call()->_flags.set(Kflags::FXS_OFFHOOK);
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::onCallSuccess(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    bool ret;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onCallSuccess(e);
+
+        if (call()->_pre_answer)
+        {
+            dtmfSuppression(Opt::_out_of_band_dtmfs);     
+
+            startListen();
+            startStream();
+        }
+        else
+        {
+            call()->_flags.set(Kflags::GEN_PBX_RING);
+            call()->_idx_pbx_ring = Board::board(_target.device)->_timers.add(
+                    Opt::_ringback_pbx_delay,
+                    &Board::KhompPvt::pbxRingGen, 
+                    this, 
+                    TM_VAL_CALL);
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+void BoardE1::KhompPvtFXS::dialTimer(KhompPvt * pvt)
+{
+    DBG(FUNC, PVT_FMT(pvt->target(), "FXS Dial timer"));
+
+    try
+    {
+        ScopedPvtLock lock(pvt);
+    
+        KhompPvtFXS * pvt_fxs = static_cast<BoardE1::KhompPvtFXS*>(pvt);
+
+        if(!pvt_fxs->callFXS()->_flags.check(Kflags::FXS_DIAL_ONGOING) 
+            || pvt_fxs->callFXS()->_flags.check(Kflags::FXS_DIAL_FINISHD))
+            return;
+
+        pvt_fxs->call()->_dest_addr = pvt_fxs->callFXS()->_incoming_exten;
+        pvt_fxs->alloc();
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock %s!") % err._msg.c_str());
+    }
+
+}
+
+void BoardE1::KhompPvtFXS::transferTimer(KhompPvt * pvt)
+{
+    DBG(FUNC, PVT_FMT(pvt->target(), "c"));
+
+    try
+    {
+        ScopedPvtLock lock(pvt);
+
+        KhompPvtFXS * pvt_fxs = static_cast<BoardE1::KhompPvtFXS*>(pvt);
+
+        if(!pvt_fxs->callFXS()->_flags.check(Kflags::FXS_FLASH_TRANSFER))
+        {
+            DBG(FUNC, PVT_FMT(pvt->target(), "r (Flag not set)"));
+            return;
+        }
+
+        pvt_fxs->callFXS()->_flags.clear(Kflags::FXS_FLASH_TRANSFER);
+
+        if(pvt_fxs->callFXS()->_flash_transfer.empty())
+        {
+            DBG(FUNC, PVT_FMT(pvt->target(), "r (Number is empty)"));
+            
+            if(!pvt_fxs->stopTransfer())
+            {
+                pvt_fxs->cleanup(KhompPvt::CLN_HARD);
+                DBG(FUNC, PVT_FMT(pvt_fxs->target(), "r (unable to stop transfer)"));
+                return;
+            }
+
+            return;
+        }
+
+        /* begin context adjusting + processing */
+        ContextListType contexts;
+
+        pvt_fxs->validContexts(contexts);
+
+        std::string tmp_exten("s");
+        std::string tmp_context("default");
+
+        switch (pvt_fxs->findExtension(tmp_exten, tmp_context, contexts, pvt_fxs->callFXS()->_flash_transfer, pvt_fxs->call()->_orig_addr, false, false))
+        {
+            case MATCH_EXACT:
+            case MATCH_MORE:
+            {
+                DBG(FUNC,FMT("incoming exten matched: %s") % pvt_fxs->callFXS()->_flash_transfer);
+
+                if(!pvt_fxs->transfer(tmp_context))
+                {
+                    pvt_fxs->cleanup(KhompPvt::CLN_HARD);
+                    DBG(FUNC, PVT_FMT(pvt_fxs->target(), "r (unable to transfer)"));
+                    return;
+                }
+
+                break;
+            }
+            case MATCH_NONE:
+            {
+                DBG(FUNC, PVT_FMT(pvt_fxs->target(), "match none!"));
+                
+                if(!pvt_fxs->stopTransfer())
+                {
+                    pvt_fxs->cleanup(KhompPvt::CLN_HARD);
+                    DBG(FUNC, PVT_FMT(pvt_fxs->target(), "r (unable to stop transfer)"));
+                    return;
+                }
+
+                break;
+            }
+        }
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(pvt->target(), "r (unable to lock %s!)") % err._msg.c_str());
+        return;
+    }
+    
+    DBG(FUNC, PVT_FMT(pvt->target(), "r"));
+
+}
+
+bool BoardE1::KhompPvtFXS::onChannelRelease(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(!callFXS()->_uuid_other_session.empty() && session())
+        {
+            /*
+            switch_core_session_t *hold_session;
+
+            if ((hold_session = switch_core_session_locate(callFXS()->_uuid_other_session.c_str()))) 
+            {
+                switch_channel_t * hold = switch_core_session_get_channel(hold_session);
+                switch_channel_stop_broadcast(hold);
+                switch_channel_wait_for_flag(hold, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
+                switch_core_session_rwunlock(hold_session);
+            }
+            */
+            try
+            {
+                /* get other side of the bridge */
+                switch_core_session_t * peer_session = getFSLockedPartnerSession();
+                unlockPartner(peer_session);
+                DBG(FUNC, PVT_FMT(target(), "bridge with the new session"));
+                switch_ivr_uuid_bridge(getUUID(peer_session), callFXS()->_uuid_other_session.c_str());
+
+            }
+            catch(Board::KhompPvt::InvalidSwitchChannel & err)
+            {
+                DBG(FUNC, PVT_FMT(target(), "no partner: %s!") % err._msg.c_str());
+            }
+
+            callFXS()->_uuid_other_session.clear();
+        }
+
+        ret = KhompPvt::onChannelRelease(e);
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::startTransfer()
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    try
+    {
+        switch_core_session_t *peer_session = getFSLockedPartnerSession();
+        switch_channel_t *peer_channel = getFSChannel(peer_session);
+
+        const char *stream = NULL;
+
+        if (!(stream = getFSChannelVar(peer_channel, SWITCH_HOLD_MUSIC_VARIABLE)))
+        {
+            stream = "silence";
+        }
+        
+        unlockPartner(peer_session);
+
+        DBG(FUNC, PVT_FMT(target(), "stream=%s") % stream);
+
+        if (stream && strcasecmp(stream, "silence"))
+        {
+            // Freeswitch not get/put frames 
+            //switch_channel_set_flag(channel, CF_HOLD);
+            switch_ivr_broadcast(getUUID(peer_session), stream, SMF_ECHO_ALEG | SMF_LOOP);
+        }
+
+        callFXS()->_flags.set(Kflags::FXS_FLASH_TRANSFER);
+    
+        startCadence(PLAY_PBX_TONE);
+
+        callFXS()->_idx_transfer = Board::board(_target.device)->_timers.add(Opt::_fxs_digit_timeout * 1000, &BoardE1::KhompPvtFXS::transferTimer, this, TM_VAL_CALL);        
+
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        //cleanup(KhompPvt::CLN_HARD);
+        LOG(ERROR, PVT_FMT(target(), "r (no valid partner %s!)") % err._msg.c_str());
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to get device: %d!") % err.device);
+    }
+
+    //switch_ivr_hold_uuid(switch_core_session_get_uuid(session()), NULL, SWITCH_TRUE);
+    DBG(FUNC, PVT_FMT(target(), "r"));
+
+    return true;
+}
+
+bool BoardE1::KhompPvtFXS::stopTransfer()
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    callFXS()->_flags.clear(Kflags::FXS_FLASH_TRANSFER);
+    
+    callFXS()->_flash_transfer.clear();
+
+    stopCadence();
+
+    try
+    {
+        Board::board(_target.device)->_timers.del(callFXS()->_idx_transfer);
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to get device: %d!") % err.device);
+    }
+
+    try
+    {
+        /* get other side of the bridge */
+        switch_core_session_t * peer_session = getFSLockedPartnerSession();
+        switch_channel_t * peer_channel = getFSChannel(peer_session);
+
+        switch_channel_stop_broadcast(peer_channel);
+        switch_channel_wait_for_flag(peer_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
+
+        unlockPartner(peer_session);
+
+        //switch_ivr_unhold_uuid(switch_core_session_get_uuid(session()));
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (no valid partner %s!)") % err._msg.c_str());
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+    return true;
+}
+
+static switch_status_t xferHook(switch_core_session_t *session)
+{
+    switch_channel_t *channel = switch_core_session_get_channel(session);
+    switch_channel_state_t state = switch_channel_get_state(channel);
+
+    DBG(FUNC, D("state change=%d") % state);
+
+    if (state == CS_PARK) 
+    {
+        switch_core_event_hook_remove_state_change(session, xferHook);
+
+        BoardE1::KhompPvtFXS * pvt = static_cast<BoardE1::KhompPvtFXS*>(switch_core_session_get_private(session));
+        
+        if(!pvt)
+        {
+            DBG(FUNC, D("pvt is NULL"));
+            return SWITCH_STATUS_FALSE;
+        }
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            if(!pvt->callFXS()->_uuid_other_session.empty())
+            {
+                DBG(FUNC, D("bridge after park"));
+                std::string number = pvt->callFXS()->_uuid_other_session;
+                pvt->callFXS()->_uuid_other_session.clear();
+
+                switch_ivr_uuid_bridge(pvt->getUUID(), number.c_str());
+            }
+        }
+        catch(ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock: %s!") %  err._msg.c_str());            
+            return SWITCH_STATUS_FALSE;
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(), "%s!") %  err._msg.c_str());            
+            return SWITCH_STATUS_FALSE;
+        }
+
+    }
+    else if (state == CS_HANGUP) 
+    {
+        switch_core_event_hook_remove_state_change(session, xferHook);
+/*
+        BoardE1::KhompPvtFXS * pvt = static_cast<BoardE1::KhompPvtFXS*>(switch_core_session_get_private(session));
+        
+        if(!pvt)
+        {
+            DBG(FUNC, D("pvt is NULL"));
+            return SWITCH_STATUS_FALSE;
+        }
+
+        try
+        {
+            ScopedPvtLock lock(pvt);
+
+            if(!pvt->callFXS()->_uuid_other_session.empty())
+            {
+                DBG(FUNC, D("bridge after hangup"));
+                std::string number = pvt->callFXS()->_uuid_other_session;
+                pvt->callFXS()->_uuid_other_session.clear();
+
+                switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), number.c_str());
+            }
+        }
+        catch(ScopedLockFailed & err)
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(), "unable to lock: %s!") %  err._msg.c_str());            
+        }
+*/
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+bool BoardE1::KhompPvtFXS::transfer(std::string & context, bool blind)
+{
+    DBG(FUNC, PVT_FMT(target(), "c"));
+
+    callFXS()->_flags.clear(Kflags::FXS_FLASH_TRANSFER);
+
+    std::string number = callFXS()->_flash_transfer;
+    callFXS()->_flash_transfer.clear();
+
+    try
+    {
+        Board::board(_target.device)->_timers.del(callFXS()->_idx_transfer);
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "unable to get device: %d!") % err.device);
+    }
+
+    try
+    {
+        /* get other side of the bridge */
+        switch_core_session_t * peer_session = getFSLockedPartnerSession();
+        switch_channel_t * peer_channel = getFSChannel(peer_session);
+
+        switch_channel_stop_broadcast(peer_channel);
+        switch_channel_wait_for_flag(peer_channel, CF_BROADCAST, SWITCH_FALSE, 5000, NULL);
+
+        unlockPartner(peer_session);
+
+        if(blind)
+        {
+            DBG(FUNC, PVT_FMT(_target, "Blind Transfer"));
+            switch_ivr_session_transfer(peer_session, number.c_str(), "XML", context.c_str());
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(_target, "Attended Transfer"));
+
+            if(!callFXS()->_uuid_other_session.empty())
+            {
+                DBG(FUNC, PVT_FMT(target(), "second transfer, hang up session"));
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), "first transfer"));
+                callFXS()->_uuid_other_session = getUUID(peer_session);    
+                const char *stream = NULL;
+
+                if (!(stream = switch_channel_get_variable(peer_channel, SWITCH_HOLD_MUSIC_VARIABLE)))
+                {
+                    stream = "silence";
+                }
+
+                DBG(FUNC, PVT_FMT(target(), "transfer stream=%s") % stream);
+
+                if (stream && strcasecmp(stream, "silence"))
+                {
+                    std::string moh = STR(FMT("endless_playback:%s,park") % stream);
+                    switch_ivr_session_transfer(peer_session, moh.c_str(), "inline", NULL);
+                }
+                else
+                {
+                    switch_ivr_session_transfer(peer_session, "endless_playback:local_stream://moh,park", "inline", NULL);
+                    //switch_ivr_session_transfer(peer_session, "park", "inline", NULL);                
+                }
+            }
+
+            switch_channel_t * channel = getFSChannel();
+            switch_channel_set_variable(channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true");
+            switch_core_event_hook_add_state_change(session(), xferHook);
+
+            switch_ivr_session_transfer(session(), number.c_str(), "XML", context.c_str());
+
+            DBG(FUNC, PVT_FMT(target(), "Generating ring"));
+            call()->_indication = INDICA_RING;
+            call()->_flags.set(Kflags::GEN_CO_RING);
+            startCadence(PLAY_RINGBACK);
+
+            /*
+            try
+            {
+                call()->_idx_co_ring = Board::board(_target.device)->_timers.add(Opt::_ringback_co_delay, &Board::KhompPvt::coRingGen,this);
+            }
+            catch (K3LAPI::invalid_device & err)
+            {
+                LOG(ERROR, PVT_FMT(_target, "unable to get device: %d!") % err.device);
+            }
+            */
+        }
+    }
+    catch(Board::KhompPvt::InvalidSwitchChannel & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "r (no valid partner %s!)") % err._msg.c_str());
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(target(), "r"));
+
+    return true;
+}
+
+bool BoardE1::KhompPvtFXS::onDtmfDetected(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c (dtmf=%c)") % (char) e->AddInfo);
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if (call()->_flags.check(Kflags::IS_INCOMING) && 
+                callFXS()->_flags.check(Kflags::FXS_OFFHOOK) &&
+                !callFXS()->_flags.check(Kflags::FXS_DIAL_FINISHD))
+        {
+            DBG(FUNC, PVT_FMT(_target, "dialing"));
+
+            if (call()->_cadence == PLAY_PBX_TONE)
+            {
+                stopCadence();
+            }
+
+            if (call()->_cadence == PLAY_PUB_TONE)
+            {
+                stopCadence();
+                //call()->_cadence = PLAY_NONE;
+                //mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+            }
+
+            if (!callFXS()->_flags.check(Kflags::FXS_DIAL_ONGOING))
+            {
+                DBG(FUNC, PVT_FMT(_target, "dialing started now, clearing stuff.."));
+
+                callFXS()->_flags.set(Kflags::FXS_DIAL_ONGOING);
+
+                callFXS()->_incoming_exten.clear();
+
+                mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+
+                callFXS()->_idx_dial = Board::board(_target.device)->_timers.add(Opt::_fxs_digit_timeout * 1000, &BoardE1::KhompPvtFXS::dialTimer, this, TM_VAL_CALL);
+            }
+            else
+            {
+                Board::board(_target.device)->_timers.restart(callFXS()->_idx_dial);
+            }
+
+            callFXS()->_incoming_exten += e->AddInfo;
+
+            /* begin context adjusting + processing */
+            ContextListType contexts;
+
+            validContexts(contexts);
+
+            std::string tmp_exten("s");
+            std::string tmp_context("default");
+
+            switch (findExtension(tmp_exten, tmp_context, contexts, callFXS()->_incoming_exten, call()->_orig_addr, false, false))
+            {
+                case MATCH_EXACT:
+                    DBG(FUNC,FMT("incoming exten matched: %s") % callFXS()->_incoming_exten);
+                    Board::board(_target.device)->_timers.del(callFXS()->_idx_dial);
+                    call()->_dest_addr = callFXS()->_incoming_exten;
+                    call()->_incoming_context = tmp_context;
+
+                    alloc();
+                    break;
+
+                case MATCH_MORE:
+                    DBG(FUNC, PVT_FMT(target(), "match more..."));
+
+                    /* can match, will match more, and it's an external call? */
+                    for (Opt::DestVectorType::iterator i = Opt::_fxs_co_dialtone.begin(); i != Opt::_fxs_co_dialtone.end(); i++)
+                    {
+                        if (callFXS()->_incoming_exten == (*i))
+                        {
+                            startCadence(PLAY_PUB_TONE);
+                            break;
+                        }
+                    }
+
+                    break;
+                case MATCH_NONE:
+                    DBG(FUNC, PVT_FMT(target(), "match none!"));
+
+                    std::string invalid = "i";
+                    
+                    Board::board(_target.device)->_timers.del(callFXS()->_idx_dial);
+
+                    switch (findExtension(tmp_exten, tmp_context, contexts, invalid, call()->_orig_addr, true, false))
+                    {
+                        case MATCH_EXACT:
+                            // this dialing is invalid, and we can handle it...
+                            call()->_dest_addr = invalid;
+                            call()->_incoming_context = tmp_context;
+                            alloc();
+                            break;
+                        case MATCH_MORE:
+                        case MATCH_NONE:
+                            callFXS()->_flags.set(Kflags::FXS_DIAL_FINISHD);
+                            startCadence(PLAY_FASTBUSY);
+                            break;
+                    }
+                    break;
+            }
+        }
+        else if(callFXS()->_flags.check(Kflags::FXS_OFFHOOK) &&
+                callFXS()->_flags.check(Kflags::FXS_FLASH_TRANSFER))
+        {
+            Board::board(_target.device)->_timers.restart(callFXS()->_idx_transfer);
+            DBG(FUNC, PVT_FMT(target(), "Flash Transfer"));
+
+            if (call()->_cadence == PLAY_PBX_TONE)
+            {
+                stopCadence();
+            }
+
+            if (call()->_cadence == PLAY_PUB_TONE)
+            {
+                stopCadence();
+                //call()->_cadence = PLAY_NONE;
+                //mixer(KHOMP_LOG, 1, kmsGenerator, kmtSilence);
+            }
+
+            callFXS()->_flash_transfer += e->AddInfo;
+    
+            /* begin context adjusting + processing */
+            ContextListType contexts;
+
+            validContexts(contexts);
+
+            std::string tmp_exten("s");
+            std::string tmp_context("default");
+            
+            switch (findExtension(tmp_exten, tmp_context, contexts, callFXS()->_flash_transfer, call()->_orig_addr, false, false))
+            {
+                case MATCH_EXACT:
+                {
+                    DBG(FUNC,FMT("incoming exten matched: %s") % callFXS()->_flash_transfer);
+
+                    if(!transfer(tmp_context))
+                    {
+                        cleanup(KhompPvt::CLN_HARD);
+                        DBG(FUNC, PVT_FMT(target(), "(FXS) r (unable to transfer)"));
+                        return false;
+                    }
+
+                    break;
+                }
+                case MATCH_MORE:
+                    DBG(FUNC, PVT_FMT(target(), "match more..."));
+
+                    /* can match, will match more, and it's an external call? */
+                    for (Opt::DestVectorType::iterator i = Opt::_fxs_co_dialtone.begin(); i != Opt::_fxs_co_dialtone.end(); i++)
+                    {
+                        if (callFXS()->_flash_transfer == (*i))
+                        {
+                            startCadence(PLAY_PUB_TONE);
+                            break;
+                        }
+                    }
+
+                    break;
+                case MATCH_NONE:
+                {
+                    DBG(FUNC, PVT_FMT(target(), "match none!"));
+
+                    if(!stopTransfer())
+                    {
+                        cleanup(KhompPvt::CLN_HARD);
+                        DBG(FUNC, PVT_FMT(target(), "(FXS) r (unable to stop transfer)"));
+                        return false;
+                    }
+
+                    break;
+                }
+            }
+        }
+        else
+        {
+            ret = KhompPvt::onDtmfDetected(e);
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    catch (K3LAPI::invalid_device & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to get device: %d!)") % err.device);
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+/*
+bool BoardE1::KhompPvtFXS::onDtmfSendFinish(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        ret = KhompPvt::onDtmfSendFinish(e);
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+*/
+
+bool BoardE1::KhompPvtFXS::onFlashDetected(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        if(callFXS()->_flags.check(Kflags::FXS_FLASH_TRANSFER))
+        {
+            DBG(FUNC, PVT_FMT(_target, "(FXS) transfer canceled"));
+
+            if(!stopTransfer())
+            {
+                cleanup(KhompPvt::CLN_HARD);
+                DBG(FUNC, PVT_FMT(target(), "(FXS) r (unable to stop transfer)"));
+                return false;
+            }
+
+            DBG(FUNC, PVT_FMT(target(), "(FXS) r"));
+            return true;
+        }
+
+        if(call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "incoming call"));
+        }
+        else if(call()->_flags.check(Kflags::IS_OUTGOING))
+        {
+            DBG(FUNC, PVT_FMT(_target, "outgoing call"));
+        }
+        else
+        {
+            DBG(FUNC, PVT_FMT(_target, "(FXS) r (!incoming and !outgoing call)"));
+            return true;
+        }
+
+        echoCancellation(false);
+
+        if(!startTransfer())
+        {
+            DBG(FUNC, PVT_FMT(target(), "(FXS) r (unable to start transfer)"));
+            return false;
+        }
+
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return true;
+}
+
+int BoardE1::KhompPvtFXS::makeCall(std::string params)
+{
+    DBG(FUNC,PVT_FMT(_target, "(FXS) c"));
+
+    /* we always have audio */
+    call()->_flags.set(Kflags::HAS_PRE_AUDIO);
+    
+    if (Opt::_fxs_bina && !call()->_orig_addr.empty())
+    {
+        /* Sending Bina DTMF*/
+        callFXS()->_flags.set(Kflags::WAIT_SEND_DTMF);
+
+        std::stringstream dial_bina;
+
+        dial_bina << "A1" << call()->_orig_addr << "C";
+
+        if (!command(KHOMP_LOG, CM_DIAL_DTMF, dial_bina.str().c_str()))
+        {
+            return ksFail;
+            //throw call_error("something went while sending BINA digits to FXS branch");
+        }
+
+        int timeout = 150;
+
+        if(!loopWhileFlagTimed(Kflags::WAIT_SEND_DTMF, timeout))
+            return ksFail;
+        //throw call_error("call has been dropped while sending digits");
+
+        if(timeout <= 0)
+            return ksFail;
+        //throw call_error("sending number of A caused timeout of this call");
+    }
+
+    if(!call()->_orig_addr.empty())
+        params += STG(FMT(" orig_addr=\"%s\"") % _call->_orig_addr);
+
+    if (callFXS()->_ring_on != -1)
+        params += STG(FMT(" ring_on=\"%ld\"") % callFXS()->_ring_on);
+
+    if (callFXS()->_ring_off != -1)
+        params += STG(FMT(" ring_off=\"%ld\"") % callFXS()->_ring_off);
+
+    if (callFXS()->_ring_on_ext != -1)
+        params += STG(FMT(" ring_on_ext=\"%ld\"") % callFXS()->_ring_on_ext);
+
+    if (callFXS()->_ring_off_ext != -1)
+        params += STG(FMT(" ring_off_ext=\"%ld\"") % callFXS()->_ring_off_ext);
+
+    int ret = KhompPvt::makeCall(params);
+
+    if(ret == ksSuccess)
+    {
+        try
+        {
+            switch_channel_mark_ring_ready(getFSChannel());
+        //signal_state(AST_CONTROL_RINGING);
+        }
+        catch(Board::KhompPvt::InvalidSwitchChannel & err)
+        {
+            LOG(ERROR, PVT_FMT(_target, "No valid channel: %s") % err._msg.c_str());
+        }
+    }
+    else
+    {
+        LOG(ERROR, PVT_FMT(target(), "Fail on make call"));
+    }
+
+    call()->_cleanup_upon_hangup = (ret == ksInvalidParams || ret == ksInvalidState);
+
+    DBG(FUNC,PVT_FMT(_target, "(FXS) r"));
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::doChannelAnswer(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+    
+    bool ret = true;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        setupConnection();
+
+        ret = KhompPvt::doChannelAnswer(cmd);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::doChannelHangup(CommandRequest &cmd)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+    
+    bool ret = true;
+
+    bool answered     = true;
+    bool disconnected = false;
+
+    try
+    {
+        ScopedPvtLock lock(this);
+        
+        if(!callFXS()->_uuid_other_session.empty())
+        {
+            DBG(FUNC,PVT_FMT(_target, "unable to transfer"));
+            
+            switch_core_session_t *hold_session;
+
+            if ((hold_session = switch_core_session_locate(callFXS()->_uuid_other_session.c_str()))) 
+            {
+                switch_channel_t *hold_channel = switch_core_session_get_channel(hold_session);
+                switch_core_session_rwunlock(hold_session);
+
+                if(hold_channel)
+                    switch_channel_hangup(hold_channel, (switch_call_cause_t)call()->_hangup_cause);
+                //switch_channel_hangup(hold_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+            }
+            callFXS()->_uuid_other_session.clear();            
+        }
+
+        if (call()->_flags.check(Kflags::IS_INCOMING))
+        {
+            DBG(FUNC,PVT_FMT(_target, "disconnecting incoming channel"));
+
+        }
+        else if (call()->_flags.check(Kflags::IS_OUTGOING))
+        {
+            if (!call()->_flags.check(Kflags::FXS_OFFHOOK))
+            {
+                DBG(FUNC, PVT_FMT(_target, "disconnecting not answered outgoing FXS channel..."));
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+                cleanup(KhompPvt::CLN_HARD);
+                answered = false;
+
+            }
+            else if(call()->_cleanup_upon_hangup)
+            {
+                DBG(FUNC,PVT_FMT(_target, "disconnecting not allocated outgoing channel..."));
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+                cleanup(KhompPvt::CLN_HARD);
+                answered = false;
+
+            }
+            else
+            {
+                DBG(FUNC,PVT_FMT(_target, "disconnecting outgoing channel...")); 
+
+                disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+            }
+        }
+        else
+        {
+            DBG(FUNC,PVT_FMT(_target, "already disconnected"));
+            return true;
+        }
+
+        if(answered)
+        {
+            indicateBusyUnlocked(SWITCH_CAUSE_USER_BUSY, disconnected);
+        }
+
+        if (call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::NEEDS_RINGBACK_CMD))
+        {
+            DBG(FUNC,PVT_FMT(_target, "disconnecting incoming channel..."));
+            disconnected = command(KHOMP_LOG, CM_DISCONNECT);
+        }
+
+        stopStream();
+
+        stopListen();
+
+        //ret = KhompPvt::doChannelHangup(cmd);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR,PVT_FMT(_target, "(FXS) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::setupConnection()
+{
+    if(!call()->_flags.check(Kflags::IS_INCOMING) && !call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        DBG(FUNC,PVT_FMT(_target, "Channel already disconnected"));
+        return false;
+    }
+
+    bool res_out_of_band_dtmf = (call()->_var_dtmf_state == T_UNKNOWN ?
+        Opt::_suppression_delay && Opt::_out_of_band_dtmfs : (call()->_var_dtmf_state == T_TRUE));
+
+    bool res_echo_cancellator = (call()->_var_echo_state == T_UNKNOWN ?
+        Opt::_echo_canceller : (call()->_var_echo_state == T_TRUE));
+
+
+    bool res_auto_gain_cntrol = (call()->_var_gain_state == T_UNKNOWN ?
+        Opt::_auto_gain_control : (call()->_var_gain_state == T_TRUE));
+
+
+    if (!call()->_flags.check(Kflags::REALLY_CONNECTED))
+    {
+        obtainRX(res_out_of_band_dtmf);
+
+        /* esvazia buffers de leitura/escrita */
+        cleanupBuffers();
+
+        if (!call()->_flags.check(Kflags::KEEP_DTMF_SUPPRESSION))
+            dtmfSuppression(res_out_of_band_dtmf);
+
+        if (!call()->_flags.check(Kflags::KEEP_ECHO_CANCELLATION))
+            echoCancellation(res_echo_cancellator);
+
+        if (!call()->_flags.check(Kflags::KEEP_AUTO_GAIN_CONTROL))
+            autoGainControl(res_auto_gain_cntrol);
+
+        startListen(false);
+
+        startStream();
+
+        DBG(FUNC, PVT_FMT(_target, "(FXS) Audio callbacks initialized successfully"));
+    }
+
+    call()->_flags.set(Kflags::FXS_OFFHOOK);
+
+    return KhompPvt::setupConnection();
+}
+
+bool BoardE1::KhompPvtFXS::indicateBusyUnlocked(int cause, bool sent_signaling)
+{
+    DBG(FUNC, PVT_FMT(_target, "(FXS) c"));
+
+    if(!KhompPvt::indicateBusyUnlocked(cause, sent_signaling))
+    {
+        DBG(FUNC, PVT_FMT(_target, "(FXS) r (false)"));
+        return false;
+    }
+
+    if(call()->_flags.check(Kflags::IS_INCOMING))
+    {
+        if(!call()->_flags.check(Kflags::CONNECTED) && !sent_signaling)
+        {
+            if(!call()->_flags.check(Kflags::HAS_PRE_AUDIO))
+            {
+                int rb_value = callFailFromCause(call()->_hangup_cause);
+                DBG(FUNC, PVT_FMT(target(), "sending the busy status"));
+
+                if (sendRingBackStatus(rb_value) == RingbackDefs::RBST_UNSUPPORTED)
+                {
+                    DBG(FUNC, PVT_FMT(target(), "falling back to audio indication!"));
+                    /* stop the line audio */
+                    stopStream();
+
+                    /* just pre connect, no ringback */
+                    if (!sendPreAudio())
+                        DBG(FUNC, PVT_FMT(target(), "everything else failed, just sending audio indication..."));
+
+                    /* be very specific about the situation. */
+                    mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+                }
+            }
+            else
+            {
+                DBG(FUNC, PVT_FMT(target(), "going to play busy"));
+
+                /* stop the line audio */
+                stopStream();
+
+                /* be very specific about the situation. */
+                mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+
+            }
+        }
+        else
+        {
+            /* already connected or sent signaling... */
+            mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+        }
+
+    }
+    else if(call()->_flags.check(Kflags::IS_OUTGOING))
+    {
+        /* already connected or sent signaling... */
+        mixer(KHOMP_LOG, 1, kmsGenerator, kmtBusy);
+    }
+
+    DBG(FUNC,PVT_FMT(_target, "(FXS) r"));
+
+    return true;
+}
+
+void BoardE1::KhompPvtFXS::reportFailToReceive(int fail_code)
+{
+    KhompPvt::reportFailToReceive(fail_code);
+
+    if(fail_code != -1)
+    {
+        DBG(FUNC,PVT_FMT(_target, "sending a 'unknown number' message/audio")); 
+
+        if(sendRingBackStatus(fail_code) == RingbackDefs::RBST_UNSUPPORTED)
+        {
+            sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+            startCadence(PLAY_FASTBUSY);
+        }
+    }
+    else
+    {
+        DBG(FUNC, PVT_FMT(_target, "sending fast busy audio directly"));
+
+        sendPreAudio(RingbackDefs::RB_SEND_DEFAULT);
+        startCadence(PLAY_FASTBUSY);
+    }
+}
+
+bool BoardE1::KhompPvtFXS::validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context)
+{
+    DBG(FUNC,PVT_FMT(_target, "(FXS) c"));
+    
+    if(!_context.empty())
+        contexts.push_back(_context);
+
+    contexts.push_back(Opt::_context_fxs);
+    contexts.push_back(Opt::_context2_fxs);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++)
+    {
+        replaceTemplate((*i), "CC", _target.object);
+    }
+
+    bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
+
+    DBG(FUNC,PVT_FMT(_target, "(FXS) r"));
+
+    return ret;
+}
+
+bool BoardE1::KhompPvtFXS::isOK()
+{
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        K3L_CHANNEL_STATUS status;
+
+        if (k3lGetDeviceStatus (_target.device, _target.object + ksoChannel, &status, sizeof (status)) != ksSuccess)
+            return false;
+
+        return (status.AddInfo != kfxsFail);
+    }
+    catch (ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "unable to lock %s!") % err._msg.c_str() );
+    }
+
+    return false;
+}
+
+
diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt_passive.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt_passive.cpp
new file mode 100644 (file)
index 0000000..01c1610
--- /dev/null
@@ -0,0 +1,288 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "khomp_pvt_passive.h"
+#include "lock.h"
+#include "logger.h"
+
+bool BoardPassive::KhompPvtPassive::validContexts(Board::KhompPvt::ContextListType & contexts, std::string extra_context)
+{
+    DBG(FUNC,PVT_FMT(_target,"(Passive) c"));
+
+    contexts.push_back(Opt::_context_pr);
+
+    for (Board::KhompPvt::ContextListType::iterator i = contexts.begin(); i != contexts.end(); i++)
+    {
+        replaceTemplate((*i), "CC", _target.object);
+    }
+
+    bool ret = Board::KhompPvt::validContexts(contexts,extra_context);
+
+    DBG(FUNC,PVT_FMT(_target,"(Passive) r"));
+
+    return ret;
+}
+
+bool BoardPassive::KhompPvtHI::onSeizureStart(K3L_EVENT *e)
+{
+    DBG(FUNC,PVT_FMT(_target,"(HI) c"));
+   
+    try
+    {
+        ScopedPvtLock lock(this);
+
+        _call->_orig_addr.clear();
+        _call->_dest_addr = "s";
+
+#if SWITCH_LESS_THAN(1,0,6)
+        session(switch_core_session_request(Globals::khomp_pr_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL));
+#else
+        session(switch_core_session_request(Globals::khomp_pr_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL));
+#endif
+
+        if (justAlloc(true) != SWITCH_STATUS_SUCCESS)
+        {
+            setHangupCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
+            cleanup(CLN_FAIL);
+            LOG(ERROR, PVT_FMT(target(), "(HI) r (Initilization Error on alloc!)"));
+            return false;
+        }
+
+        /* begin context adjusting + processing */
+        ContextListType contexts;
+
+        validContexts(contexts);
+
+        std::string tmp_exten;
+        std::string tmp_context;
+
+        switch (findExtension(tmp_exten, tmp_context, contexts, call()->_dest_addr, call()->_orig_addr, false))
+        {
+        case MATCH_NONE:
+            destroy();
+            owner(NULL);
+            LOG(WARNING, PVT_FMT(_target, "(HI) r (unable to find exten/context on incoming call %s/%s)")
+                    % _call->_dest_addr % (contexts.size() >= 1 ? contexts[0] : "default"));
+            return false;
+        default:
+            DBG(FUNC, PVT_FMT(_target, "(HI) our: context '%s', exten '%s'") % tmp_context % tmp_exten);
+            break;
+
+        }
+
+        call()->_incoming_context = tmp_context;
+
+        startListen();
+
+        if (justStart() != SWITCH_STATUS_SUCCESS)
+        {
+            setHangupCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+            cleanup(CLN_FAIL);
+            LOG(ERROR, PVT_FMT(target(), "(HI) r (Initilization Error on start!)"));
+            return false;
+        }
+
+        call()->_flags.set(Kflags::REALLY_CONNECTED);
+        call()->statistics()->incrementNewCall();
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(HI) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+
+    DBG(FUNC, PVT_FMT(_target, "(HI) r"));
+
+    return true;
+}
+
+bool BoardPassive::KhompPvtKPR::onNewCall(K3L_EVENT *e)
+{
+    DBG(FUNC, PVT_FMT(_target, "(KPR) c"));
+
+    try
+    {
+        std::string orig_addr, dest_addr;
+
+        Globals::k3lapi.get_param(e, "orig_addr", orig_addr);
+        Globals::k3lapi.get_param(e, "dest_addr", dest_addr);
+        
+        if(dest_addr.empty())
+        {
+            dest_addr="s";
+        }
+
+        bool isdn_reverse_charge = false;        
+        std::string isdn_reverse_charge_str;
+        int isdn_status = Globals::k3lapi.get_param(e, "isdn_reverse_charge", isdn_reverse_charge_str);        
+
+        if (isdn_status == ksSuccess && !isdn_reverse_charge_str.empty())
+        {
+            try
+            {
+                isdn_reverse_charge = Strings::toboolean(isdn_reverse_charge_str);
+            }
+            catch (Strings::invalid_value & err)
+            {
+            }
+        }
+
+        long int r2_category = -1;
+        std::string r2_categ_a;
+        int r2_status = Globals::k3lapi.get_param(e, "r2_categ_a", r2_categ_a);
+
+        if (r2_status == ksSuccess && !r2_categ_a.empty())
+        {
+            try
+            {
+                r2_category = Strings::toulong(r2_categ_a);
+            }
+            catch (Strings::invalid_value e)
+            {
+            }
+
+        }
+
+        ScopedPvtLock lock(this);
+
+        _call->_orig_addr = orig_addr;
+        _call->_dest_addr = dest_addr;
+
+        if(isdn_reverse_charge || r2_category == kg2CollectCall)
+        {
+            call()->_collect_call = true;            
+        }
+
+#if SWITCH_LESS_THAN(1,0,6)
+        session(switch_core_session_request(Globals::khomp_pr_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL));
+#else
+        session(switch_core_session_request(Globals::khomp_pr_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, SOF_NONE, NULL));
+#endif
+
+        if (justAlloc(true) != SWITCH_STATUS_SUCCESS)
+        {
+            setHangupCause(SWITCH_CAUSE_UNALLOCATED_NUMBER);
+            cleanup(CLN_FAIL);
+            LOG(ERROR, PVT_FMT(target(), "(KPR) r (Initilization Error on alloc!)"));
+            return false;
+        }
+
+        /* begin context adjusting + processing */
+        ContextListType contexts;
+
+        validContexts(contexts);
+
+        std::string tmp_exten;
+        std::string tmp_context;
+
+        switch (findExtension(tmp_exten, tmp_context, contexts, call()->_dest_addr, call()->_orig_addr, false))
+        {
+            case MATCH_NONE:
+                destroy();
+                owner(NULL);
+                LOG(WARNING, PVT_FMT(_target, "(KPR) r (unable to find exten/context on incoming call %s/%s)")
+                        % _call->_dest_addr % (contexts.size() >= 1 ? contexts[0] : "default"));
+                return false;
+            default:
+                DBG(FUNC, PVT_FMT(_target, "(KPR) our: context '%s', exten '%s'") % tmp_context % tmp_exten);
+                break;
+
+        }
+
+        call()->_incoming_context = tmp_context;
+        _call->_dest_addr = tmp_exten;
+
+        obtainBoth();
+
+        startListen(false);
+
+        if (justStart() != SWITCH_STATUS_SUCCESS)
+        {
+            setHangupCause(SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
+            cleanup(CLN_FAIL);
+            LOG(ERROR, PVT_FMT(target(), "(KPR) r (Initilization Error on start!)"));
+            return false;
+        }
+
+        call()->_flags.set(Kflags::REALLY_CONNECTED);
+        call()->statistics()->incrementNewCall();
+
+    }
+    catch(ScopedLockFailed & err)
+    {
+        LOG(ERROR, PVT_FMT(target(), "(KPR) r (unable to lock %s!)") % err._msg.c_str() );
+        return false;
+    }
+    
+    DBG(FUNC, PVT_FMT(_target, "(KPR) r"));   
+    return true;
+}
+
+bool BoardPassive::KhompPvtKPR::obtainBoth()
+{
+    /* estes buffers *NAO PODEM SER ESTATICOS*! */
+    char cmd1[] = { 0x3f, 0x03, 0xff, 0x00, 0x05, 0xff };
+    char cmd2[] = { 0x3f, 0x03, 0xff, 0x01, 0x05, 0xff };
+
+    cmd1[2] = cmd1[5] = cmd2[2] = _target.object;
+    cmd2[5] = _target.object + 30;
+
+    try
+    {
+        int dsp = Globals::k3lapi.get_dsp(_target.device, K3LAPI::DSP_AUDIO);
+
+        Globals::k3lapi.raw_command(_target.device, dsp, cmd1, sizeof(cmd1));
+
+        Globals::k3lapi.raw_command(_target.device, dsp, cmd2, sizeof(cmd2));
+
+    }
+    catch(K3LAPI::failed_raw_command & e)
+    {
+        LOG(ERROR, PVT_FMT(target(), "ERROR sending mixer command!"));
+        return false;
+    }
+
+    return true;
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/lock.cpp b/src/mod/endpoints/mod_khomp/src/lock.cpp
new file mode 100644 (file)
index 0000000..01d1689
--- /dev/null
@@ -0,0 +1,138 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "lock.h"
+
+/* ScopedPvtLock */
+
+ScopedPvtLock::ScopedPvtLock(KhompPvt * pvt)
+: ScopedLockBasic(false), _pvt(pvt)
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+
+    if (! _pvt)
+        throw ScopedLockFailed(ScopedLockFailed::NULL_PVT, "null KhompPvt");
+
+    switch(_pvt->_mutex.lock())
+    {
+        case SimpleLock::FAILURE:
+            throw ScopedLockFailed(ScopedLockFailed::FAILED, "Failure");
+            break;
+        case SimpleLock::ISINUSE:
+            throw ScopedLockFailed(ScopedLockFailed::FAILED, "In use");
+            break;
+        default:
+            break;
+    }
+
+    _locked = true;
+
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
+ScopedPvtLock::~ScopedPvtLock()
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+    unlock();
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
+void ScopedPvtLock::unlock()
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+
+    if (_locked)
+    {
+        //DBG(LOCK, DP(_pvt, "unlocking!"));
+
+        _locked = false;
+        _pvt->_mutex.unlock();
+    }
+
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
+ScopedAllocLock::ScopedAllocLock()
+: ScopedLockBasic(false)
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+
+    switch(Globals::khomp_alloc_mutex.lock())
+    {
+        case SimpleLock::FAILURE:
+            throw ScopedLockFailed(ScopedLockFailed::ALLOC_FAILED, "Failure");
+            break;
+        case SimpleLock::ISINUSE:
+            throw ScopedLockFailed(ScopedLockFailed::ALLOC_FAILED, "In use");
+            break;
+        default:
+            break;
+    }
+
+    _locked = true;
+
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
+ScopedAllocLock::~ScopedAllocLock()
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+    unlock();
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
+void ScopedAllocLock::unlock()
+{
+    //DBG(LOCK, DP(_pvt, "c"));
+
+    if (_locked)
+    {
+        //DBG(LOCK, DP(_pvt, "unlocking!"));
+
+        _locked = false;
+        Globals::khomp_alloc_mutex.unlock();
+    }
+
+    //DBG(LOCK, DP(_pvt, "r"));
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/logger.cpp b/src/mod/endpoints/mod_khomp/src/logger.cpp
new file mode 100644 (file)
index 0000000..c68518a
--- /dev/null
@@ -0,0 +1,437 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "logger.h"
+#include "globals.h"
+
+namespace K
+{
+    LogManager Logger::Logg;
+    LogInternalManager Logger::Logg2;
+
+    std::string     Logger::base_path;
+    std::ofstream   Logger::generic_file;
+
+    bool LogConfig::set(Logfile & file, const char * section, const char * option, bool value)
+    {
+        Section * sec = file.root().section_find(section);
+
+        if (!sec)
+            return false;
+
+        Option * opt = sec->option_find(option);
+
+        if (!opt)
+            return false;
+
+        opt->set( value ? "Ativado" : "Desativado" );
+
+        return true;
+    }
+
+    bool LogConfig::commit(Logfile & file)
+    {
+        return file.provide();
+    }
+        
+    bool Logger::start()
+    {
+        /* we love shortcuts! */
+        typedef LogManager::Option LogOpt; 
+
+        typedef LogOpt::Flags     Flags;
+        typedef LogOpt::InitFlags FL;  
+
+        /* configures default log levels */
+        Logger::Logg.classe(C_ERROR)
+            & LogOpt(O_CONSOLE, "ERROR: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::ENABLED)))
+            & LogOpt(O_GENERIC, "E: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_WARNING)
+            & LogOpt(O_CONSOLE, "WARNING: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::ENABLED)))
+            & LogOpt(O_GENERIC, "W: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_MESSAGE)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::ENABLED)))
+            & LogOpt(O_GENERIC, "M: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        /* k3l messages */
+        Logger::Logg.classe(C_COMMAND)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME)))
+            & LogOpt(O_GENERIC, "c: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID)));
+
+        Logger::Logg.classe(C_EVENT)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME)))
+            & LogOpt(O_GENERIC, "e: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID)));
+
+        Logger::Logg.classe(C_AUDIO_EV)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME)))
+            & LogOpt(O_GENERIC, "a: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID)));
+
+        Logger::Logg.classe(C_MODEM_EV)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME)))
+            & LogOpt(O_GENERIC, "m: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_LINK_STT)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME) & FL(LogOpt::ENABLED)))
+            & LogOpt(O_GENERIC, "s: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_CAS_MSGS)
+            & LogOpt(O_CONSOLE, Flags(FL(LogOpt::DATETIME) & FL(LogOpt::ENABLED)))
+            & LogOpt(O_GENERIC, "p: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        /* channel debug */
+        Logger::Logg.classe(C_DBG_FUNC)
+            & LogOpt(O_GENERIC, "F: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_DBG_LOCK)
+            & LogOpt(O_GENERIC, "L: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_DBG_THRD)
+            & LogOpt(O_GENERIC, "T: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_DBG_STRM)
+            & LogOpt(O_GENERIC, "S: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_DBG_CONF)
+            & LogOpt(O_GENERIC, "C: ", Flags(FL(LogOpt::DATETIME) & FL(LogOpt::THREADID) & FL(LogOpt::ENABLED)));
+
+        Logger::Logg.classe(C_DBG_FUNC).enabled(false);
+        Logger::Logg.classe(C_DBG_LOCK).enabled(false);
+        Logger::Logg.classe(C_DBG_THRD).enabled(false);
+        Logger::Logg.classe(C_DBG_STRM).enabled(false);
+
+        /* we debug config file loading, by default */
+        Logger::Logg.classe(C_DBG_CONF).enabled(true);
+
+        /* adds a prefix to the cli messages */
+        Logger::Logg.classe(C_CLI).prefix("<K> ");
+
+        /* inserts default console log before opening files */
+        Logger::Logg.add(O_CONSOLE,SwitchConsoleLog(), "mod_khomp: ");
+
+        time_t      tv;
+        struct tm   lt;
+
+        /* get local time! */
+        time (&tv);
+        localtime_r (&tv, &lt);
+
+        base_path = STG(FMT("/var/log/khomp%d.%d/mod_khomp-%04d%02d%02d_%02d%02d%02d/")
+                % k3lApiMajorVersion % k3lApiMinorVersion % (lt.tm_year + 1900) % (lt.tm_mon + 1)
+                % lt.tm_mday % lt.tm_hour % lt.tm_min % lt.tm_sec );
+
+        // NOTE: ALWAYS unlink, as we may have a dangling symlink lying around...
+        std::string link_path = STG(FMT("/var/log/khomp%d.%d/current") % k3lApiMajorVersion % k3lApiMinorVersion );
+        unlink(link_path.c_str());
+
+        if (mkdir(base_path.c_str(), 493 /*755*/) < 0 && errno != EEXIST)
+        {
+            Logger::Logg(C_ERROR, D("unable to create log directory '%s': %s!") % base_path % strerror(errno));
+            return false;
+        }
+
+        if (symlink(base_path.c_str(), link_path.c_str()))
+        {
+            Logger::Logg(C_ERROR, D("unable to create symlink to latest log directory '%s': %s!") % base_path % strerror(errno));
+        }
+
+        std::string gen_tmp = base_path + std::string("generic.log");
+        generic_file.open(gen_tmp.c_str());
+
+        if (!generic_file.good())
+        {
+            Logger::Logg(C_ERROR, D("could not open file '%s': %s") % gen_tmp % strerror(errno));
+            return false;
+        }
+
+        /* inserts other file descriptors (TODO: delete this when stopping logs) */
+        Logger::Logg.add(O_GENERIC, &generic_file);
+        return true;
+    }
+
+    void Logger::stop()
+    {
+        if(generic_file.is_open())
+        {
+            generic_file.close();
+        }
+    }
+
+    bool Logger::rotate()
+    {
+        std::string new_gen;
+
+        for (unsigned int i = 0;; i++)
+        {   
+            std::string tmp = base_path + STG(FMT("generic.%d.log") % i); 
+
+            if (access(tmp.c_str(), R_OK|W_OK) != 0 && errno == ENOENT)
+            {   
+                new_gen = tmp;
+                break;
+            }   
+        }   
+
+        std::string old_gen = base_path + "generic.log";
+
+        if (rename(old_gen.c_str(), new_gen.c_str()) != 0)
+        {   
+            Logger::Logg(C_ERROR, FMT("unable to move generic log file: %s.") % strerror(errno));
+            return false;
+        }   
+
+        Globals::logs_being_rotated = true;
+
+        generic_file.close();
+        generic_file.open(old_gen.c_str());
+
+        Globals::logs_being_rotated = false;
+
+        return true;
+    }
+
+    void Logger::processLogConsole(switch_stream_handle_t *s, const std::string options, bool invert, bool unique)
+    {
+        class_type classe = ( !s ? C_MESSAGE : C_CLI );
+
+        Strings::vector_type tokens;
+        Strings::tokenize(options, tokens, ",");
+
+        bool flag_errors   = false;
+        bool flag_warnings = false;
+        bool flag_messages = false;
+        bool flag_events   = false;
+        bool flag_commands = false;
+        bool flag_audio    = false;
+        bool flag_modem    = false;
+        bool flag_link     = false;
+        bool flag_cas      = false;
+
+        Strings::Merger strs;
+
+        for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++) 
+        {    
+            std::string tok = Strings::trim(*i);
+
+            /**/ if ((tok) == "errors")     flag_errors   = true;
+            else if ((tok) == "warnings")   flag_warnings = true;
+            else if ((tok) == "messages")   flag_messages = true;
+            else if ((tok) == "events")     flag_events   = true;
+            else if ((tok) == "commands")   flag_commands = true;
+            else if ((tok) == "audio")      flag_audio    = true;
+            else if ((tok) == "modem")      flag_modem    = true;
+            else if ((tok) == "link")       flag_link     = true;
+            else if ((tok) == "cas")        flag_cas      = true;
+            else if ((tok) == "standard")
+            {    
+                flag_errors   = true;
+                flag_warnings = true;
+                flag_messages = true;
+                flag_link     = true;
+            }    
+            else if ((tok) == "all")
+            {    
+                flag_errors   = true;
+                flag_warnings = true;
+                flag_messages = true;
+                flag_events   = true;
+                flag_commands = true;
+                flag_audio    = true;
+                flag_modem    = true;
+                flag_link     = true;
+                flag_cas      = true;
+            }    
+            else 
+            {    
+                K::Logger::Logg2(classe, s, FMT("WARNING: The following console message option is not valid and will be ignored: %s.") % (tok) );
+                continue;
+            }    
+
+            strs.add(tok);
+        }
+
+        if ((unique && !flag_errors)    || flag_errors)    K::Logger::Logg.classe(C_ERROR)   .set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_errors));
+        if ((unique && !flag_warnings)  || flag_warnings)  K::Logger::Logg.classe(C_WARNING) .set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_warnings));
+        if ((unique && !flag_messages)  || flag_messages)  K::Logger::Logg.classe(C_MESSAGE) .set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_messages));
+        if ((unique && !flag_events)    || flag_events)    K::Logger::Logg.classe(C_EVENT)   .set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_events));
+        if ((unique && !flag_commands)  || flag_commands)  K::Logger::Logg.classe(C_COMMAND) .set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_commands));
+        if ((unique && !flag_audio)     || flag_audio)     K::Logger::Logg.classe(C_AUDIO_EV).set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_audio));
+        if ((unique && !flag_modem)     || flag_modem)     K::Logger::Logg.classe(C_MODEM_EV).set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_modem));
+        if ((unique && !flag_link)      || flag_link)      K::Logger::Logg.classe(C_LINK_STT).set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_link));
+        if ((unique && !flag_cas)       || flag_cas)       K::Logger::Logg.classe(C_CAS_MSGS).set(O_CONSOLE, LogManager::Option::ENABLED, (!invert && flag_cas));
+
+        if (!strs.empty())
+        {
+            K::Logger::Logg2(classe, s, FMT("NOTICE: %s %sthe following console messages: %s.")
+                    % (invert ? "Disabling" : "Enabling")
+                    % (unique ? "just " : "") % strs.merge(", "));
+        }
+        else
+        {
+            K::Logger::Logg2(classe, s, "WARNING: No valid console messages have been specified, doing nothing.");
+        }
+    }
+
+    void Logger::processLogDisk(switch_stream_handle_t *s, const std::string options, bool invert, bool unique)
+    {
+        class_type classe = ( !s ? C_MESSAGE : C_CLI );
+
+        Strings::vector_type tokens;
+        Strings::tokenize(options, tokens, ",");
+
+        bool flag_errors    = false;
+        bool flag_warnings  = false;
+        bool flag_messages  = false;
+        bool flag_events    = false;
+        bool flag_commands  = false;
+        bool flag_audio     = false;
+        bool flag_modem     = false;
+        bool flag_link      = false;
+        bool flag_cas       = false;
+        bool flag_functions = false;
+        bool flag_threads   = false;
+        bool flag_locks     = false;
+        bool flag_streams   = false;
+
+        Strings::Merger strs;
+        
+        for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++) 
+        {    
+            std::string tok = Strings::trim(*i);
+
+            /**/ if ((tok) == "errors")     flag_errors    = true;
+            else if ((tok) == "warnings")   flag_warnings  = true;
+            else if ((tok) == "messages")   flag_messages  = true;
+            else if ((tok) == "events")     flag_events    = true;
+            else if ((tok) == "commands")   flag_commands  = true;
+            else if ((tok) == "audio")      flag_audio     = true;
+            else if ((tok) == "modem")      flag_modem     = true;
+            else if ((tok) == "link")       flag_link      = true;
+            else if ((tok) == "cas")        flag_cas       = true;
+            else if ((tok) == "functions")  flag_functions = true;
+            else if ((tok) == "threads")    flag_threads   = true;
+            else if ((tok) == "locks")      flag_locks     = true;
+            else if ((tok) == "streams")    flag_streams   = true;
+            else if ((tok) == "standard")
+            {    
+                flag_errors   = true;
+                flag_warnings = true;
+                flag_messages = true;
+                flag_link     = true;
+            }    
+            else if ((tok) == "debugging")
+            {    
+                flag_errors    = true;
+                flag_warnings  = true;
+                flag_messages  = true;
+                flag_commands  = true;
+                flag_events    = true;
+                flag_audio     = true;
+                flag_modem     = true;
+                flag_link      = true;
+                flag_cas       = true;
+                flag_functions = true;
+            }    
+            else if ((tok) == "all")
+            {    
+                flag_errors    = true;
+                flag_warnings  = true;
+                flag_messages  = true;
+                flag_events    = true;
+                flag_commands  = true;
+                flag_audio     = true;
+                flag_modem     = true;
+                flag_link      = true;
+                flag_cas       = true;
+                flag_functions = true;
+                flag_threads   = true;
+                flag_locks     = true;
+                flag_streams   = true;
+            }
+            else
+            {
+                /* do not show! */
+                continue;
+            }
+
+            strs.add(tok);
+        }
+
+        if ((unique && !flag_errors)    || flag_errors)    K::Logger::Logg.classe(C_ERROR)   .set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_errors));
+        if ((unique && !flag_warnings)  || flag_warnings)  K::Logger::Logg.classe(C_WARNING) .set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_warnings));
+        if ((unique && !flag_messages)  || flag_messages)  K::Logger::Logg.classe(C_MESSAGE) .set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_messages));
+        if ((unique && !flag_events)    || flag_events)    K::Logger::Logg.classe(C_EVENT)   .set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_events));
+        if ((unique && !flag_commands)  || flag_commands)  K::Logger::Logg.classe(C_COMMAND) .set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_commands));
+        if ((unique && !flag_audio)     || flag_audio)     K::Logger::Logg.classe(C_AUDIO_EV).set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_audio));
+        if ((unique && !flag_modem)     || flag_modem)     K::Logger::Logg.classe(C_MODEM_EV).set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_modem));
+        if ((unique && !flag_link)      || flag_link)      K::Logger::Logg.classe(C_LINK_STT).set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_link));
+        if ((unique && !flag_cas)       || flag_cas)       K::Logger::Logg.classe(C_CAS_MSGS).set(O_GENERIC, LogManager::Option::ENABLED, (!invert && flag_cas));
+        if ((unique && !flag_functions) || flag_functions) K::Logger::Logg.classe(C_DBG_FUNC).enabled(!invert && flag_functions);
+        if ((unique && !flag_threads)   || flag_threads)   K::Logger::Logg.classe(C_DBG_THRD).enabled(!invert && flag_threads);
+        if ((unique && !flag_locks)     || flag_locks)     K::Logger::Logg.classe(C_DBG_LOCK).enabled(!invert && flag_locks);
+        if ((unique && !flag_streams)   || flag_streams)   K::Logger::Logg.classe(C_DBG_STRM).enabled(!invert && flag_streams);
+
+        if (!strs.empty())
+        {
+            K::Logger::Logg2(classe, s, FMT("NOTICE: %s %sthe logging of the following messages: %s.")
+                    % (invert ? "Disabling" : "Enabling")
+                    % (unique ? "just " : "") % strs.merge(", "));
+
+            if ((flag_streams || flag_locks) && !invert)
+            {
+                K::Logger::Logg2(classe, s, "WARNING: You have enabled *INTENSIVE* debug messages for the Khomp channel!");
+                K::Logger::Logg2(classe, s, "WARNING: Don't *EVER* use these options on production systems, unless you *REALLY* know what you are doing!");
+            }
+            else if ((flag_functions || flag_threads) && !invert)
+            {
+                K::Logger::Logg2(classe, s, "WARNING: You have enabled some debug messages for the Khomp channel.");
+                K::Logger::Logg2(classe, s, "WARNING: Do not use these options on production systems unless you really know what you are doing!");
+            }
+        }
+        else
+        {
+            K::Logger::Logg2(classe, s, "WARNING: No valid log messages have been specified, doing nothing.");
+        }
+    }
+}
diff --git a/src/mod/endpoints/mod_khomp/src/opt.cpp b/src/mod/endpoints/mod_khomp/src/opt.cpp
new file mode 100644 (file)
index 0000000..946f508
--- /dev/null
@@ -0,0 +1,772 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include "opt.h"
+#include "globals.h"
+#include "defs.h"
+#include "logger.h"
+#include "spec.h"
+
+bool                            Opt::_debug;
+std::string                     Opt::_dialplan;
+std::string                     Opt::_context;
+std::string                     Opt::_user_xfer;
+std::map < std::string, CSpan > Opt::_spans;
+Opt::GroupToDestMapType         Opt::_groups;
+Opt::CadencesMapType            Opt::_cadences;
+
+bool Opt::_echo_canceller;
+bool Opt::_auto_gain_control;
+bool Opt::_out_of_band_dtmfs;
+bool Opt::_suppression_delay;
+bool Opt::_pulse_forwarding;
+bool Opt::_native_bridge;
+bool Opt::_recording;
+bool Opt::_has_ctbus;
+bool Opt::_fxs_bina;
+bool Opt::_fxo_send_pre_audio;
+bool Opt::_drop_collect_call;
+bool Opt::_ignore_letter_dtmfs;
+bool Opt::_optimize_audio_path;
+
+bool         Opt::_auto_fax_adjustment;
+unsigned int Opt::_fax_adjustment_timeout;
+
+bool         Opt::_r2_strict_behaviour;
+unsigned int Opt::_r2_preconnect_wait;
+
+unsigned int Opt::_fxs_digit_timeout;
+
+unsigned int Opt::_transferdigittimeout;
+
+std::string Opt::_atxfer;
+std::string Opt::_blindxfer;
+
+unsigned int Opt::_ringback_co_delay;
+unsigned int Opt::_ringback_pbx_delay;
+
+unsigned int Opt::_disconnect_delay;
+
+int Opt::_input_volume;
+int Opt::_output_volume;
+
+Opt::DestVectorType     Opt::_fxs_co_dialtone;
+Opt::OrigToDestMapType  Opt::_fxs_hotline;
+std::string             Opt::_fxs_global_orig_base;
+
+Opt::BoardToOrigMapType    Opt::_fxs_orig_base;
+Opt::BranchToObjectMapType Opt::_fxs_branch_map;
+Opt::BranchToOptMapType    Opt::_branch_options;
+
+std::string Opt::_global_mohclass;
+std::string Opt::_global_language;
+
+std::string Opt::_record_prefix;
+
+std::string Opt::_context_gsm_call;
+std::string Opt::_context2_gsm_call;
+std::string Opt::_context_gsm_sms;
+std::string Opt::_context_fxo;
+std::string Opt::_context2_fxo;
+std::string Opt::_context_fxs;
+std::string Opt::_context2_fxs;
+std::string Opt::_context_digital;
+std::string Opt::_context_pr;
+
+int Opt::_amaflags;
+std::string Opt::_callgroup;
+std::string Opt::_pickupgroup;
+
+std::string Opt::_accountcode;
+
+unsigned int Opt::_kommuter_timeout;
+std::string  Opt::_kommuter_activation;
+
+unsigned int Opt::_audio_packet_size;
+
+void Opt::initialize(void) 
+{ 
+    Globals::options.add(ConfigOption("debug",    _debug,    false));
+    Globals::options.add(ConfigOption("dialplan", _dialplan, "XML"));
+    Globals::options.add(ConfigOption("context",  _context,  "default"));
+
+       Globals::options.add(ConfigOption("echo-canceller",       _echo_canceller,       true));
+       Globals::options.add(ConfigOption("auto-gain-control",    _auto_gain_control,    true));
+       Globals::options.add(ConfigOption("out-of-band-dtmfs",    _out_of_band_dtmfs,    true));
+       Globals::options.add(ConfigOption("suppression-delay",    _suppression_delay,    true));
+       Globals::options.add(ConfigOption("pulse-forwarding",     _pulse_forwarding,     false));
+       Globals::options.add(ConfigOption("native-bridge",        _native_bridge,        true));
+       Globals::options.add(ConfigOption("recording",            _recording,            true));
+       Globals::options.add(ConfigOption("has-ctbus",            _has_ctbus,            false));
+       Globals::options.add(ConfigOption("fxs-bina",             _fxs_bina,             true));
+       Globals::options.add(ConfigOption("fxo-send-pre-audio",   _fxo_send_pre_audio,   true));
+       Globals::options.add(ConfigOption("drop-collect-call",    _drop_collect_call,    false));
+       Globals::options.add(ConfigOption("ignore-letter-dtmfs", _ignore_letter_dtmfs,  false));
+       Globals::options.add(ConfigOption("optimize-audio-path",  _optimize_audio_path,  false));
+
+    Globals::options.add(ConfigOption("auto-fax-adjustment",    _auto_fax_adjustment,    true));
+    Globals::options.add(ConfigOption("fax-adjustment-timeout", _fax_adjustment_timeout, 30u, 3u, 9999u));
+
+    Globals::options.add(ConfigOption("r2-strict-behaviour", _r2_strict_behaviour, false));
+    Globals::options.add(ConfigOption("r2-preconnect-wait",  _r2_preconnect_wait,  250u, 25u, 500u));
+
+    Globals::options.add(ConfigOption("fxs-digit-timeout",   _fxs_digit_timeout,   7u,  1u, 30u));
+
+    Globals::options.add(ConfigOption("transferdigittimeout", _transferdigittimeout, 3000u, 0u, 90000u));
+
+    Globals::options.add(ConfigOption("atxfer", _atxfer, ""));
+    Globals::options.add(ConfigOption("blindxfer", _blindxfer, ""));
+
+    Globals::options.add(ConfigOption("delay-ringback-co",  _ringback_co_delay,  1500u, 0u, 999000u)); 
+    Globals::options.add(ConfigOption("delay-ringback-pbx", _ringback_pbx_delay, 2500u, 0u, 999000u));
+    
+    Globals::options.add(ConfigOption("disconnect-delay", _disconnect_delay, 0u, 0u, 100000u)); 
+
+    Globals::options.add(ConfigOption("input-volume",  _input_volume, 0, -10, 10));
+    Globals::options.add(ConfigOption("output-volume", _output_volume, 0, -10, 10));
+
+
+    Globals::options.add(ConfigOption("fxs-co-dialtone", ProcessFXSCODialtone(), ""));
+    Globals::options.add(ConfigOption("fxs-global-orig", _fxs_global_orig_base,  "0"));
+
+    Globals::options.add(ConfigOption("language", _global_language, ""));
+    Globals::options.add(ConfigOption("mohclass", _global_mohclass, ""));
+
+    Globals::options.add(ConfigOption("record-prefix", ProcessRecordPrefix(), "/var/spool/freeswitch/monitor/"));
+
+    Globals::options.add(ConfigOption("context-fxo",          _context_fxo,       "khomp-DD-CC"));
+    Globals::options.add(ConfigOption("context-fxo-alt",      _context2_fxo,      "khomp-DD"));
+    Globals::options.add(ConfigOption("context-fxs",          _context_fxs,       "khomp-DD-CC"));
+    Globals::options.add(ConfigOption("context-fxs-alt",      _context2_fxs,      "khomp-DD"));
+    Globals::options.add(ConfigOption("context-gsm-call",     _context_gsm_call,  "khomp-DD-CC"));
+    Globals::options.add(ConfigOption("context-gsm-call-alt", _context2_gsm_call, "khomp-DD"));
+    Globals::options.add(ConfigOption("context-gsm-sms",      _context_gsm_sms,   "khomp-sms-DD-CC"));
+    Globals::options.add(ConfigOption("context-digital",      _context_digital,   "khomp-DD-LL"));
+    Globals::options.add(ConfigOption("context-pr",           _context_pr,        "khomp-DD-CC"));
+
+    Globals::options.add(ConfigOption("amaflags",    ProcessAMAFlags(),    "default"));
+    Globals::options.add(ConfigOption("callgroup",   _callgroup,   "0"));
+    Globals::options.add(ConfigOption("pickupgroup", _pickupgroup, "0"));
+    //Globals::options.add(ConfigOption("callgroup",   ProcessCallGroup(),   "0"));
+    //Globals::options.add(ConfigOption("pickupgroup", ProcessPickupGroup(), "0"));
+
+    Globals::options.add(ConfigOption("accountcode", _accountcode, ""));
+
+    ConfigOption::string_allowed_type kommuter_allowed;
+    kommuter_allowed.insert("auto");
+    kommuter_allowed.insert("manual");
+
+    Globals::options.add(ConfigOption("kommuter-activation", _kommuter_activation , "auto", kommuter_allowed));
+    Globals::options.add(ConfigOption("kommuter-timeout",    _kommuter_timeout ,(unsigned int) 10 , (unsigned int) 0 , (unsigned int) 255));
+
+    Globals::options.add(ConfigOption("audio-packet-length", _audio_packet_size,
+         (unsigned int)KHOMP_READ_PACKET_SIZE, (unsigned int)KHOMP_MIN_READ_PACKET_SIZE, (unsigned int)KHOMP_MAX_READ_PACKET_SIZE, 8u));
+
+    Globals::options.add(ConfigOption("log-to-disk",    ProcessLogOptions(O_GENERIC), "standard", false));
+    Globals::options.add(ConfigOption("log-to-console", ProcessLogOptions(O_CONSOLE), "standard", false));
+
+    Globals::options.add(ConfigOption("trace",          ProcessTraceOptions(), "", false));
+    Globals::options.add(ConfigOption("user-transfer-digits", _user_xfer, ""));
+
+    /* aliases */
+    Globals::options.synonym("context-gsm", "context-gsm-call");
+    Globals::options.synonym("context-gsm-alt", "context-gsm-call-alt");
+    Globals::options.synonym("echocanceller", "echo-canceller");
+    Globals::options.synonym("dtmfsuppression", "out-of-band-dtmfs");
+    Globals::options.synonym("dtmfsupression", "out-of-band-dtmfs");
+    Globals::options.synonym("pulsedetection", "pulse-forwarding");
+    Globals::options.synonym("r2preconnectwait", "r2-preconnect-wait");
+    Globals::options.synonym("bridge", "native-bridge");
+    Globals::options.synonym("suppressiondelay", "suppression-delay");
+    Globals::options.synonym("log", "log-to-disk");
+    Globals::options.synonym("volume", "output-volume");
+    Globals::options.synonym("disconnectdelay", "disconnect-delay");
+
+}
+
+void Opt::obtain(void)
+{
+    /* everything should start clean! */
+    cleanConfiguration();        
+
+    /* reset loaded options */
+    Globals::options.reset();
+
+    loadConfiguration("khomp.conf", NULL);
+
+    /* commit, loading defaults where needed */
+    ConfigOptions::messages_type msgs = Globals::options.commit();
+
+    /* config already full loaded at this point, so we can use our own log system... */
+    for (ConfigOptions::messages_type::iterator i = msgs.begin(); i != msgs.end(); i++)
+    {
+        DBG(FUNC,FMT("%s") % (*i).c_str());
+    }
+}
+
+void Opt::commit(void)
+{
+    processGroupString();
+
+    /* Check FXS hotlines correcteness */
+    OrigToDestMapType::const_iterator endOfHotlines = _fxs_hotline.end();
+
+    for (OrigToDestMapType::const_iterator i = _fxs_hotline.begin(); i != endOfHotlines; i++)
+    {  
+        BranchToObjectMapType::const_iterator j = _fxs_branch_map.find(i->first);
+
+        if (j == _fxs_branch_map.end())
+        {   
+            LOG(ERROR, FMT("unable to find branch '%s': hotline '%s' to '%s' is invalid!")
+                % i->first % i->first % i->second);
+        } 
+    }   
+
+    /* Check FXS options correcteness */
+    BranchToOptMapType::const_iterator endOfOptions = _branch_options.end();
+        
+    for (BranchToOptMapType::const_iterator i = _branch_options.begin(); i != endOfOptions; i++)
+    {   
+        BranchToObjectMapType::const_iterator j = _fxs_branch_map.find(i->first);        
+        if (j == _fxs_branch_map.end())
+        {   
+            LOG(ERROR, FMT("unable to find branch '%s' for options '%s'")
+                % i->first % i->second);
+        } 
+    }   
+}
+
+void Opt::loadConfiguration(const char *file_name, const char **section, bool show_errors)
+{
+    switch_xml_t cfg, xml, settings;
+
+    if (!(xml = switch_xml_open_cfg(file_name, &cfg, NULL))) {
+        LOG(ERROR,FMT("Open of %s failed") % file_name);
+        return;
+    }
+
+    /* Load all the global settings pertinent to all boards */
+    settings = processSimpleXML(cfg,"settings");
+    
+    /* Process channel settings */
+    processSimpleXML(settings,"channels");
+
+    /* Process groups settings */
+    processGroupXML(settings);
+
+    /* Process cadence settings */
+    processCadenceXML(settings);
+
+    /* Process fxs branches settings */
+    processFXSBranchesXML(settings);
+
+    /* Process hotlines settings */
+    processFXSHotlines(settings);
+
+    /* Process fxs options settings */
+    processFXSOptions(settings);
+    
+    switch_xml_free(xml);
+}
+
+void Opt::printConfiguration(switch_stream_handle_t* stream)
+{
+    for( std::map<std::string, CSpan>::iterator ii=_spans.begin(); ii!=_spans.end(); ++ii )
+    {
+        stream->write_function(stream,
+                               "Span: %s.\nDialplan: %s.\nContext: %s.\nDialstring: %s.\n\n",
+                               (*ii).first.c_str(),
+                               (*ii).second._dialplan.c_str(),
+                               (*ii).second._context.c_str(),
+                               (*ii).second._dialstring.c_str());
+    }
+}
+
+void Opt::cleanConfiguration(void)
+{
+    _fxs_orig_base.clear();
+    _fxs_hotline.clear();
+    _fxs_co_dialtone.clear();
+    _fxs_branch_map.clear();
+    _branch_options.clear();
+
+    _groups.clear();
+    _cadences.clear();
+
+    _cadences.insert(CadencesPairType("fast-busy", CadenceType(100,100)));
+    _cadences.insert(CadencesPairType("ringback", CadenceType(1000,4000)));
+    _cadences.insert(CadencesPairType("pbx-dialtone", CadenceType(1000,100)));
+    _cadences.insert(CadencesPairType("co-dialtone", CadenceType(0,0)));
+    _cadences.insert(CadencesPairType("vm-dialtone", CadenceType(1000,100,100,100)));
+}
+
+void Opt::ProcessFXSCODialtone::operator()(std::string options) // const
+{
+    Strings::vector_type tokens;
+    Strings::tokenize(options, tokens, ",");
+
+    for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++)
+        _fxs_co_dialtone.push_back(*i);
+}
+
+void Opt::ProcessRecordPrefix::operator()(std::string path) // const
+{
+    if (mkdir(path.c_str(), 493 /* 0755 */) < 0 && errno != EEXIST)
+    {
+        throw ConfigProcessFailure("the default recording directory could not be created.");
+    }
+    else
+    {
+        _record_prefix = path;
+    }
+}
+
+void Opt::ProcessAMAFlags::operator()(std::string options)
+{
+/*
+    //TODO: Do we need this ?
+    amaflags = ast_cdr_amaflags2int(options.c_str());
+
+    if (amaflags < 0)
+        throw ConfigProcessFailure(STG(FMT("invalid AMA flags: %s") % options));
+*/
+}
+
+//TODO: Check this
+void Opt::ProcessCallGroup::operator()(std::string options)
+{
+//    _callgroup = options.c_str();
+}
+
+//TODO: Check this
+void Opt::ProcessPickupGroup::operator()(std::string options)
+{
+//    _pickupgroup = options.c_str();
+}
+
+void Opt::ProcessLogOptions::operator()(std::string options)
+{
+    switch (_output)
+    {   
+        case O_GENERIC:
+            K::Logger::processLogDisk(NULL, options, false, true);
+            break;
+
+        case O_CONSOLE:
+            K::Logger::processLogConsole(NULL, options, false, true);
+            break;
+
+        default:
+            throw ConfigProcessFailure("attempt to process unknown log file configuration");
+            break;
+    }   
+}
+
+void Opt::ProcessTraceOptions::operator()(std::string options)
+{
+    Strings::vector_type tokens;
+    Strings::tokenize(options, tokens, ",");
+
+    bool         enable_k3l_tracing  = false;
+    bool         enable_r2_tracing   = false;
+    bool         enable_rdsi_tracing = false;
+
+    for (Strings::vector_type::iterator i = tokens.begin(); i != tokens.end(); i++)
+    {
+        std::string tok = Strings::trim(*i);
+
+        if (tok == "k3l")
+        {
+            enable_k3l_tracing = true;
+        }
+        else if (tok == "r2")
+        {
+            enable_r2_tracing = true;
+        }
+        else if (tok == "rdsi")
+        {
+            enable_rdsi_tracing = true;
+        }
+    }
+
+    Logfile logfile;
+
+    /* k3l tracing */
+    if (enable_k3l_tracing)
+    {
+        K::LogConfig::set(logfile, "K3L", "Value",        enable_k3l_tracing);
+        K::LogConfig::set(logfile, "K3L", "CallProgress", enable_k3l_tracing);
+        K::LogConfig::set(logfile, "K3L", "CallAnalyzer", enable_k3l_tracing);
+        K::LogConfig::set(logfile, "K3L", "CadenceRecog", enable_k3l_tracing);
+        K::LogConfig::set(logfile, "K3L", "CallControl",  enable_k3l_tracing);
+        K::LogConfig::set(logfile, "K3L", "Fax",          enable_k3l_tracing);
+    }
+
+    /* r2 tracing */
+    K::LogConfig::set(logfile, "R2", "Value",     enable_r2_tracing);
+    K::LogConfig::set(logfile, "R2", "Signaling", enable_r2_tracing);
+    K::LogConfig::set(logfile, "R2", "States",    enable_r2_tracing);
+
+    /* ISDN tracing */
+    if (enable_rdsi_tracing ^ Globals::flag_trace_rdsi)
+    {
+        K::LogConfig::set(logfile, "ISDN", "Value", enable_rdsi_tracing);
+        K::LogConfig::set(logfile, "ISDN", "Lapd",  enable_rdsi_tracing);
+        K::LogConfig::set(logfile, "ISDN", "Q931",  enable_rdsi_tracing);
+    }
+
+    try
+    {
+        Globals::k3lapi.command(-1, -1, CM_LOG_UPDATE);
+    }
+    catch(...)
+    {
+        LOG(ERROR,"Error while send command CM_LOG_UPDATE");
+    }
+}
+
+switch_xml_t Opt::processSimpleXML(switch_xml_t &xml, const std::string& child_name)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml, child_name.c_str())))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+            try
+            {
+                DBG(FUNC,FMT("loading '%s' options: '%s'...")
+                    % var
+                    % val);
+
+                Globals::options.process(var, val);
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);
+
+            }
+        }
+    }
+
+    return child;
+}
+
+void Opt::processGroupXML(switch_xml_t &xml)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml,"groups")))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+            try
+            {
+                DBG(FUNC,FMT("loading group '%s' options: '%s'...")
+                    % var
+                    % val);
+
+                _groups.insert(GroupToDestPairType(var,val));
+
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);
+            }
+        }
+    }
+}
+
+void Opt::processCadenceXML(switch_xml_t &xml)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml,"cadences")))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+            try
+            {
+                DBG(FUNC,FMT("loading cadences '%s' options: '%s'...")
+                    % var
+                    % val);
+
+                Strings::vector_type values;
+                Strings::tokenize(val, values, " :,.");
+
+                if (values.size() != 2 && values.size() != 4)
+                {
+                    LOG(WARNING, FMT("file '%s': wrong number of arguments at cadence '%s'!")
+                        % "khomp.conf.xml"
+                        % var);
+                }
+                else
+                {
+                    CadenceType cadence;
+
+                    cadence.ring       = Strings::toulong(Strings::trim(values[0]));
+                    cadence.ring_s     = Strings::toulong(Strings::trim(values[1]));
+
+                    if (values.size() == 4)
+                    {   
+                        cadence.ring_ext   = Strings::toulong(Strings::trim(values[2]));
+                        cadence.ring_ext_s = Strings::toulong(Strings::trim(values[3]));
+                    }   
+
+                    _cadences.erase(var); /* erases previous (possibly predefined) cadence */
+                    _cadences.insert(CadencesPairType(var, cadence));
+                } 
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);
+
+            }                  
+            catch (Strings::invalid_value e)
+            {   
+               LOG(ERROR,FMT("file '%s': number expected at cadence '%s', got '%s'.") 
+                    % "khomp.conf.xml"
+                    % var
+                    % e.value().c_str());
+            }   
+        }
+    }
+}
+
+void Opt::processFXSBranchesXML(switch_xml_t &xml)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml,"fxs-branches")))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+
+            DBG(FUNC,FMT("loading fxs-branches '%s' options: '%s'...")
+                    % var
+                    % val);
+
+            try
+            {
+                unsigned long orig_number = Strings::toulong(var);
+
+                /* gcc! stop complaining! */
+                (void)orig_number;
+
+                Strings::vector_type boards;
+                Strings::tokenize(val, boards, " :,");
+
+                if (boards.size() < 1)
+                {
+                    DBG(FUNC,FMT("file '%s': orig number '%s' without any board!")
+                        % "khomp.conf.xml"
+                        % var);
+                    continue;
+                }
+
+                for (Strings::vector_type::iterator iter = boards.begin(); iter != boards.end(); iter++)
+                {
+                    /* quebrar em strings por vírgula/espaço */
+                    unsigned long serial_number = Strings::toulong(Strings::trim(*iter));
+
+                    bool found = false;
+
+                    for (unsigned int device = 0; device < Globals::k3lapi.device_count(); device++)
+                    {
+                        K3L_DEVICE_CONFIG & conf = Globals::k3lapi.device_config(device);
+
+                        std::string str_serial(conf.SerialNumber);
+
+                        if (Strings::toulong(str_serial) == serial_number)
+                        {
+                            found = true;
+
+                            _fxs_orig_base.insert(BoardToOrigPairType(device, var));
+                            break;
+                        }
+                    }
+
+                    if (!found)
+                    {
+                        LOG(WARNING, FMT("file 'khomp.conf.xml': board with serial number '%u' not found!") 
+                        % serial_number);
+
+                        break;
+                    }
+                }
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);
+            }
+            catch (Strings::invalid_value & e)
+            {
+                LOG(ERROR, D("invalid numeric value: %s") % e.value());
+            }
+            catch (...)
+            {
+                LOG(ERROR, D("config processing error..."));
+            }
+        }
+    }
+}
+
+void Opt::processFXSHotlines(switch_xml_t &xml)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml,"fxs-hotlines")))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+            try
+            {
+                DBG(FUNC,FMT("loading fxs-hotlines '%s' options: '%s'...")
+                    % var
+                    % val);
+
+                unsigned long orig_number = Strings::toulong(var);
+
+                (void)orig_number; /* stop complaining! */
+
+                _fxs_hotline.insert(OrigToDestPairType(var, val));
+
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);        
+            }
+            catch (Strings::invalid_value e)
+            {
+                LOG(WARNING, FMT("file '%s': number expected, got '%s'!") 
+                    % "khomp.conf.xml" % e.value().c_str());
+            }  
+        }
+    }
+}
+
+void Opt::processFXSOptions(switch_xml_t &xml)
+{
+    switch_xml_t param, child;
+
+    if ((child = switch_xml_child(xml,"fxs-options")))
+    {
+        for (param = switch_xml_child(child, "param"); param; param = param->next)
+        {
+            char *var = (char *) switch_xml_attr_soft(param, "name");
+            char *val = (char *) switch_xml_attr_soft(param, "value");
+
+            try
+            {
+                DBG(FUNC,FMT("loading fxs-options '%s' options: '%s'...")
+                    % var
+                    % val);
+
+                Strings::vector_type branches;
+                Strings::tokenize(var, branches, " ,");
+
+                if (branches.size() < 1)
+                {   
+                    //TODO: Get linenumber
+                    LOG(WARNING, FMT("file '%s': no branches specified in line %d!") 
+                    % "khomp.conf.xml" % 0);
+                }           
+                else
+                {   
+                    for (Strings::vector_type::iterator iter = branches.begin();
+                            iter != branches.end(); iter++)
+                    {                   
+                        std::string tmp_branch = Strings::trim(*iter);
+
+                        unsigned long branch_number = Strings::toulong(tmp_branch);
+                        (void) branch_number;
+
+                        _branch_options.insert(BranchToOptPairType(tmp_branch, val));
+                    }
+                }
+            }
+            catch (ConfigProcessFailure e)
+            {
+                LOG(ERROR,FMT("config processing error: %s. [%s=%s]")  
+                    % e.msg.c_str()
+                    % var
+                    % val);      
+            }
+            catch (Strings::invalid_value e)
+            {
+                LOG(WARNING, FMT("file '%s': number expected, got '%s'!") 
+                    % "khomp.conf.xml" % e.value().c_str());
+            }
+        }
+    }
+}
diff --git a/src/mod/endpoints/mod_khomp/src/spec.cpp b/src/mod/endpoints/mod_khomp/src/spec.cpp
new file mode 100644 (file)
index 0000000..5af0263
--- /dev/null
@@ -0,0 +1,885 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include <regex.hpp>
+#include "spec.h"
+#include "logger.h"
+#include "khomp_pvt.h"
+#include "khomp_pvt_kxe1.h"
+
+/************************** Forward declaration *******************************/
+static SpecRetType processSpecAtom(std::string &, SpecFlagsType &, SpecFunType &);
+static SpecRetType processSpecAtoms(std::string &, SpecFlagsType &, SpecFunType &);
+
+static bool processCallChannelString(std::string &, Board::KhompPvt *&, int *, bool need_free = true);
+
+/******************************************************************************/
+
+static SpecRetType processSpecAtom(std::string & atom, SpecFlagsType & flags, SpecFunType & fun)
+{
+       std::string allocstr = Strings::trim(atom);
+
+       DBG(FUNC, D("allocation string 'atom': %s") % allocstr.c_str());
+
+    /* check if is a group */
+       if (allocstr.size() >= 1 && (allocstr[0] == 'g' || allocstr[0] == 'G'))
+    {
+               std::string group_name = allocstr.substr(1);
+
+               Opt::GroupToDestMapType::iterator it = Opt::_groups.find(group_name);
+
+               if (it == Opt::_groups.end())
+               {
+                       LOG(ERROR, FMT("invalid dial string '%s': no valid group found!") % allocstr.c_str());
+               return SPR_FAIL;
+               }
+
+               allocstr = it->second;
+               return processSpecAtoms(allocstr, flags, fun);
+    }
+
+    Regex::Expression e("(((([bB])[ ]*([0-9]+))|(([sS])[ ]*([0-9]+)))[ ]*(([cClL])[ ]*([0-9]+)[ ]*([-][ ]*([0-9]+))?)?)|(([rR])[ ]*([0-9]+)[ ]*([-][ ]*([0-9]+))?)", Regex::E_EXTENDED);
+
+       Regex::Match what(allocstr, e);
+
+       if (!what.matched())
+       {
+               LOG(ERROR, FMT("invalid dial string '%s': this is not a valid expression.") % allocstr.c_str());
+               return SPR_FAIL;
+       }
+
+       bool reverse = true;
+
+       try
+       {
+
+               unsigned long int board_id = UINT_MAX;
+
+               if (what.matched(3)) //matched [bB]
+               {
+                       board_id = Strings::toulong(what.submatch(5));
+
+                       DBG(FUNC, D("board matched: %d") % board_id);
+
+
+                       if (board_id >= Globals::k3lapi.device_count())
+                       {
+               LOG(ERROR, FMT("invalid dial string '%s': no such board '%d'.") % allocstr.c_str() % board_id);
+                               return SPR_FAIL;
+                       }
+
+                       switch ((what.submatch(4))[0])
+                       {
+                               case 'b': reverse = false; break;
+                               case 'B': reverse = true;  break;
+                       }
+               }
+
+               else if (what.matched(6)) //matched [sS]
+               {
+                       unsigned int serial_id = Strings::toulong(what.submatch(8));
+
+                       DBG(FUNC, D("serial matched: %d") % serial_id);
+
+                       for (unsigned int i = 0; i < Globals::k3lapi.device_count(); i++)
+                       {
+
+                               K3L_DEVICE_CONFIG conf = Globals::k3lapi.device_config(i);
+
+                               unsigned int tmp = Strings::toulong((const char *)conf.SerialNumber);
+
+                               if (tmp == serial_id)
+                               {
+                                       board_id = i;
+                                       break;
+                               }
+                       }
+
+                       if (board_id == UINT_MAX)
+                       {
+                       LOG(ERROR, FMT("invalid dial string '%s': there is no board with serial '%04d'.") % allocstr.c_str() % serial_id);
+                               return SPR_FAIL;
+                       }
+
+                       switch ((what.submatch(7))[0])
+                       {
+                               case 's': reverse = false; break;
+                               case 'S': reverse = true;  break;
+                       }
+               }
+               else if (what.matched(14)) //matched [rR]
+               {
+                       std::string base_addr = what.submatch(16);
+
+                       unsigned int branch_id = Strings::toulong(base_addr);
+
+                       if (what.matched(17))
+                       {
+                               unsigned int branch2_id = Strings::toulong(what.submatch(18));
+
+                               DBG(FUNC, D("branch range matched (%d to %d)") % branch_id % branch2_id);
+
+                               switch ((what.submatch(15))[0])
+                               {
+                                       case 'r': reverse = false; break;
+                                       case 'R': reverse = true;  break;
+                               }
+
+                               if (!reverse)
+                               {
+                                       for (unsigned int i = branch_id; i <= branch2_id; i++)
+                                       {
+                                               std::string call_addr = BoardE1::KhompPvtFXS::padOrig(base_addr, i - branch_id);
+                                               Opt::BranchToObjectMapType::iterator i = Opt::_fxs_branch_map.find(call_addr);
+
+                                               if (i == Opt::_fxs_branch_map.end())
+                                               {
+                                       LOG(WARNING, FMT("invalid value '%s': there is no such branch number.") % call_addr);
+                                                       return SPR_FAIL;
+                                               }
+
+                                               if (!fun(i->second.first, i->second.second, flags))
+                                                       return SPR_SUCCESS;
+                                       }
+                               }
+                               else
+                               {
+                                       for (unsigned int i = branch2_id; i >= branch_id; i--)
+                                       {
+                                               std::string call_addr = BoardE1::KhompPvtFXS::padOrig(base_addr, i - branch_id);
+
+                                               Opt::BranchToObjectMapType::iterator i = Opt::_fxs_branch_map.find(call_addr);
+
+                                               if (i == Opt::_fxs_branch_map.end())
+                                               {
+                                       LOG(WARNING, FMT("invalid value '%s': there is no such branch number.") % call_addr);
+                                                       return SPR_FAIL;
+                                               }
+
+                                               if (!fun(i->second.first, i->second.second, flags))
+                                                       return SPR_SUCCESS;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               DBG(FUNC, D("branch matched: %s") % base_addr);
+
+                               Opt::BranchToObjectMapType::iterator i = Opt::_fxs_branch_map.find(base_addr);
+
+                               if (i == Opt::_fxs_branch_map.end())
+                               {
+                       LOG(WARNING, FMT("invalid value '%s': there is no such branch number.") % base_addr);
+                                       return SPR_FAIL;
+                               }
+
+                               if (!fun(i->second.first, i->second.second, flags))
+                                       return SPR_SUCCESS;
+                       }
+               }
+
+               else
+               {
+               LOG(ERROR, FMT("invalid dial string '%s': unknown allocation method.") % allocstr.c_str());
+                       return SPR_FAIL;
+               }
+
+               if (what.matched(9)) // matched something about links/channels [cClL]n|[cC]n-m
+               {
+                       DBG(FUNC, D("channel/link matched"));
+                       unsigned long int object_id = Strings::toulong(what.submatch(11));
+
+                       if (what.matched(12))
+                       {
+
+                               DBG(FUNC, D("channel range matched")); // matched [cC]n-m
+
+                               if ((what.submatch(10))[0] != 'c' && (what.submatch(10))[0] != 'C')
+                               {
+                                       LOG(ERROR, FMT("invalid dial string '%s': range just allowed for channels.") % allocstr.c_str());
+                                       return SPR_FAIL;
+                               }
+
+                               unsigned long int object2_id = Strings::toulong(what.submatch(13));
+
+                               DBG(FUNC, D("(d=%d,lo=%d,up=%d,r=%s) c") % board_id % object_id % object2_id % (reverse ? "true" : "false"));
+
+                               if (reverse)
+                               {
+                                       for (unsigned int obj = std::min<unsigned int>(object2_id + 1, Globals::k3lapi.channel_count(board_id)); obj > 0 && obj > object_id; obj--)
+                                       {
+                                               if (!fun(board_id, obj-1, flags))
+                                                       return SPR_SUCCESS;
+                                       }
+                               }
+                               else
+                               {
+                                       for (unsigned int obj = object_id; obj < std::min<unsigned int>(Globals::k3lapi.channel_count(board_id), object2_id + 1); obj++)
+                                       {
+                                               if (!fun(board_id, obj, flags))
+                                                       return SPR_SUCCESS;
+                                       }
+                               }
+
+                       }
+
+                       else // matched [cClL]n
+                       {
+                               DBG(FUNC, D("individual channel/link matched"));
+
+                               switch ((what.submatch(10))[0])
+                               {
+                                       case 'C':
+                                       case 'c':
+                                               DBG(FUNC, D("individual channel matched"));
+
+                                               if (!fun(board_id, object_id, flags))
+                                                       return SPR_SUCCESS;
+
+                        return SPR_CONTINUE;
+
+                                       case 'l':
+                                       case 'L':
+                                               DBG(FUNC, D("individual link matched"));
+
+                                               switch (Globals::k3lapi.device_type(board_id))
+                                               {
+                                                       case kdtE1:
+                                                       case kdtPR:
+                                                       case kdtE1GW:
+                                                       case kdtE1IP:
+                                                       case kdtE1Spx:
+#if K3L_AT_LEAST(2,1,0)
+                                                       case kdtE1FXSSpx:
+#endif
+                                                       {
+                                                               unsigned int link_first = object_id * 30;
+                                                               unsigned int link_final = ((object_id + 1) * 30);
+
+                                                               if (reverse)
+                                                               {
+                                                                       for (unsigned int obj = std::min(link_final, Globals::k3lapi.channel_count(board_id)); obj > 0 && obj > link_first; obj--)
+                                                                       {
+                                                                               if (!fun(board_id, obj-1, flags))
+                                                                                       return SPR_SUCCESS;
+                                                                       }
+                                                               }
+                                                               else
+                                                               {
+                                                                       for (unsigned int obj = link_first; obj < std::min(Globals::k3lapi.channel_count(board_id), link_final); obj++)
+                                                                       {
+                                                                               if (!fun(board_id, obj, flags))
+                                                                                       return SPR_SUCCESS;
+                                                                       }
+                                                               }
+                                return SPR_CONTINUE;
+
+                                                       }
+
+                                                       default:
+                                                               LOG(ERROR, FMT("invalid dial string '%s': board '%d' does not have links.")
+                                                                       % allocstr.c_str() % board_id);
+                                                               return SPR_FAIL;
+                                               }
+
+                                       default:
+                                               LOG(ERROR, FMT("invalid dial string '%s': invalid object specification.") % allocstr.c_str());
+                                               return SPR_FAIL;
+                               }
+                       }
+               }
+               else if (what.matched(3) || what.matched(6)) // matched something about boards [bBsS]
+               {
+                       if (reverse)
+                       {
+                               for (unsigned int obj = Globals::k3lapi.channel_count(board_id); obj > 0; obj--)
+                               {
+                                       if (!fun(board_id, obj-1, flags))
+                                               return SPR_SUCCESS;
+                       }
+               }
+                       else
+                       {
+                               for (unsigned int obj = 0; obj < Globals::k3lapi.channel_count(board_id); obj++)
+                               {
+                                       if (!fun(board_id, obj, flags))
+                                               return SPR_SUCCESS;
+                               }
+                       }
+               }
+
+       }
+       catch (Strings::invalid_value e)
+       {
+               LOG(ERROR, FMT("invalid dial string '%s': invalid numeric value specified.") % allocstr.c_str());
+               return SPR_FAIL;
+       }
+    catch (Function::EmptyFunction & e)
+    {
+               LOG(ERROR, FMT("invalid function."));
+               return SPR_FAIL;
+    }
+
+       return SPR_CONTINUE;
+}
+
+static SpecRetType processSpecAtoms(std::string & gotatoms, SpecFlagsType & flags, SpecFunType & fun)
+{
+       std::string atoms(gotatoms);
+
+       DBG(FUNC, D("allocation string 'atoms': %s") % atoms);
+
+
+       if (!atoms.empty() && (atoms.at(0) == '*'))  //so it is a "cyclical" allocation
+       {
+               atoms.erase(0, 1);
+
+               if (flags & SPF_FIRST)
+               {
+                       if (!(flags & SPF_CYCLIC))
+                       {
+                               DBG(FUNC, D("got a cyclic/fair allocation (%s), priorizing less used channels...") % atoms);
+                               flags |= SPF_CYCLIC;
+                       }
+               }
+               else
+               {
+                       DBG(FUNC, D("cyclic/fair allocation NOT at first string, ignoring..."));
+               }
+       }
+
+
+       Strings::vector_type boundaries;
+       Strings::tokenize(atoms, boundaries, "+");
+
+    if (boundaries.size() < 1)
+    {
+        LOG(ERROR, FMT("invalid dial string '%s': no allocation string found!") % atoms);
+        return SPR_FAIL;
+    }
+
+       for (Strings::vector_type::iterator iter = boundaries.begin(); iter != boundaries.end(); iter++)
+       {
+               switch (processSpecAtom(*iter, flags, fun))
+               {
+                       // if had some error processing dialstring, bail out..
+                       case SPR_FAIL:
+                               return SPR_FAIL;
+
+                       // found someone? return ASAP!
+                       case SPR_SUCCESS:
+                               return SPR_SUCCESS;
+
+                       // else, keep going..
+                       case SPR_CONTINUE:
+                               break;
+               }
+
+               flags &= ~SPF_FIRST;
+       }
+
+       /* found nothing, but this is NOT an error */
+       return SPR_CONTINUE;
+}
+
+struct funProcessCallChannelString
+{
+       funProcessCallChannelString(int *cause, bool need_free)
+       : _cause(cause), _need_free(need_free),
+         _all_fail(true), //_fxs_only(true),
+         _pvt(NULL)
+       {};
+
+       bool operator()(unsigned int dev, unsigned int obj, SpecFlagsType & flags)
+       {
+        try
+        {
+           Board::KhompPvt *tmp = Board::get(dev, obj);
+
+               // used for cause definition
+                   if (_all_fail)
+                           _all_fail = (tmp ? !tmp->isOK() : true);
+        }
+        catch (K3LAPI::invalid_channel & err)
+        {
+            _all_fail = true;
+        }
+
+               //used for precise cause definition
+        //if (_fxs_only)
+               //      _fxs_only = (tmp ? tmp->is_fxs() : false);
+
+               if (flags & SPF_CYCLIC)
+               {
+                       Board::queueAddChannel(_channels, dev, obj);
+                       return true;
+               }
+               else
+               {
+                       _pvt = Board::findFree(dev, obj, _need_free);
+                       return (_pvt == NULL);
+               }
+               return true;
+       }
+
+       Board::KhompPvt * pvt(SpecFlagsType & flags)
+       {
+
+               if ((flags & SPF_CYCLIC) && !_pvt)
+               {
+                        //we have no pvt 'till now, lets find a suitable one..
+                       _pvt = Board::queueFindFree(_channels);
+               }
+
+               if (!_pvt && _cause && !(*_cause))
+               {
+
+                       if (_all_fail)
+                       {
+                               // all channels are in fail
+                               *_cause = SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+                       }
+                       else
+                       {
+                               //if (_fxs_only)
+                               //      *_cause = SWITCH_CAUSE_USER_BUSY;
+                               //else
+                                       *_cause = SWITCH_CAUSE_SWITCH_CONGESTION;
+                       }
+               }
+
+               return _pvt;
+       }
+
+       int   * _cause;
+
+       bool    _need_free;
+
+       bool    _all_fail;
+       //bool    _fxs_only; //TODO: futuro implementar a parte de FXS
+
+       Board::KhompPvt          * _pvt;
+       Board::PriorityCallQueue   _channels;
+};
+
+struct funProcessSMSChannelString
+{
+
+    funProcessSMSChannelString(int *cause)
+    : _cause(cause), _all_fail(true), _pvt(NULL)
+    {};  
+
+    bool operator()(unsigned int dev, unsigned int obj, SpecFlagsType & flags)
+    {    
+        Board::KhompPvt *pvt = Board::findFree(dev, obj);
+
+        if (pvt)
+        {
+            // found something? check if its GSM 
+            if (pvt->application(SMS_CHECK, NULL, NULL))
+            {    
+                // used for cause definition 
+                if (_all_fail)
+                    _all_fail = (pvt ? !pvt->isOK() : true);
+
+                if (flags & SPF_CYCLIC)
+                {    
+                    Board::queueAddChannel(_channels, dev, obj);
+                    return true;
+                }    
+                else 
+                {    
+                    _pvt = pvt; 
+                    return false;
+                }    
+            }    
+            else 
+            {    
+                // not gsm, return ASAP and stop search 
+                LOG(ERROR, PVT_FMT(pvt->target(), "channel is NOT a GSM channel! unable to send message!"));
+                return false;
+            }
+        }
+
+        // keep searching 
+        return true;
+    }
+
+    Board::KhompPvt * pvt(SpecFlagsType & flags)
+    {    
+        if ((flags & SPF_CYCLIC) && !_pvt)
+        {    
+            // we have no pvt 'till now, lets find a suitable one.. 
+            _pvt = Board::queueFindFree(_channels);
+        }
+
+        if (!_pvt && _cause && !(*_cause))
+        {    
+            if (_all_fail)
+            {    
+                // all channels are in fail 
+                *_cause = SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+            }    
+            else 
+            {    
+                // otherwise, congestion..
+                *_cause = SWITCH_CAUSE_SWITCH_CONGESTION;
+            }
+        }
+
+        return _pvt;
+    }
+
+    int                            * _cause;
+
+    bool                             _need_free;
+
+    bool                             _all_fail;
+
+       Board::KhompPvt          * _pvt;
+       Board::PriorityCallQueue   _channels;
+};
+
+struct FunProcessGroupString
+{
+    /* used for group processing */
+    FunProcessGroupString(std::string ctx)
+        : _ctx(ctx) {};
+
+    FunProcessGroupString(const FunProcessGroupString &o)
+        : _ctx(o._ctx) {};
+
+    bool operator()(unsigned int dev, unsigned int obj, SpecFlagsType & flags) const
+    {
+        try
+        {
+            Board::KhompPvt * pvt = Board::get(dev,obj);
+
+            DBG(CONF, FMT("loading context %s for channel %d,%d") % _ctx % dev % obj);
+
+            if (pvt) pvt->_group_context = _ctx;
+        }
+        catch (K3LAPI::invalid_channel & err)
+        {
+        }
+
+        return true;
+    }
+
+
+    std::string _ctx;
+};
+
+static bool processCallChannelString(std::string & str, Board::KhompPvt *& pvt, int * cause, bool need_free)
+{
+       funProcessCallChannelString  proc(cause, need_free);
+
+       SpecFlagsType   flags = SPF_FIRST;
+       SpecFunType     fun(proc, false); //   = ReferenceWrapper < SpecFunType > (proc);
+
+    bool ret = true;
+
+       switch (processSpecAtoms(str, flags, fun))
+       {
+               case SPR_FAIL:
+                       DBG(FUNC, D("SPR_FAIL: %p") % cause);
+
+                       if (cause)
+                               *cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+
+                       ret = false;
+            break;
+               case SPR_SUCCESS:
+               case SPR_CONTINUE:
+            pvt = proc.pvt(flags);
+                       DBG(FUNC, D("pvt = %p") % pvt);
+
+                       if (!pvt && cause && !(*cause))
+                               *cause = SWITCH_CAUSE_INTERWORKING;
+
+                       ret = true;
+            break;
+       }
+
+       return ret;
+}
+
+bool processSMSChannelString(std::string & str, Board::KhompPvt *& pvt, int *cause)
+{
+    funProcessSMSChannelString proc(cause);
+
+    SpecFlagsType flags = SPF_FIRST;
+    SpecFunType   fun(proc, false); 
+
+    switch (processSpecAtoms(str, flags, fun)) 
+    {    
+        case SPR_FAIL:
+            DBG(FUNC, FMT("SPR_FAIL: %p") % cause);
+            if (cause)
+                *cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+            return false;
+
+        case SPR_SUCCESS:
+        case SPR_CONTINUE:
+            pvt = proc.pvt(flags);
+            DBG(FUNC, FMT("pvt = %p") % pvt);
+
+            if (!pvt && cause && !(*cause))
+                *cause = SWITCH_CAUSE_INTERWORKING;
+
+            return true;
+    }    
+
+    return true;
+}
+
+Board::KhompPvt * processDialString (const char *dial_charv, int *cause)
+{
+       DBG(FUNC, D("c (%p, %p)") % dial_charv % cause);
+       std::string           dial_string(dial_charv);
+       Strings::vector_type  dial_args;
+
+       Strings::tokenize(dial_string, dial_args, "/");
+
+       Board::KhompPvt *pvt = NULL;
+
+    DBG(FUNC, FMT("processing dial string [%d] : '%s'") % dial_args.size() % dial_string);
+
+       if ((dial_args.size() < 1 && dial_args.size() > 3))
+       {
+               LOG(ERROR, FMT("invalid dial string '%s': wrong number of separators ('/').") % dial_string);
+               return NULL;
+       }
+
+       bool dial_string_ok = processCallChannelString(dial_args[0], pvt, cause, true);
+
+       if (pvt == NULL)
+       {
+               if (dial_string_ok)
+            LOG(WARNING, "unable to allocate channel -- no free channel found!");
+               return NULL;
+    }
+
+    DBG(FUNC, PVT_FMT(pvt->target(), "pvt %p") % pvt);
+
+       unsigned int opt_size = (pvt->hasNumberDial() ? 3 : 2);
+       unsigned int opt_arg  = opt_size - 1;
+    
+       if (dial_args.size() == opt_size)
+       {
+        Strings::vector_type options_args;
+        Strings::tokenize (dial_args[opt_arg], options_args, ":");
+
+               for (Strings::vector_type::iterator opt_arg = options_args.begin();
+                    opt_arg != options_args.end(); opt_arg++)
+               {
+                       std::string str = (*opt_arg);
+
+                       Strings::vector_type option_item;
+                       Strings::tokenize (str, option_item, "=");
+
+                       switch (option_item.size())
+                       {
+                               case 2:
+                               {
+                                       std::string index (option_item[0]);
+                                       std::string value (option_item[1]);
+
+                    if(pvt->call()->process(index, value))
+                                               continue;
+
+                                       break;
+                               }
+
+                               case 1:
+                               {
+                           std::string index (option_item[0]);
+
+                    if(pvt->call()->process(index))
+                                               continue;
+
+                                       break;
+                               }
+
+                               default:
+                   {
+                                       LOG(ERROR, FMT("invalid option specification '%s'.") % str);
+                       continue;
+                   }
+                       }
+            LOG(ERROR, FMT("unknown option name '%s', ignoring...") % str);
+        }
+       }
+
+    if(pvt->hasNumberDial())
+    {
+               if (dial_args.size() <= 1)
+               {
+            LOG(ERROR, FMT("invalid dial string '%s': missing destination number!") % dial_string);
+                       return NULL;
+               }
+
+        std::string name ("dest");
+        std::string value (dial_args[1]);
+
+        pvt->call()->process(name, value);
+
+               //pvt->call()->dest_addr = dial_args[1];
+       }
+
+    return pvt;
+};
+
+Board::KhompPvt * processSMSString (const char *sms_charv, int *cause)
+{
+    std::string           sms_string(sms_charv);
+    Strings::vector_type  sms_args;
+
+    Strings::tokenize(sms_string, sms_args, "/|,", 3); // '/' is a backward compatibility feature! 
+
+    DBG(FUNC, FMT("processing SMS string [%d] : '%s'") % sms_args.size() % sms_string);
+
+    if (sms_args.size () != 3)
+    {
+        LOG(ERROR, FMT("invalid dial string '%s': wrong number of separators.") % sms_string);
+        return NULL;
+    }
+
+    Board::KhompPvt *pvt = NULL;
+
+    bool dial_string_ok = processSMSChannelString(sms_args[0], pvt, cause);
+
+    if (pvt == NULL)
+    {
+        if (dial_string_ok)
+        {
+            LOG(WARNING, "unable to allocate channel -- no free channel found!");
+        }
+
+        return NULL;
+    }
+    else
+    {
+        if (!pvt->application(SMS_CHECK, NULL, NULL))
+        {
+            LOG(ERROR, PVT_FMT(pvt->target(), "allocated channel is NOT a GSM channel! unable to send message!"));
+
+            return NULL;
+        }
+    }
+
+
+/*
+    std::string dest(sms_args[1]);
+
+    bool conf = false;
+
+    if (dest[0] == '!')
+    {
+        dest.erase(0,1);
+        conf = true;
+    }
+
+    if (dest[dest.size()-1] == '!')
+    {
+        dest.erase(dest.size()-1,1);
+        conf = true;
+    }
+
+    // get options/values 
+    pvt->send_sms.sms_dest = dest;
+    pvt->send_sms.sms_conf = conf;
+    pvt->send_sms.sms_body = sms_args[2];
+*/
+
+    return pvt;
+};
+
+void processGroupString()
+{
+    for (Opt::GroupToDestMapType::iterator i = Opt::_groups.begin(); i != Opt::_groups.end(); i++)
+    {
+        const std::string & name = (*i).first;
+        std::string & opts = (*i).second;
+
+        Strings::vector_type tokens;
+        Strings::tokenize(opts, tokens, ",:", 2);
+
+        if (tokens.size() != 2 && tokens.size() != 1)
+        {
+            LOG(WARNING, FMT("wrong number of arguments at group '%s', ignoring group!\n") % name.c_str());
+            opts.clear();
+            continue;
+        }
+
+        if (tokens.size() < 2)
+            continue;
+        FunProcessGroupString    proc(tokens[1]);
+
+        SpecFlagsType   flags = SPF_FIRST;
+        SpecFunType     fun(proc, false);
+
+        switch (processSpecAtoms(tokens[0], flags, fun))
+        {
+            case SPR_CONTINUE:
+                // remove context from spec 
+                opts = tokens[0];
+
+                // log this! 
+                DBG(CONF, FMT("group '%s' is now '%s', with context '%s'...")
+                        % name % tokens[0] % tokens[1]);
+                break;
+
+            default:
+                LOG(WARNING, FMT("skipping group '%s', bad configuration!\n") % name.c_str());
+
+                // "zero" group 
+                opts.clear();
+
+                // log this! 
+                DBG(CONF, FMT("group '%s' have misconfigured options, ignoring...") % name);
+                break;
+        }
+    }
+}
+
diff --git a/src/mod/endpoints/mod_khomp/src/utils.cpp b/src/mod/endpoints/mod_khomp/src/utils.cpp
new file mode 100644 (file)
index 0000000..9044e60
--- /dev/null
@@ -0,0 +1,393 @@
+/*******************************************************************************
+
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License 
+  Version 1.1 (the "License"); you may not use this file except in compliance 
+  with the License. You may obtain a copy of the License at 
+  http://www.mozilla.org/MPL/ 
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file 
+  under the MPL, indicate your decision by deleting the provisions above and 
+  replace them with the notice and other provisions required by the LGPL 
+  License. If you do not delete the provisions above, a recipient may use your 
+  version of this file under either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, 
+    Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*******************************************************************************/
+
+#include <utils.h>
+#include "khomp_pvt.h"
+
+
+void Kflags::init()
+{
+    _flags[CONNECTED]._name = "CONNECTED";
+    _flags[CONNECTED]._value = false;
+    _flags[REALLY_CONNECTED]._name = "REALLY_CONNECTED";
+    _flags[REALLY_CONNECTED]._value = false;
+    _flags[IS_OUTGOING]._name = "IS_OUTGOING";
+    _flags[IS_OUTGOING]._value = false;
+    _flags[IS_INCOMING]._name = "IS_INCOMING";
+    _flags[IS_INCOMING]._value = false;
+    _flags[STREAM_UP]._name = "STREAM_UP";
+    _flags[STREAM_UP]._value = false;
+    _flags[LISTEN_UP]._name = "LISTEN_UP";
+    _flags[LISTEN_UP]._value = false;
+    _flags[GEN_CO_RING]._name = "GEN_CO_RING";
+    _flags[GEN_CO_RING]._value = false;
+    _flags[GEN_PBX_RING]._name = "GEN_PBX_RING";
+    _flags[GEN_PBX_RING]._value = false;
+    _flags[HAS_PRE_AUDIO]._name = "HAS_PRE_AUDIO";
+    _flags[HAS_PRE_AUDIO]._value = false;
+    _flags[HAS_CALL_FAIL]._name = "HAS_CALL_FAIL";
+    _flags[HAS_CALL_FAIL]._value = false;
+    _flags[DROP_COLLECT]._name = "DROP_COLLECT";
+    _flags[DROP_COLLECT]._value = false;
+    _flags[NEEDS_RINGBACK_CMD]._name = "NEEDS_RINGBACK_CMD";
+    _flags[NEEDS_RINGBACK_CMD]._value = false;
+    _flags[EARLY_RINGBACK]._name = "EARLY_RINGBACK";
+    _flags[EARLY_RINGBACK]._value = false;
+    _flags[FAX_DETECTED]._name = "FAX_DETECTED";
+    _flags[FAX_DETECTED]._value = false;
+    _flags[FAX_SENDING]._name = "FAX_SENDING";
+    _flags[FAX_SENDING]._value = false;
+    _flags[FAX_RECEIVING]._name = "FAX_RECEIVING";
+    _flags[FAX_RECEIVING]._value = false;
+    _flags[OUT_OF_BAND_DTMFS]._name = "OUT_OF_BAND_DTMFS";
+    _flags[OUT_OF_BAND_DTMFS]._value = false;
+    _flags[KEEP_DTMF_SUPPRESSION]._name = "KEEP_DTMF_SUPPRESSION";
+    _flags[KEEP_DTMF_SUPPRESSION]._value = false;
+    _flags[KEEP_ECHO_CANCELLATION]._name = "KEEP_ECHO_CANCELLATION";
+    _flags[KEEP_ECHO_CANCELLATION]._value = false;
+    _flags[KEEP_AUTO_GAIN_CONTROL]._name = "KEEP_AUTO_GAIN_CONTROL";
+    _flags[KEEP_AUTO_GAIN_CONTROL]._value = false;
+    _flags[WAIT_SEND_DTMF]._name = "WAIT_SEND_DTMF";
+    _flags[WAIT_SEND_DTMF]._value = false;
+    _flags[CALL_WAIT_SEIZE]._name = "CALL_WAIT_SEIZE";
+    _flags[CALL_WAIT_SEIZE]._value = false;
+    _flags[NUMBER_DIAL_FINISHD]._name = "NUMBER_DIAL_FINISHD";
+    _flags[NUMBER_DIAL_FINISHD]._value = false;
+    _flags[NUMBER_DIAL_ONGOING]._name = "NUMBER_DIAL_ONGOING";
+    _flags[NUMBER_DIAL_ONGOING]._value = false;
+
+    _flags[FXS_OFFHOOK]._name = "FXS_OFFHOOK";
+    _flags[FXS_OFFHOOK]._value = false;
+    _flags[FXS_DIAL_FINISHD]._name = "FXS_DIAL_FINISHD";
+    _flags[FXS_DIAL_FINISHD]._value = false;
+    _flags[FXS_DIAL_ONGOING]._name = "FXS_DIAL_ONGOING";
+    _flags[FXS_DIAL_ONGOING]._value = false;
+    _flags[FXS_FLASH_TRANSFER]._name = "FXS_FLASH_TRANSFER";
+    _flags[FXS_FLASH_TRANSFER]._value = false;
+    _flags[XFER_QSIG_DIALING]._name = "XFER_QSIG_DIALING";
+    _flags[XFER_QSIG_DIALING]._value = false;
+    _flags[XFER_DIALING]._name = "XFER_DIALING";
+    _flags[XFER_DIALING]._value = false;
+
+    _flags[SMS_DOING_UPLOAD]._name = "SMS_DOING_UPLOAD";
+    _flags[SMS_DOING_UPLOAD]._value = false;
+
+    /*
+    NOW LOADING ... 
+
+    _flags[BRIDGED]._name = "BRIDGED";
+    _flags[BRIDGED]._value = false;
+    */
+
+    _flags[INVALID_FLAG]._name = "INVALID_FLAG";
+    _flags[INVALID_FLAG]._value = false;
+}
+
+
+/* Command */
+
+bool ChanCommandHandler::writeNoSignal(const CommandRequest & cmd)
+{
+    _fifo->_mutex.lock();
+    bool status = _fifo->_buffer.provide(cmd);
+    _fifo->_mutex.unlock();
+    return status;
+};
+
+bool ChanCommandHandler::write(const CommandRequest & cmd)
+{
+    bool status = writeNoSignal(cmd);
+
+    if (status) signal();
+
+    return status;
+};
+
+void ChanCommandHandler::unreference()
+{
+    
+    if (!_fifo)
+        return;
+    
+    if(_fifo->_thread)
+    {
+        _fifo->_thread->join();
+        delete _fifo->_thread;
+        _fifo->_thread = NULL;
+    }
+
+    delete _fifo;
+    _fifo = NULL;
+};
+
+
+/* Event */
+
+bool ChanEventHandler::provide(const EventRequest & evt)
+{
+    _fifo->_mutex.lock();
+    bool status = _fifo->_buffer.provide(evt);
+    _fifo->_mutex.unlock();
+    return status;
+};
+
+bool ChanEventHandler::writeNoSignal(const EventRequest & evt)
+{
+    bool status = true;
+    _fifo->_mutex.lock();
+
+    try
+    {
+        _fifo->_buffer.provider_start().mirror(evt);
+        _fifo->_buffer.provider_commit();
+    }
+    catch(...) //BufferFull & e
+    {
+        status = false;
+    }
+
+    _fifo->_mutex.unlock();
+    return status;
+};
+
+bool ChanEventHandler::write(const EventRequest & evt)
+{
+    bool status = writeNoSignal(evt);
+
+    if (status) signal();
+
+    return status;
+};
+
+void ChanEventHandler::unreference()
+{
+    
+    if (!_fifo)
+        return;
+    
+    if(_fifo->_thread)
+    {
+        _fifo->_thread->join();
+        delete _fifo->_thread;
+        _fifo->_thread = NULL;
+    }
+
+    delete _fifo;
+    _fifo = NULL;
+};
+
+const char * answerInfoToString(int answer_info)
+{
+    switch (answer_info)
+    {    
+        case Board::KhompPvt::CI_MESSAGE_BOX:
+            return "MessageBox";
+        case Board::KhompPvt::CI_HUMAN_ANSWER:
+            return "HumanAnswer";
+        case Board::KhompPvt::CI_ANSWERING_MACHINE:
+            return "AnsweringMachine";
+        case Board::KhompPvt::CI_CARRIER_MESSAGE:
+            return "CarrierMessage";
+        case Board::KhompPvt::CI_UNKNOWN:
+            return "Unknown";
+        case Board::KhompPvt::CI_FAX:
+            return "Fax";
+    }    
+
+    return NULL;
+}
+
+/******************************** Kommuter ************************************/
+bool Kommuter::stop()
+{
+    if(_kwtd_timer_on)
+    {
+        Globals::global_timer->del(_kwtd_timer_index);
+        _kwtd_timer_on = false;
+    }
+
+    /* stop all watches */
+    if (Opt::_kommuter_activation == "auto")
+    {
+        for (int kommuter = 0 ; kommuter < _kommuter_count ; kommuter++)
+        {
+            try
+            {
+                Globals::k3lapi.command(-1, kommuter, CM_STOP_WATCHDOG);
+                LOG(MESSAGE, FMT("kommuter device (%d) was stoped at finalize_module().") % kommuter);
+            }
+            catch(K3LAPI::failed_command & e)
+            {
+                LOG(ERROR, FMT("could not stop the Kommuter device (%d) at finalize_module().") % kommuter);
+            }
+
+        }
+    }
+
+    return true;
+}
+
+bool Kommuter::initialize(K3L_EVENT *e)
+{
+    /* get total of kommuter devices */
+    _kommuter_count = e->AddInfo;
+   
+    if(Opt::_kommuter_activation == "manual")
+    {
+        if (_kommuter_count > 0)
+        {
+            LOG(WARNING, "Kommuter devices were found on your system, but activation is set to manual. To activate this devices use the command 'khomp kommuter on'.");
+        }
+
+        return true;
+    }
+
+    if (_kommuter_count > 0) 
+    {    
+        bool start_timer = false;
+        int timeout = Opt::_kommuter_timeout;
+
+        std::string param = STG(FMT("timeout=%d") % timeout);
+
+        for (int kommuter = 0; kommuter < _kommuter_count; kommuter++)
+        {   
+            try
+            {
+                Globals::k3lapi.command(-1, kommuter, CM_START_WATCHDOG, param.c_str());
+                start_timer = true;
+            }
+            catch(K3LAPI::failed_command & e)
+            {
+                switch(e.rc)
+                {
+                case ksInvalidParams:
+                    LOG(ERROR, FMT("invalid timeout '%d' for Kommuter device '%d' timeout. Mininum is 0, maximum is 255.")
+                                % timeout % kommuter);
+                    break;
+                default:
+                    LOG(ERROR, FMT("could not start the kommuter device number '%d'.") % kommuter);
+                    break;
+
+                }
+            }
+            catch(...)
+            {
+                LOG(ERROR, FMT("could not start the kommuter device number '%d'.") % kommuter);
+            }
+        }
+
+        if(timeout == 0)
+        {    
+            DBG(FUNC, D("kommuter watchdog timer not created because timeout is 0."));
+            return true;
+        }    
+
+        if (start_timer)
+        {    
+            if (!Globals::global_timer)
+            {    
+                LOG(ERROR, D("error creating the timer for kommuter."));
+            }
+            else
+            {
+                _kwtd_timer_index = Globals::global_timer->add((timeout < 5 ? (timeout*500) : 2000), &wtdKickTimer);
+                _kwtd_timer_on = true;
+
+                DBG(FUNC, D("kommuter watchdog timer created and started."));
+            }
+        }
+    }
+    else
+    {
+        DBG(FUNC, D("no kommuter devices were found on system."));
+    }
+    return true;
+}
+
+void Kommuter::wtdKickTimer(void *)
+{
+    try
+    {
+        bool restart_timer = false;
+
+        for (int kommuter = 0; kommuter < Board::kommuter._kommuter_count; kommuter++)
+        {
+            try
+            {
+                Globals::k3lapi.command(-1, kommuter, CM_NOTIFY_WATCHDOG);
+                restart_timer = true;
+                DBG(FUNC, D("Kommuter device (%d) notified.") % kommuter);
+            }
+            catch(K3LAPI::failed_command & e)
+            {
+                switch(e.rc)
+                {
+                    case ksInvalidState:
+                        LOG(ERROR, FMT("Kommuter device '%d' was not initialized.") % kommuter);
+                        break;
+                    case ksNotAvailable:
+                        LOG(ERROR, FMT("Kommuter device '%d' not found.") % kommuter);
+                        break;
+                    case ksFail:
+                        LOG(ERROR, FMT("Kommuter notify command has failed for device '%d'.") % kommuter);
+                        break;
+                    default:
+                        LOG(ERROR, FMT("Kommuter device '%d' could not be notified for some unknow reason.") % kommuter);
+                        break;
+                }
+            }
+        }
+
+        if(restart_timer)
+        {
+            Globals::global_timer->restart( Board::kommuter._kwtd_timer_index, true );
+            DBG(FUNC, D("Kommuter timer restarted."));
+        }
+    }
+    catch (...)
+    {
+        return;
+    }
+}
+
diff --git a/src/mod/endpoints/mod_khomp/support/config_defaults.cpp b/src/mod/endpoints/mod_khomp/support/config_defaults.cpp
new file mode 100644 (file)
index 0000000..9cf809e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <config_defaults.hpp>
+
+/* boolean value */
+Restriction::Pair booleanValue[3] =
+{
+    {    "Ativado",  "true" },
+    { "Desativado", "false" },
+    {        NULL ,   NULL  },
+};
diff --git a/src/mod/endpoints/mod_khomp/support/config_defaults.hpp b/src/mod/endpoints/mod_khomp/support/config_defaults.hpp
new file mode 100644 (file)
index 0000000..b3b77cf
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <configurator/restriction.hpp>
+
+#ifndef _CONFIG_DEFAULTS_HPP_
+#define _CONFIG_DEFAULTS_HPP_
+
+/* default khomp config directory */
+#define KHOMP_CONFIG_DIR "/etc/khomp/config"
+
+/* define util macro for text conversion */
+#define CONV(s) \
+    encoder::recode_env(encoder::C_ISO88591, s)
+
+/* define another util macro for text conversion */
+#define CONVU(s) \
+    encoder::recode_env(encoder::C_UTF8, s)
+
+/* shortcut */
+#define K(x) Restriction::K_##x
+#define N(x) Restriction::N_##x
+#define B(x) Restriction::B_##x
+
+/* boolean value */
+extern Restriction::Pair booleanValue[3];
+
+/* nasty shortcuts */
+#define BOOLEAN_VALUE        booleanValue[0], booleanValue[1], booleanValue[2]
+
+#define BOOLEAN_ALWAYS_TRUE  booleanValue[0], booleanValue[2]
+#define BOOLEAN_ALWAYS_FALSE booleanValue[1], booleanValue[2]
+
+#define BOOLEAN_TRUE         booleanValue[0].pretty
+#define BOOLEAN_FALSE        booleanValue[1].pretty
+
+#endif /* _CONFIG_DEFAULTS_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/support/klog-config.cpp b/src/mod/endpoints/mod_khomp/support/klog-config.cpp
new file mode 100644 (file)
index 0000000..d2d743a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <config_defaults.hpp>
+
+#include <support/klog-config.hpp>
+
+Logfile::Logfile()
+: Configfile("Options", "Log Options")
+{
+    _filename = STG(FMT("%s/klog.cfg") % KHOMP_CONFIG_DIR);
+
+    // necessario?
+    add(&_logoptions);
+
+    /* Obtain configuration, if file exists. */
+    _good = obtain();
+}
+
+Logfile::~Logfile()
+{
+    /* nothing for now */
+};
+
+bool Logfile::select(Section ** ptr, std::string str)
+{
+    // default section, needed for API compliance.
+    if (str == "")
+        *ptr = &_logoptions;
+    else
+    {
+        try
+        {
+            *ptr = _logoptions.section_find(str);
+        }
+        catch (Section::not_found e)
+        {
+            _errors.push_back(STG(FMT("unsupported section '%s', ignoring!") % str));
+        }
+    }
+
+    return (*ptr != 0);
+};
+
+bool Logfile::serialize(std::ofstream &fd)
+{
+    typedef std::vector < std::string > StrList;
+
+    StrList vec;
+
+    vec.push_back("KLogger");
+    vec.push_back("K3L");
+    vec.push_back("IntfK3L");
+    vec.push_back("IntfK3L_C");
+    vec.push_back("ISDN");
+    vec.push_back("R2");
+    vec.push_back("Firmware");
+    vec.push_back("Audio");
+    vec.push_back("SS7");
+    vec.push_back("SIP");
+    vec.push_back("GSM");
+    vec.push_back("Timer");
+
+    for (StrList::iterator i = vec.begin(); i != vec.end(); i++)
+    {
+        fd << "[" << (*i) << "]" << std::endl;
+
+        try
+        {
+            Section * sec = _logoptions.section_find(*i);
+            recurse(fd, sec);
+        }
+        catch (Section::not_found e)
+        {
+            _errors.push_back(STG(FMT("unable to find section '%s' in memory, ignoring!") % (*i)));
+        }
+
+        fd << std::endl;
+    }
+
+    fd << "# precisa ter um caracter sobrando no final!" << std::endl;
+
+    return true;
+}
diff --git a/src/mod/endpoints/mod_khomp/support/klog-config.hpp b/src/mod/endpoints/mod_khomp/support/klog-config.hpp
new file mode 100644 (file)
index 0000000..6e3e75a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#pragma GCC visibility push(default)
+#include <stdexcept>
+#pragma GCC visibility pop
+
+#include <format.hpp>
+
+#include <configurator/configfile.hpp>
+
+#include <support/klog-options.hpp>
+
+#ifndef _KLOG_CONFIG_HPP_
+#define _KLOG_CONFIG_HPP_
+
+struct Logfile: public Configfile
+{
+    Logfile();
+    ~Logfile();
+
+    bool select(Section **, std::string str = "");
+    bool serialize(std::ofstream &);
+
+    Section & root() { return _logoptions; };
+
+  protected:
+    LogOptions _logoptions;
+};
+
+#endif /* _KLOG_CONFIG_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/support/klog-options.cpp b/src/mod/endpoints/mod_khomp/support/klog-options.cpp
new file mode 100644 (file)
index 0000000..3cb7e3e
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <config_defaults.hpp>
+
+#include <support/klog-options.hpp>
+
+LogOptions::KLogger::KLogger()
+: Section("KLogger", "KLogger", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("FullLog", "Log everything", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::K3L::K3L()
+: Section("K3L", "K3L", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("CallProgress", "Call Progress events", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("CallAnalyzer", "Call Analyzer events", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("CadenceRecog", "Cadences recognized", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("CallControl",  "Call control", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("Fax",          "Fax stack", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::IntfK3L::IntfK3L()
+: Section("IntfK3L", "IntfK3L", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("AudioEvent", "Audio events", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::IntfK3L_C::IntfK3L_C()
+: Section("IntfK3L_C", "IntfK3L_C", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("AudioEvent", "Audio events", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::ISDN::ISDN()
+: Section("ISDN", "ISDN", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("Lapd", "LAPD layer log", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("Q931", "Q.931 layer log", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::R2::R2()
+: Section("R2", "R2", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("Signaling", "R2 Signaling log", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("States", "R2 States Log", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::Firmware::Firmware()
+: Section("Firmware", "Firmware", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("FwHdlcMsg", "HDLC messages", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("FwLinkErrors", "Link errors", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("FwModemChar", "MODEM char TX/RX", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::Audio::Audio()
+: Section("Audio", "Audio", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("DSP", "DSP audio messages", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("K3L", "K3L audio messages", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::SS7::SS7()
+: Section("SS7", "SS7", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("MTP2States", "MTP2 States", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("MTP2Debug", "MTP2 Debug", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("MTP3Management", "MTP3 Management", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("MTP3Test", "MTP3 Test", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("MTP3Debug", "MTP3 Debug", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("ISUPStates", "ISUP States", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("ISUPDebug", "ISUP Debug", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+    add(Option("ISUPMessages", "ISUP Messages", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::SIP::SIP()
+: Section("SIP", "SIP", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::GSM::GSM()
+: Section("GSM", "GSM", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::Timer::Timer()
+: Section("Timer", "Timer", false)
+{
+    add(Option("Value", "Enable log class?", BOOLEAN_FALSE, Restriction(K(STRING), N(UNIQUE), BOOLEAN_VALUE)));
+};
+
+LogOptions::LogOptions()
+: Section("Options", "KLog Options", false)
+{
+    add(&_klogger);
+    add(&_k3l);
+    add(&_intfk3l);
+    add(&_intfk3lc);
+    add(&_isdn);
+    add(&_r2);
+    add(&_firmware);
+    add(&_audio);
+    add(&_ss7);
+    add(&_sip);
+    add(&_gsm);
+    add(&_timer);
+};
diff --git a/src/mod/endpoints/mod_khomp/support/klog-options.hpp b/src/mod/endpoints/mod_khomp/support/klog-options.hpp
new file mode 100644 (file)
index 0000000..b700947
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+    KHOMP generic endpoint/channel library.
+    Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+  The contents of this file are subject to the Mozilla Public License Version 1.1
+  (the "License"); you may not use this file except in compliance with the
+  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+  the specific language governing rights and limitations under the License.
+
+  Alternatively, the contents of this file may be used under the terms of the
+  "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+  case the provisions of "LGPL License" are applicable instead of those above.
+
+  If you wish to allow use of your version of this file only under the terms of
+  the LGPL License and not to allow others to use your version of this file under
+  the MPL, indicate your decision by deleting the provisions above and replace them
+  with the notice and other provisions required by the LGPL License. If you do not
+  delete the provisions above, a recipient may use your version of this file under
+  either the MPL or the LGPL License.
+
+  The LGPL header follows below:
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this library; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+#include <types.hpp>
+
+#include <configurator/option.hpp>
+#include <configurator/section.hpp>
+
+#ifndef _KLOG_OPTIONS_HPP_
+#define _KLOG_OPTIONS_HPP_
+
+struct LogOptions: public Section
+{
+    struct KLogger:   public Section { KLogger();   };
+    struct K3L:       public Section { K3L();       };
+    struct IntfK3L:   public Section { IntfK3L();   };
+    struct IntfK3L_C: public Section { IntfK3L_C(); };
+    struct ISDN:      public Section { ISDN();      };
+    struct R2:        public Section { R2();        };
+    struct Firmware:  public Section { Firmware();  };
+    struct Audio:     public Section { Audio();     };
+    struct SS7:       public Section { SS7();       };
+    struct SIP:       public Section { SIP();       };
+    struct GSM:       public Section { GSM();     };
+    struct Timer:     public Section { Timer();     };
+
+    LogOptions();
+
+    KLogger     _klogger;
+    K3L         _k3l;
+    IntfK3L     _intfk3l;
+    IntfK3L_C   _intfk3lc;
+    ISDN        _isdn;
+    R2          _r2;
+    Firmware    _firmware;
+    Audio       _audio;
+    SS7         _ss7;
+    SIP         _sip;
+    GSM         _gsm;
+    Timer       _timer;
+};
+
+#endif /* _KLOG_OPTIONS_HPP_ */
diff --git a/src/mod/endpoints/mod_khomp/tools/getversion.sh b/src/mod/endpoints/mod_khomp/tools/getversion.sh
new file mode 100755 (executable)
index 0000000..d22bf2b
--- /dev/null
@@ -0,0 +1,51 @@
+#/bin/bash
+
+###############################################################################
+#   KHOMP generic endpoint/channel library.
+#   Copyright (C) 2007-2010 Khomp Ind. & Com.
+
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.1 (the "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+# the specific language governing rights and limitations under the License.
+
+# Alternatively, the contents of this file may be used under the terms of the
+# "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+# case the provisions of "LGPL License" are applicable instead of those above.
+
+# If you wish to allow use of your version of this file only under the terms of
+# the LGPL License and not to allow others to use your version of this file
+# under the MPL, indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by the LGPL
+# License. If you do not delete the provisions above, a recipient may use your
+# version of this file under either the MPL or the LGPL License.
+
+# The LGPL header follows below:
+
+#   This library is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU Lesser General Public
+#   License as published by the Free Software Foundation; either
+#   version 2.1 of the License, or (at your option) any later version.
+
+#   This library is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   Lesser General Public License for more details.
+
+#   You should have received a copy of the GNU Lesser General Public License
+#   along with this library; if not, write to the Free Software Foundation,
+#   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+###############################################################################
+
+version=`grep "#define $1" $2/src/include/switch_version.h | sed -r "s/#define\s+$1.*\"(.*)\"/\1/g"`
+
+if [ "$version" == "head" ]
+then
+    echo -1
+else
+    echo $version
+fi