]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
[mod_kazoo] some fixes & enhancements
authorAndrey Volk <andywolk@gmail.com>
Thu, 5 Mar 2020 16:48:40 +0000 (20:48 +0400)
committerGitHub <noreply@github.com>
Thu, 5 Mar 2020 16:48:40 +0000 (20:48 +0400)
* [mod_kazoo] address scan-build warnings

* [mod_kazoo] don't use switch_core_session_force_locate

* [mod_kazoo] add loglevel support per event

* [mod_kazoo] add option to serialize as array

* [mod_kazoo] handle verbose fields

* [mod_kazoo] handle _body header field

* [mod_kazoo] ensure raw json is valid

* [mod_kazoo] encode json number

encodes double as unsigned long long if possible

note: file was formatted

* [mod_kazoo] fix tweaks configuration

* [mod_kazoo] move headers to proper place

* to use Target-Node in filtering
  we need to add and then remove it
  since the next node uses the same event
  to build the message

* [mod_kazoo] handle cleanup in new_event_stream

* [mod_kazoo] do not decode _json_ headers

* [mod_kazoo] add kz_cdr event

* fires the event in report state
* adds json serialized parts
  that can be included
  in event message
* moves history funcs from
  kazoo_commands to kazoo_cdr

* [mod_kazoo] format default configuration

* [mod_kazoo] validate bracket creation

* [mod_kazoo] use single fd for kz_http_put

* [mod_kazoo] add uuid to kz_expand

20 files changed:
src/mod/event_handlers/mod_kazoo/Makefile.am
src/mod/event_handlers/mod_kazoo/kazoo.conf.xml
src/mod/event_handlers/mod_kazoo/kazoo_api.c
src/mod/event_handlers/mod_kazoo/kazoo_cdr.c [new file with mode: 0644]
src/mod/event_handlers/mod_kazoo/kazoo_commands.c
src/mod/event_handlers/mod_kazoo/kazoo_config.c
src/mod/event_handlers/mod_kazoo/kazoo_dptools.c
src/mod/event_handlers/mod_kazoo/kazoo_ei_config.c
src/mod/event_handlers/mod_kazoo/kazoo_ei_utils.c
src/mod/event_handlers/mod_kazoo/kazoo_endpoints.c
src/mod/event_handlers/mod_kazoo/kazoo_event_stream.c
src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c
src/mod/event_handlers/mod_kazoo/kazoo_fields.h
src/mod/event_handlers/mod_kazoo/kazoo_message.c
src/mod/event_handlers/mod_kazoo/kazoo_node.c
src/mod/event_handlers/mod_kazoo/kazoo_tweaks.c
src/mod/event_handlers/mod_kazoo/kazoo_utils.c
src/mod/event_handlers/mod_kazoo/kazoo_utils.h
src/mod/event_handlers/mod_kazoo/mod_kazoo.c
src/mod/event_handlers/mod_kazoo/mod_kazoo.h

index 668d9ffed2a94ad46a6ba741e8589677dd322ed7..36e7a9ea4a40a751230a1b9d2ff26fb62427d5be 100644 (file)
@@ -12,6 +12,7 @@ mod_kazoo_la_SOURCES  += kazoo_message.c
 mod_kazoo_la_SOURCES  += kazoo_ei_config.c kazoo_ei_utils.c kazoo_event_stream.c
 mod_kazoo_la_SOURCES  += kazoo_fetch_agent.c kazoo_node.c
 mod_kazoo_la_SOURCES  += kazoo_endpoints.c
+mod_kazoo_la_SOURCES  += kazoo_cdr.c
 mod_kazoo_la_SOURCES  += kz_node.c
 
 mod_kazoo_la_CFLAGS   = $(AM_CFLAGS) @ERLANG_CFLAGS@ -D_REENTRANT -DERLANG_VERSION=@ERLANG_VERSION@ -DERLANG_MAJOR=@ERLANG_MAJOR@ -DERLANG_MINOR=@ERLANG_MINOR@
index a86942068193cb58eb7a43d242b0ed0e2f06df76..353db1b0c132df8d120981f084ae65390f081e1b 100644 (file)
@@ -4,13 +4,12 @@
        <settings>
                <param name="listen-ip" value="0.0.0.0" />
                <param name="listen-port" value="6031" />
-               <!--<param name="cookie-file" value="/etc/freeswitch/autoload_configs/.erlang.cookie" 
-                       /> -->
+               <!--<param name="cookie-file" value="/etc/freeswitch/autoload_configs/.erlang.cookie"/> -->
                <param name="cookie" value="change_me" />
                <param name="shortname" value="false" />
                <param name="nodename" value="freeswitch" />
-               <!--<param name="kazoo-var-prefix" value="ecallmgr" /> -->
-               <!--<param name="compat-rel" value="12"/> -->
+               <!--<param name="kazoo-var-prefix" value="ecallmgr" />-->
+               <!--<param name="compat-rel" value="12"/>-->
                <param name="send-all-headers" value="false" />
 
                <param name="event-stream-preallocate" value="8192" />
 
        </settings>
 
-    <variables>
-        <variable name="UNIX_EPOCH_IN_GREGORIAN" value="62167219200"/>
-    </variables>
-
-    <definitions>
-        <definition name="debug-call">
-            <filters>
-                <filter name="${first-of(variable_debug_call|Call-Debug|#$${Call-Debug})}" type="include" value="true" />
-            </filters>
-            <field name="Call-Debug" type="static" serialize-as="object">
-                <fields verbose="true" />
-            </field>
-        </definition>
-
-        <definition name="originated-legs">
-            <filters>
-                <filter name="variable_originated_legs" type="include" compare="exists" />
-            </filters>
-            <field name="Other-Legs" type="static" serialize-as="object">
-                <fields verbose="false">
-                    <field name="variable_originated_legs" as="Callee" />
-                    <field name="variable_originate_causes" as="Causes" />
-                </fields>
-            </field>            
-        </definition>
-
-        <definition name="transfer-history">
-            <filters>
-                <filter name="variable_transfer_history" type="include" compare="exists" />
-            </filters>
-            <field name="Transfer-History" type="expand" value="${kz_json_history(${variable_transfer_history})}" serialize-as="raw"/>
-        </definition>
-
-        <definition name="transfer-source">
-            <filters>
-                <filter name="variable_transfer_source" type="include" compare="exists" />
-            </filters>
-            <field name="Transfer-Source" type="expand" value="${kz_json_history(variable_transfer_source)}" serialize-as="raw"/>
-        </definition>
-
-        <definition name="interaction-id">
-            <field name="variable_Call-Interaction-ID" as="Call-Interaction-ID" />
-            <field name="Call-Interaction-Is-Root" type="static" value="true" serialize-as="boolean">
-                   <filters>
-                   <filter name="variable_Call-Interaction-ID" type="include" compare="field" value="variable_Original-Call-Interaction-ID" />
-                      <filter name="${first-of(Event-Subclass|Event-Name|#none)}" type="include" compare="list" value="CHANNEL_DESTROY|KZ_CDR"/>
-                   </filters>
-            </field>
-        </definition>
-
-        <definition name="Metaflow-Control">
-            <field name="Metaflow-Control" type="static" serialize-as="object">
-                <filters>
-                    <filter name="ecallmgr" type="include" compare="prefix"
-                        value="variable_Metaflow-Control-" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_Metaflow-Control-" type="prefix" exclude-prefix="true" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="Call-Control">
-            <field name="Call-Control" type="static" serialize-as="object">
-                <filters>
-                    <filter name="ecallmgr" type="include" compare="prefix"
-                        value="variable_Call-Control-" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_Call-Control-" type="prefix" exclude-prefix="true" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="Control">
-            <field name="Call-Control" type="reference" />
-            <field name="Metaflow-Control" type="reference" />
-        </definition>
-
-        <definition name="Privacy">
-            <field name="Privacy" type="static" serialize-as="object">
-                <fields verbose="false">
-                           <field name="Caller-Privacy-Hide-Number" as="Hide-Number" serialize-as="boolean" />
-                           <field name="Caller-Privacy-Hide-Name" as="Hide-Name" serialize-as="boolean" />
-                           <field name="Caller-Screen-Bit" as="Screen-Bit" serialize-as="boolean" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="Custom-Channel-Vars">
-            <field name="Custom-Channel-Vars" type="static" serialize-as="object">
-                <fields verbose="false">
-                    <field name="X-ecallmgr_" type="prefix"
-                        exclude-prefix="true" />
-                    <field name="variable_sip_h_X-ecallmgr_" type="prefix"
-                        exclude-prefix="true" />
-                    <field name="variable_ecallmgr_" type="prefix"
-                        exclude-prefix="true" />
-
-                    <field name="Fetch-UUID" as="Fetch-ID" />
-
-                    <field name="Referred-To" type="expand"
-                        value="sip:${regex(${url_decode(${variable_sip_refer_to})}|&lt;sips?:(.*)&gt;|%1)}">
-                        <filters>
-                            <filter name="variable_sip_refer_to" type="include" compare="exists" />
-                        </filters>
-                    </field>
-                    <field name="variable_sip_h_Referred-By" as="Referred-By"/>
-                    <!-- <field name="Referred-By" type="expand" value="sip:${regex(${variable_sip_h_Referred-By}|&lt;sips?:(.*)&gt;|%1)}">
-                        <filters>
-                            <filter name="variable_sip_h_Referred-By" type="include" compare="exists" />
-                        </filters>
-                    </field>
-                    -->
-
-                    <!-- <field name="variable_Call-Interaction-ID" as="Call-Interaction-ID" /> -->
-                    <field name="interaction-id" type="reference" />
-
-                    <field name="variable_presence_id" as="Presence-ID" />
-
-                    <field name="redirect" type="group">
-                        <filters>
-                            <!-- <filter name="variable_last_bridge_hangup_cause" type="include" compare="value" value="REDIRECTION_TO_NEW_DESTINATION" /> -->
-                            <filter name="variable_sip_redirected_by" type="include" compare="exists" />
-                        </filters>
-                        <fields verbose="false">
-                            <field name="Redirected-By" type="expand" value="sip:${regex(${variable_sip_redirected_by}|&lt;sips?:(.*)&gt;|%1)}"/>
-                            <field name="Redirected-Reason" type="expand" value="${regex(${variable_sip_redirected_by}|reason=(.*)|%1)}"/>
-                        </fields>
-                    </field>
-
-                    <field name="Caller-Privacy-Hide-Number" as="Privacy-Hide-Number" serialize-as="boolean" />
-                    <field name="Caller-Privacy-Hide-Name" as="Privacy-Hide-Name" serialize-as="boolean" />
-
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="Custom-Application-Vars">
-            <field name="Custom-Application-Vars" type="static"
-                serialize-as="object">
-                <filters>
-                    <filter name="ecallmgr" type="include" compare="prefix"
-                        value="variable_cav_" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_cav_" type="prefix" exclude-prefix="true" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="Custom-SIP-Headers">
-            <field name="Custom-SIP-Headers" type="static" serialize-as="object">
-                <filters>
-                    <filter name="ecallmgr" type="include" compare="prefix"
-                        value="variable_sip_h_" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_sip_h_" type="prefix" exclude-prefix="true" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="to-did">
-            <field name="To-DID" type="first-of"
-                value="variable_ecallmgr_E164-Destination|variable_ecallmgr_Original-Number|Caller-Destination-Number" />
-        </definition>
-
-        <definition name="from-network">
-            <field name="From-Network-Addr" type="first-of"
-                value="variable_sip_h_X-AUTH-IP|variable_sip_received_ip" />
-            <field name="From-Network-Port" type="first-of"
-                value="variable_sip_h_X-AUTH-PORT|variable_sip_received_port" />
-        </definition>
-
-        <definition name="call-direction">
-            <!-- <field name="Call-Direction" type="first-of" value="Caller-Logical-Direction|Call-Direction" 
-                /> -->
-            <field name="Call-Direction" />
-        </definition>
-
-        <definition name="caller-id">
-            <field name="Caller-ID-Number" type="first-of"
-                value="variable_origination_caller_id_number|variable_effective_caller_id_number|Caller-Caller-ID-Number" />
-            <field name="Caller-ID-Name" type="first-of"
-                value="variable_origination_caller_id_name|variable_effective_caller_id_name|Caller-Caller-ID-Name" />
-            <field name="Callee-ID-Number" type="first-of"
-                value="variable_origination_callee_id_number|variable_effective_callee_id_number|Caller-Callee-ID-Number|Other-Leg-Caller-ID-Number" />
-            <field name="Callee-ID-Name" type="first-of"
-                value="variable_origination_callee_id_name|variable_effective_callee_id_name|Caller-Callee-ID-Name|Other-Leg-Caller-ID-Name" />
-        </definition>
-
-        <definition name="other-leg">
-            <field name="Other-Leg-Direction" />
-            <field name="Other-Leg-Caller-ID-Name" />
-            <field name="Other-Leg-Caller-ID-Number" />
-            <field name="Other-Leg-Destination-Number" />
-            <field name="Other-Leg-Call-ID" type="first-of"
-                value="Other-Leg-Unique-ID|Other-Leg-Call-ID|variable_origination_uuid" />
-        </definition>
-
-        <definition name="application">
-            <field name="Application-Name" type="first-of"
-                value="Application-UUID-Name|kazoo_application_name|Application|Event-Subclass" />
-            <field name="Application-Response" type="first-of"
-                value="kazoo_application_response|Application-Response" />
-        </definition>
-
-        <definition name="raw-application">
-            <field name="Raw-Application-Name" type="first-of"
-                value="kazoo_application_name|Application|Event-Subclass" />
-            <field name="Application-Data" as="Raw-Application-Data" />
-        </definition>
-
-        <definition name="application-all">
-            <field name="raw-application" type="reference" />
-            <field name="application" type="reference" />
-        </definition>
-
-        <definition name="application-uuid">
-            <field name="application-all" type="reference" />
-            <field name="Application-UUID" type="first-of"
-                value="app_uuid|variable_app_uuid|Application-UUID" />
-        </definition>
-
-        <definition name="Switch-URI">
-            <field name="variable_Switch-URI" as="Switch-URI" />
-        </definition>
-
-        <definition name="freeswitch-url">
-            <field name="FreeSWITCH-Hostname" as="Media-Server" />
-            <field name="FreeSWITCH-Hostname" as="Switch-Hostname" />
-            <field name="Switch-Nodename" />
-            <field name="variable_Switch-URL" as="Switch-URL" />
-            <field name="Switch-URI" type="reference" />
-        </definition>
-
-        <definition name="loopback">
-            <field name="variable_is_loopback" as="Channel-Is-Loopback"
-                serialize-as="boolean" />
-            <field name="Loopback" type="group">
-                <filters>
-                    <filter name="variable_is_loopback" type="include" compare="value"
-                        value="1" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_loopback_leg" as="Channel-Loopback-Leg" />
-                    <field name="variable_other_loopback_leg_uuid" as="Channel-Loopback-Other-Leg-ID" />
-                    <field name="variable_loopback_bowout" as="Channel-Loopback-Bowout"
-                        serialize-as="boolean" />
-                    <field name="variable_loopback_bowout_on_execute" as="Channel-Loopback-Bowout-Execute"
-                        serialize-as="boolean" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="caller-context">
-            <field name="variable_sofia_profile_name" as="Caller-Profile" />
-            <field name="Caller-Context" />
-            <field name="Caller-Dialplan" />
-            <field name="Caller-Destination-Number" />
-        </definition>
-
-        <definition name="hunt-context">
-            <field name="variable_sofia_profile_name" as="Hunt-Profile" />
-            <field name="Hunt-Context" />
-            <field name="Hunt-Dialplan" />
-            <field name="Hunt-Destination-Number" />
-            <!-- 
-            <field name="Request" type="expand"
-                value="${first-of(variable_sip_to_uri|variable_sip_req_uri|#${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)})}" />
-            <field name="To" type="expand"
-                value="${first-of(variable_sip_to_uri|variable_sip_req_uri|#${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)})}" />
-            -->
-            <field name="Request" type="expand"
-                value="${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
-            <field name="To" type="expand"
-                value="${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
-            <field name="From" type="expand"
-                value="${first-of(Hunt-Caller-ID-Number|origination_callee_id_number|variable_sip_from_user)}@${first-of(variable_sip_invite_domain|variable_sip_from_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
-        </definition>
-
-        <definition name="sip-tags">
-            <field name="variable_sip_to_tag" as="To-Tag" />
-            <field name="variable_sip_from_tag" as="From-Tag" />
-        </definition>
-
-        <definition name="channel-state">
-            <!-- erlang strips CS_ from beginning, lets do that -->
-            <field name="Channel-State" type="expand"
-                value="${regex(${Channel-State}|^CS_(.*)$|%1)}" />
-            <field name="Channel-Call-State" />
-            <field name="Channel-Name" />
-            <field name="Answer-State" />
-        </definition>
-
-        <definition name="presence-id">
-            <field name="variable_presence_id" as="Presence-ID" />
-        </definition>
-
-
-        <definition name="call_event_headers">
-            <field name="Event-Category" type="static" value="call_event" />
-            <field name="Event-Name" type="first-of"
-                value="kazoo_event_name|Event-Subclass|Event-Name" />
-            <field name="Event-Date-Timestamp" as="Msg-ID" />
-            <field name="Timestamp" type="expand"
-                value="${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}"
-                serialize-as="number" />
-            <field name="variable_sip_origination_call_uuid" as="Origination-Call-ID" />
-            <field name="Call-ID" type="first-of" value="Unique-ID|Caller-Unique-ID|caller-unique-id"/>
-            <field name="Caller-Channel-Created-Time" as="Channel-Created-Time" />
-
-            <field name="Switch-Nodename" as="Node" />
-
-            <field name="variable_sip_invite_domain" as="Domain-Name" />
-            <field name="App-Name" type="static" value="freeswitch" />
-            <field name="App-Version" type="static" value="1.0" />
-        </definition>
-
-        <definition name="user-agent">
-            <field name="variable_sip_user_agent" as="User-Agent" />
-        </definition>
-
-
-        <definition name="call_event">
-            <field name="call_event_headers" type="reference" />
-            <field name="application-all" type="reference" />
-            <field name="call-direction" type="reference" />
-            <field name="channel-state" type="reference" />
-            <field name="caller-id" type="reference" />
-            <field name="caller-context" type="reference" />
-            <field name="sip-tags" type="reference" />
-            <field name="presence-id" type="reference" />
-            <field name="loopback" type="reference" />
-            <field name="freeswitch-url" type="reference" />
-            <field name="other-leg" type="reference" />
-            <field name="user-agent" type="reference" />
-            <field name="Custom-Channel-Vars" type="reference" />
-            <field name="Custom-Application-Vars" type="reference" />
-            <field name="Control" type="reference" />
-            <field name="debug-call" type="reference" />
-        </definition>
-
-        <definition name="fetch-info">
-            <field name="Event-Category" type="static" value="fetch" />
-            <field name="App-Name" type="static" value="freeswitch" />
-            <field name="App-Version" type="static" value="1.0" />
-            <field name="Switch-Nodename" as="Node" />
-            <field name="Fetch-UUID" />
-            <field name="Fetch-UUID" as="Msg-ID" />
-            <!-- <field name="Call-ID" type="first-of" value="Fetch-Call-UUID|Unique-ID" 
-                /> -->
-            <field name="Call-ID" type="first-of" value="Unique-ID" />
-            <field name="Fetch-Section" />
-            <field name="Fetch-Timeout" />
-            <field name="Fetch-Timestamp-Micro" />
-            <field name="Kazoo-Bundle" as="Fetch-Version" />
-            <field name="Custom-SIP-Headers" type="reference" />
-            <field name="Custom-Channel-Vars" type="reference" />
-            <field name="Custom-Application-Vars" type="reference" />
-            <field name="freeswitch-url" type="reference" />
-            <field name="Control" type="reference" />
-            <field name="Privacy" type="reference" />
-            <field name="debug-call" type="reference" />
-            
-        </definition>
-
-        <definition name="destination-number">
-            <field name="Destination-Number" type="first-of"
-                value="Hunt-Destination-Number|Caller-Destination-Number" />
-        </definition>
-
-        <definition name="from-to">
-            <field name="Request" type="first-of"
-                value="variable_sip_req_uri|variable_sip_loopback_req_uri|variable_sip_to_uri" />
-            <field name="To" type="first-of"
-                value="variable_sip_to_uri|variable_sip_req_uri|variable_sip_loopback_req_uri" />
-            <field name="variable_sip_to_uri" as="To-URI" />
-            <field name="From" type="first-of"
-                value="variable_sip_from_uri|variable_presence_id|variable_sip_loopback_from_uri" />
-            <field name="variable_sip_from_uri" as="From-URI" />
-        </definition>
-
-        <definition name="sdp">
-            <field name="variable_switch_r_sdp" as="Remote-SDP" />
-            <field name="variable_rtp_local_sdp_str" as="Local-SDP" />
-        </definition>
-
-        <definition name="call-duration">
-            <field name="variable_duration" as="Duration-Seconds"
-                serialize-as="number" />
-            <field name="variable_progresssec" as="Ringing-Seconds"
-                serialize-as="number" />
-            <field name="Billing-Seconds" type="expand"
-                value="${expr(ceil(${variable_billmsec} / 1000))}" serialize-as="number" />
-        </definition>
-
-        <definition name="hangup-disposition">
-            <field name="Disposition" type="first-of"
-                value="variable_originate_disposition|variable_endpoint_disposition" />
-        </definition>
-
-        <definition name="hangup-code">
-            <field name="Hangup-Code" type="first-of"
-                value="variable_proto_specific_hangup_cause|variable_last_bridge_proto_specific_hangup_cause" />
-        </definition>
-
-        <definition name="hangup-cause">
-            <field name="Hangup-Cause" type="first-of"
-                value="variable_originate_failed_cause|variable_bridge_hangup_cause|variable_hangup_cause|Hangup-Cause">
-                <filters>
-                    <filter name="variable_current_application" type="include"
-                        compare="value" value="bridge" />
-                </filters>
-            </field>
-            <field name="Hangup-Cause" type="first-of"
-                value="variable_originate_failed_cause|variable_hangup_cause|variable_bridge_hangup_cause|Hangup-Cause">
-                <filters>
-                    <filter name="variable_current_application" type="exclude"
-                        compare="value" value="bridge" />
-                </filters>
-            </field>
-        </definition>
-
-        <definition name="hangup-fields">
-            <field name="hangup-code" type="reference" />
-            <field name="hangup-cause" type="reference" />
-            <field name="hangup-disposition" type="reference" />
-        </definition>
-
-        <definition name="conference-caller-id">
-            <field name="CONF-CALLER-ID-IN" type="group">
-                <filters>
-                    <filter name="Call-Direction" type="include" compare="value" value="inbound" />
-                </filters>
-                <fields verbose="false">
-                    <field name="Caller-Caller-ID-Name" as="Caller-ID-Name" />
-                    <field name="Caller-Caller-ID-Number" as="Caller-ID-Number" />
-                </fields>
-            </field>
-            <field name="CONF-CALLER-ID-OUT" type="group">
-                <filters>
-                    <filter name="Call-Direction" type="include" compare="value" value="outbound" />
-                </filters>
-                <fields verbose="false">
-                    <field name="variable_origination_callee_id_name" as="Caller-ID-Name" />
-                    <field name="variable_origination_callee_id_number" as="Caller-ID-Number" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="conference-bgdial">
-            <field name="Dial-Result" type="static" serialize-as="object">
-                <filters>
-                    <filter name="Action" type="include" compare="value" value="bgdial-result" />
-                </filters>
-                <fields verbose="false">
-                    <field name="Result"/>
-                    <field name="Job-UUID"/>
-                    <field name="Peer-UUID"/>
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="conference-vars">
-            <field name="Conference-Vars" type="static"
-                serialize-as="object">
-                <fields verbose="false">
-                    <field name="Conference-" type="prefix" exclude-prefix="true" />
-                    <field name="Account-ID" type="first-of" value="Account-ID|Conference-Account-ID|variable_ecallmgr_Account-ID" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="conference-channel-vars">
-            <field name="Conference-Channel-Vars" type="static"
-                serialize-as="object">
-                <fields verbose="false">
-                    <field name="variable_conference_moderator" as="Is-Moderator"
-                        serialize-as="boolean" />
-                    <field name="Floor" serialize-as="boolean" />
-                    <field name="Video" serialize-as="boolean" />
-                    <field name="See" serialize-as="boolean" />
-                    <field name="Speak" serialize-as="boolean" />
-                    <field name="Hear" serialize-as="boolean" />
-                    <field name="Talking" serialize-as="boolean" />
-                    <field name="Mute-Detect" serialize-as="boolean" />
-
-                    <field name="Energy-Level" serialize-as="number" />
-                    <field name="Current-Energy" serialize-as="number" />
-                    <field name="Member-ID" serialize-as="number" />
-
-                    <field name="Member-Ghost" serialize-as="boolean" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="conference-event">
-            <field name="Event-Category" type="static" value="conference" />
-            <field name="Event-Name" type="static" value="event" />
-            <field name="Switch-Nodename" as="Node" />
-            <field name="Core-UUID" />
-            <field name="freeswitch-url" type="reference" />
-            <field name="App-Name" type="static" value="freeswitch" />
-            <field name="App-Version" type="static" value="1.0" />
-            <field name="Action" as="Event" />
-            <field name="Conference-Name" as="Conference-ID" />
-            <field name="Conference-Unique-ID" as="Instance-ID" />
-            <field name="Conference-Node" />
-            <field name="Conference-Profile" as="Profile" />
-            <field name="Unique-ID" as="Call-ID" />
-            <field name="Account-ID" type="first-of"
-                value="Conference-Account-ID|variable_ecallmgr_Account-ID" />
-            <!-- <field name="Account-ID"/> -->
-            <!-- <field name="variable_ecallmgr_Account-ID" as="Account-ID"/> -->
-            
-            <!-- 
-            <field name="Caller-Caller-ID-Name" as="Caller-ID-Name" />
-            <field name="Caller-Caller-ID-Number" as="Caller-ID-Number" />
-            <field name="variable_origination_callee_id_name" as="Callee-ID-Name" />
-            <field name="variable_origination_callee_id_number" as="Callee-ID-Number" />
-            <field name="call-direction" type="reference" />
-            -->
-            
-            <field name="conference-caller-id" type="reference" />
-            
-            <field name="Channel-Presence-ID" />
-            <field name="Member-ID" as="Participant-ID" serialize-as="number" />
-            <field name="Custom-Channel-Vars" type="reference" />
-            <field name="Custom-Application-Vars" type="reference" />
-            <field name="conference-vars" type="reference" />
-            <field name="conference-channel-vars" type="reference" />
-            <field name="conference-bgdial" type="reference" />
-        </definition>
-
-        <definition name="recording_vars">
-            <field name="Recording" type="static" serialize-as="object">
-                <filters>
-                    <filter name="recording" type="include" compare="prefix"
-                        value="Recording-Variable-" />
-                </filters>
-                <fields verbose="false">
-                    <field name="Recording-Variable-" type="prefix" exclude-prefix="true" />
-                </fields>
-            </field>
-        </definition>
-
-        <definition name="recording">
-            <field name="Application-Name" type="static" value="record" />
-            <field name="Application-Response" type="first-of"
-                value="Record-File-Path|kazoo_application_response" />
-          <field name="recording_vars" type="reference" />
-        </definition>
-
-        <definition name="fax_data">
-            <field name="variable_fax_success" as="Fax-Success" serialize-as="boolean" />
-            <field name="variable_has_t38" as="Fax-T38-Used" serialize-as="boolean" />
-            <field name="variable_fax_t38_status" as="Fax-T38-Status" />
-            <field name="variable_fax_ecm_used" as="Fax-ECM-Used" serialize-as="boolean" />
-            <field name="variable_fax_ecm_requested" as="Fax-ECM-Requested" serialize-as="boolean" />
-            <field name="variable_fax_document_transferred_pages" as="Fax-Transferred-Pages" serialize-as="number" />
-            <field name="variable_fax_document_total_pages" as="Fax-Total-Pages" serialize-as="number" />
-            <field name="variable_fax_bad_rows" as="Fax-Bad-Rows" serialize-as="number" />
-            <field name="variable_fax_transfer_rate" as="Fax-Transfer-Rate" serialize-as="number" />
-            <field name="variable_fax_local_station_id" as="Fax-Local-Station-ID" />
-            <field name="variable_fax_remote_station_id" as="Fax-Remote-Station-ID" />
-            <field name="variable_fax_remote_country" as="Fax-Remote-Country" />
-            <field name="variable_fax_remote_vendor" as="Fax-Remote-Vendor" />
-            <field name="variable_fax_remote_model" as="Fax-Remote-Model" />
-            <field name="variable_fax_image_resolution" as="Fax-Image-Resolution" />
-            <field name="variable_fax_file_image_resolution" as="Fax-File-Image-Resolution" />
-            <field name="variable_fax_image_size" as="Fax-Image-Size" serialize-as="number" />
-            <field name="variable_fax_image_pixel_size" as="Fax-Image-Pixel-Size" />
-            <field name="variable_fax_file_image_pixel_size" as="Fax-File-Image-Pixel-Size" />
-            <field name="variable_fax_longest_bad_row_run" as="Fax-Longest-Bad-Row-Run" serialize-as="number" />
-            <field name="variable_fax_encoding" as="Fax-Encoding" />
-            <field name="variable_fax_encoding_name" as="Fax-Encoding-Name" />
-            <field name="variable_fax_timezone" as="Fax-Timezone" />
-            <field name="variable_fax_ident" as="Fax-Identity-Number" />
-            <field name="variable_fax_header" as="Fax-Identity-Name" />
-            <field name="variable_fax_doc_id" as="Fax-Doc-ID" />
-            <field name="variable_fax_doc_database" as="Fax-Doc-DB" />
-
-        </definition>
-
-        <definition name="fax_event">
-            <field name="call_event_headers" type="reference" />
-            <field name="Event-Name" type="static" value="CHANNEL_FAX_STATUS" />
-            <field name="Application-Data" type="static" serialize-as="object">
-                <fields verbose="false">
-                    <field name="fax_data" type="reference" />
-                </fields>
-            </field>
-            <field name="user-agent" as="reference" />
-            <field name="Custom-Channel-Vars" type="reference" />
-            <field name="Custom-Application-Vars" type="reference" />
-        </definition>
-
-        <definition name="voice_dialplan">
-                <field name="fetch-info" type="reference" />
-                <field name="Timestamp" type="expand"
-                    value="${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}"
-                    serialize-as="number" />
-                <field name="Unique-ID" as="Call-ID" />
-                <field name="variable_sip_invite_domain" as="Domain-Name" />
-                <field name="call-direction" type="reference" />
-                <field name="caller-id" type="reference" />
-                <field name="from-network" type="reference" />
-                <field name="user-agent" type="reference" />
-                <field name="from-to" type="reference" />
-                <field name="to-did" type="reference" />
-                <field name="loopback" type="reference" />
-                <field name="sip-tags" type="reference" />
-                <field name="freeswitch-url" type="reference" />
-                <field name="destination-number" type="reference" />
-                <field name="Resource-Type" type="static" value="audio" />
-                <field name="hunt-context" type="reference" />
-                <field name="Call-Setup" type="static" value="true"
-                    serialize-as="boolean" />
-
-                <field name="Event-Category" type="static" value="dialplan" />
-                <field name="Event-Name" type="static" value="route_req" />
-                <field name="Hunt-Context" as="Fetch-Key-Value" />
-        </definition>
-
-    </definitions>
+       <variables>
+               <variable name="UNIX_EPOCH_IN_GREGORIAN" value="62167219200" />
+       </variables>
+
+       <definitions>
+               <definition name="msg-id">
+                       <field name="Event-Date-Timestamp" as="Msg-ID" />
+               </definition>
+
+               <definition name="timestamp">
+                       <field name="Timestamp" type="expand"
+                               value="${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}"
+                               serialize-as="number" />
+               </definition>
+
+               <definition name="call-interaction">
+                       <field name="Call-Interaction" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="variable_Call-Interaction-ID" as="Id" />
+                                       <field name="Key" type="expand"
+                                               value="${regex(${variable_Call-Interaction-ID}|([^-]*)-(.*)|%2)}" />
+                                       <field name="Timestamp" type="expand"
+                                               value="${regex(${variable_Call-Interaction-ID}|([^-]*)-(.*)|%1)}"
+                                               serialize-as="number" />
+                                       <field name="Is-Root" type="expand"
+                                               value="${cond(${variable_Call-Interaction-ID} == ${variable_Original-Call-Interaction-ID} ? true : false)}"
+                                               serialize-as="boolean" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="debug-call">
+                       <filters>
+                               <filter
+                                       name="${first-of(variable_debug_call|Call-Debug|#$${Call-Debug})}"
+                                       type="include" value="true" />
+                       </filters>
+                       <field name="Call-Debug" type="static" serialize-as="object">
+                               <fields verbose="true" />
+                       </field>
+               </definition>
+
+               <definition name="originated-legs">
+                       <filters>
+                               <filter name="variable_originated_legs" type="include"
+                                       compare="exists" />
+                       </filters>
+                       <field name="Other-Legs" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="variable_originated_legs" as="Callee" />
+                                       <field name="variable_originate_causes" as="Causes" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="transfer-history">
+                       <filters>
+                               <filter name="variable_transfer_history" type="include"
+                                       compare="exists" />
+                       </filters>
+                       <field name="Transfer-History" type="expand"
+                               value="${kz_json_history(${variable_transfer_history})}"
+                               serialize-as="raw" />
+               </definition>
+
+               <definition name="transfer-source">
+                       <filters>
+                               <filter name="variable_transfer_source" type="include"
+                                       compare="exists" />
+                       </filters>
+                       <field name="Transfer-Source" type="expand"
+                               value="${kz_json_history(variable_transfer_source)}" serialize-as="raw" />
+               </definition>
+
+               <definition name="interaction-id">
+                       <field name="variable_Call-Interaction-ID" as="Call-Interaction-ID" />
+                       <field name="Call-Interaction-Is-Root" type="static" value="true"
+                               serialize-as="boolean">
+                               <filters>
+                                       <filter name="variable_Call-Interaction-ID" type="include"
+                                               compare="field" value="variable_Original-Call-Interaction-ID" />
+                                       <filter name="${first-of(Event-Subclass|Event-Name|#none)}"
+                                               type="include" compare="list" value="CHANNEL_DESTROY|KZ_CDR" />
+                               </filters>
+                       </field>
+               </definition>
+
+               <definition name="Metaflow-Control">
+                       <field name="Metaflow-Control" type="static" serialize-as="object">
+                               <filters>
+                                       <filter name="ecallmgr" type="include" compare="prefix"
+                                               value="variable_Metaflow-Control-" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_Metaflow-Control-" type="prefix"
+                                               exclude-prefix="true" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="Call-Control">
+                       <field name="Call-Control" type="static" serialize-as="object">
+                               <filters>
+                                       <filter name="ecallmgr" type="include" compare="prefix"
+                                               value="variable_Call-Control-" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_Call-Control-" type="prefix"
+                                               exclude-prefix="true" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="Control">
+                       <field name="Call-Control" type="reference" />
+                       <field name="Metaflow-Control" type="reference" />
+               </definition>
+
+               <definition name="Privacy">
+                       <field name="Privacy" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="Caller-Privacy-Hide-Number" as="Hide-Number"
+                                               serialize-as="boolean" />
+                                       <field name="Caller-Privacy-Hide-Name" as="Hide-Name"
+                                               serialize-as="boolean" />
+                                       <field name="Caller-Screen-Bit" as="Screen-Bit" serialize-as="boolean" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="Custom-Channel-Vars">
+                       <field name="Custom-Channel-Vars" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="X-ecallmgr_" type="prefix" exclude-prefix="true" />
+                                       <field name="variable_sip_h_X-ecallmgr_" type="prefix"
+                                               exclude-prefix="true" />
+                                       <field name="variable_ecallmgr_" type="prefix"
+                                               exclude-prefix="true" />
+
+                                       <field name="Fetch-UUID" as="Fetch-ID" />
+
+                                       <field name="Referred-To" type="expand"
+                                               value="sip:${regex(${url_decode(${variable_sip_refer_to})}|&lt;sips?:(.*)&gt;|%1)}">
+                                               <filters>
+                                                       <filter name="variable_sip_refer_to" type="include"
+                                                               compare="exists" />
+                                               </filters>
+                                       </field>
+                                       <field name="variable_sip_h_Referred-By" as="Referred-By" />
+
+                                       <field name="variable_presence_id" as="Presence-ID" />
+
+                                       <field name="redirect" type="group">
+                                               <filters>
+                                                       <filter name="variable_sip_redirected_by" type="include"
+                                                               compare="exists" />
+                                               </filters>
+                                               <fields verbose="false">
+                                                       <field name="Redirected-By" type="expand"
+                                                               value="sip:${regex(${variable_sip_redirected_by}|&lt;sips?:(.*)&gt;|%1)}" />
+                                                       <field name="Redirected-Reason" type="expand"
+                                                               value="${regex(${variable_sip_redirected_by}|reason=(.*)|%1)}" />
+                                               </fields>
+                                       </field>
+
+                                       <field name="Caller-Privacy-Hide-Number" as="Privacy-Hide-Number"
+                                               serialize-as="boolean" />
+                                       <field name="Caller-Privacy-Hide-Name" as="Privacy-Hide-Name"
+                                               serialize-as="boolean" />
+
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="Custom-Application-Vars">
+                       <field name="Custom-Application-Vars" type="static"
+                               serialize-as="object">
+                               <filters>
+                                       <filter name="ecallmgr" type="include" compare="prefix"
+                                               value="variable_cav_" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_cav_" type="prefix" exclude-prefix="true" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="Custom-SIP-Headers">
+                       <field name="Custom-SIP-Headers" type="static" serialize-as="object">
+                               <filters>
+                                       <filter name="ecallmgr" type="include" compare="prefix"
+                                               value="variable_sip_h_" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_sip_h_" type="prefix" exclude-prefix="true" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="to-did">
+                       <field name="To-DID" type="first-of"
+                               value="variable_ecallmgr_E164-Destination|variable_ecallmgr_Original-Number|Caller-Destination-Number" />
+               </definition>
+
+               <definition name="from-network">
+                       <field name="From-Network-Addr" type="first-of"
+                               value="variable_sip_h_X-AUTH-IP|variable_sip_received_ip" />
+                       <field name="From-Network-Port" type="first-of"
+                               value="variable_sip_h_X-AUTH-PORT|variable_sip_received_port" />
+               </definition>
+
+               <definition name="call-direction">
+                       <field name="Call-Direction" />
+               </definition>
+
+               <definition name="caller-id">
+                       <field name="Caller-ID-Number" type="first-of"
+                               value="variable_origination_caller_id_number|variable_effective_caller_id_number|Caller-Caller-ID-Number" />
+                       <field name="Caller-ID-Name" type="first-of"
+                               value="variable_origination_caller_id_name|variable_effective_caller_id_name|Caller-Caller-ID-Name" />
+                       <field name="Callee-ID-Number" type="first-of"
+                               value="variable_origination_callee_id_number|variable_effective_callee_id_number|Caller-Callee-ID-Number|Other-Leg-Caller-ID-Number" />
+                       <field name="Callee-ID-Name" type="first-of"
+                               value="variable_origination_callee_id_name|variable_effective_callee_id_name|Caller-Callee-ID-Name|Other-Leg-Caller-ID-Name" />
+               </definition>
+
+               <definition name="other-leg">
+                       <field name="Other-Leg-Direction" />
+                       <field name="Other-Leg-Caller-ID-Name" />
+                       <field name="Other-Leg-Caller-ID-Number" />
+                       <field name="Other-Leg-Destination-Number" />
+                       <field name="Other-Leg-Call-ID" type="first-of"
+                               value="Other-Leg-Unique-ID|Other-Leg-Call-ID|variable_origination_uuid" />
+               </definition>
+
+               <definition name="application">
+                       <field name="Application-Name" type="first-of"
+                               value="Application-UUID-Name|kazoo_application_name|Application|Event-Subclass" />
+                       <field name="Application-Response" type="first-of"
+                               value="kazoo_application_response|Application-Response" />
+               </definition>
+
+               <definition name="raw-application">
+                       <field name="Raw-Application-Name" type="first-of"
+                               value="kazoo_application_name|Application|Event-Subclass" />
+                       <field name="Application-Data" as="Raw-Application-Data" />
+               </definition>
+
+               <definition name="application-all">
+                       <field name="raw-application" type="reference" />
+                       <field name="application" type="reference" />
+               </definition>
+
+               <definition name="application-uuid">
+                       <field name="application-all" type="reference" />
+                       <field name="Application-UUID" type="first-of"
+                               value="app_uuid|variable_app_uuid|Application-UUID" />
+               </definition>
+
+               <definition name="Switch-URI">
+                       <field name="variable_Switch-URI" as="Switch-URI" />
+               </definition>
+
+               <definition name="freeswitch-url">
+                       <field name="FreeSWITCH-Hostname" as="Media-Server" />
+                       <field name="FreeSWITCH-Hostname" as="Switch-Hostname" />
+                       <field name="Switch-Nodename" />
+                       <field name="variable_Switch-URL" as="Switch-URL" />
+                       <field name="Switch-URI" type="reference" />
+               </definition>
+
+               <definition name="loopback">
+                       <field name="variable_is_loopback" as="Channel-Is-Loopback"
+                               serialize-as="boolean" />
+                       <field name="Loopback" type="group">
+                               <filters>
+                                       <filter name="variable_is_loopback" type="include" compare="value"
+                                               value="1" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_loopback_leg" as="Channel-Loopback-Leg" />
+                                       <field name="variable_other_loopback_leg_uuid" as="Channel-Loopback-Other-Leg-ID" />
+                                       <field name="variable_loopback_bowout" as="Channel-Loopback-Bowout"
+                                               serialize-as="boolean" />
+                                       <field name="variable_loopback_bowout_on_execute" as="Channel-Loopback-Bowout-Execute"
+                                               serialize-as="boolean" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="caller-context">
+                       <field name="variable_sofia_profile_name" as="Caller-Profile" />
+                       <field name="Caller-Context" />
+                       <field name="Caller-Dialplan" />
+                       <field name="Caller-Destination-Number" />
+               </definition>
+
+               <definition name="hunt-context">
+                       <field name="variable_sofia_profile_name" as="Hunt-Profile" />
+                       <field name="Hunt-Context" />
+                       <field name="Hunt-Dialplan" />
+                       <field name="Hunt-Destination-Number" />
+                       <field name="Request" type="expand"
+                               value="${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
+                       <field name="To" type="expand"
+                               value="${Hunt-Destination-Number}@${first-of(variable_sip_invite_domain|variable_sip_to_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
+                       <field name="From" type="expand"
+                               value="${first-of(Hunt-Caller-ID-Number|origination_callee_id_number|variable_sip_from_user)}@${first-of(variable_sip_invite_domain|variable_sip_from_host|variable_sip_req_host|variable_ecallmgr_Realm)}" />
+               </definition>
+
+               <definition name="sip-tags">
+                       <field name="variable_sip_to_tag" as="To-Tag" />
+                       <field name="variable_sip_from_tag" as="From-Tag" />
+               </definition>
+
+               <definition name="channel-state">
+                       <!-- erlang strips CS_ from beginning, lets do that -->
+                       <field name="Channel-State" type="expand"
+                               value="${regex(${Channel-State}|^CS_(.*)$|%1)}" />
+                       <field name="Channel-Call-State" />
+                       <field name="Channel-Name" />
+                       <field name="Answer-State" />
+               </definition>
+
+               <definition name="presence-id">
+                       <field name="variable_presence_id" as="Presence-ID" />
+               </definition>
+
+
+               <definition name="call_event_headers">
+                       <field name="Event-Category" type="static" value="call_event" />
+                       <field name="Event-Name" type="first-of"
+                               value="kazoo_event_name|Event-Subclass|Event-Name" />
+                       <field name="Event-Date-Timestamp" as="Msg-ID" />
+                       <field name="Timestamp" type="expand"
+                               value="${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}"
+                               serialize-as="number" />
+                       <field name="variable_sip_origination_call_uuid" as="Origination-Call-ID" />
+                       <field name="Call-ID" type="first-of"
+                               value="Unique-ID|Caller-Unique-ID|caller-unique-id" />
+                       <field name="Caller-Channel-Created-Time" as="Channel-Created-Time" />
+
+                       <field name="Switch-Nodename" as="Node" />
+
+                       <field name="variable_sip_invite_domain" as="Domain-Name" />
+                       <field name="App-Name" type="static" value="freeswitch" />
+                       <field name="App-Version" type="static" value="1.0" />
+               </definition>
+
+               <definition name="user-agent">
+                       <field name="variable_sip_user_agent" as="User-Agent" />
+               </definition>
+
+
+               <definition name="call_event">
+                       <field name="call_event_headers" type="reference" />
+                       <field name="application-all" type="reference" />
+                       <field name="call-direction" type="reference" />
+                       <field name="channel-state" type="reference" />
+                       <field name="caller-id" type="reference" />
+                       <field name="caller-context" type="reference" />
+                       <field name="sip-tags" type="reference" />
+                       <field name="presence-id" type="reference" />
+                       <field name="loopback" type="reference" />
+                       <field name="freeswitch-url" type="reference" />
+                       <field name="other-leg" type="reference" />
+                       <field name="user-agent" type="reference" />
+                       <field name="Custom-Channel-Vars" type="reference" />
+                       <field name="Custom-Application-Vars" type="reference" />
+                       <field name="Control" type="reference" />
+                       <field name="debug-call" type="reference" />
+               </definition>
+
+               <definition name="fetch-info">
+                       <field name="Event-Category" type="static" value="fetch" />
+                       <field name="App-Name" type="static" value="freeswitch" />
+                       <field name="App-Version" type="static" value="1.0" />
+                       <field name="Switch-Nodename" as="Node" />
+                       <field name="Fetch-UUID" />
+                       <field name="Fetch-UUID" as="Msg-ID" />
+                       <field name="Call-ID" type="first-of" value="Unique-ID" />
+                       <field name="Fetch-Section" />
+                       <field name="Fetch-Timeout" />
+                       <field name="Fetch-Timestamp-Micro" />
+                       <field name="Kazoo-Bundle" as="Fetch-Version" />
+                       <field name="Custom-SIP-Headers" type="reference" />
+                       <field name="Custom-Channel-Vars" type="reference" />
+                       <field name="Custom-Application-Vars" type="reference" />
+                       <field name="freeswitch-url" type="reference" />
+                       <field name="Control" type="reference" />
+                       <field name="Privacy" type="reference" />
+                       <field name="debug-call" type="reference" />
+
+               </definition>
+
+               <definition name="destination-number">
+                       <field name="Destination-Number" type="first-of"
+                               value="Hunt-Destination-Number|Caller-Destination-Number" />
+               </definition>
+
+               <definition name="from-to">
+                       <field name="Request" type="first-of"
+                               value="variable_sip_req_uri|variable_sip_loopback_req_uri|variable_sip_to_uri" />
+                       <field name="To" type="first-of"
+                               value="variable_sip_to_uri|variable_sip_req_uri|variable_sip_loopback_req_uri" />
+                       <field name="variable_sip_to_uri" as="To-URI" />
+                       <field name="From" type="first-of"
+                               value="variable_sip_from_uri|variable_presence_id|variable_sip_loopback_from_uri" />
+                       <field name="variable_sip_from_uri" as="From-URI" />
+               </definition>
+
+               <definition name="sdp">
+                       <field name="variable_switch_r_sdp" as="Remote-SDP" />
+                       <field name="variable_rtp_local_sdp_str" as="Local-SDP" />
+               </definition>
+
+               <definition name="call-duration">
+                       <field name="variable_duration" as="Duration-Seconds"
+                               serialize-as="number" />
+                       <field name="variable_progresssec" as="Ringing-Seconds"
+                               serialize-as="number" />
+                       <field name="Billing-Seconds" type="expand"
+                               value="${expr(ceil(${variable_billmsec} / 1000))}" serialize-as="number" />
+               </definition>
+
+               <definition name="hangup-disposition">
+                       <field name="Disposition" type="first-of"
+                               value="variable_originate_disposition|variable_endpoint_disposition" />
+               </definition>
+
+               <definition name="hangup-code">
+                       <field name="Hangup-Code" type="first-of"
+                               value="variable_proto_specific_hangup_cause|variable_last_bridge_proto_specific_hangup_cause" />
+               </definition>
+
+               <definition name="hangup-cause">
+                       <field name="Hangup-Cause" type="first-of"
+                               value="variable_originate_failed_cause|variable_bridge_hangup_cause|variable_hangup_cause|Hangup-Cause">
+                               <filters>
+                                       <filter name="variable_current_application" type="include"
+                                               compare="value" value="bridge" />
+                               </filters>
+                       </field>
+                       <field name="Hangup-Cause" type="first-of"
+                               value="variable_originate_failed_cause|variable_hangup_cause|variable_bridge_hangup_cause|Hangup-Cause">
+                               <filters>
+                                       <filter name="variable_current_application" type="exclude"
+                                               compare="value" value="bridge" />
+                               </filters>
+                       </field>
+               </definition>
+
+               <definition name="hangup-fields">
+                       <field name="hangup-code" type="reference" />
+                       <field name="hangup-cause" type="reference" />
+                       <field name="hangup-disposition" type="reference" />
+               </definition>
+
+               <definition name="conference-caller-id">
+                       <field name="CONF-CALLER-ID-IN" type="group">
+                               <filters>
+                                       <filter name="Call-Direction" type="include" compare="value"
+                                               value="inbound" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="Caller-Caller-ID-Name" as="Caller-ID-Name" />
+                                       <field name="Caller-Caller-ID-Number" as="Caller-ID-Number" />
+                               </fields>
+                       </field>
+                       <field name="CONF-CALLER-ID-OUT" type="group">
+                               <filters>
+                                       <filter name="Call-Direction" type="include" compare="value"
+                                               value="outbound" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="variable_origination_callee_id_name" as="Caller-ID-Name" />
+                                       <field name="variable_origination_callee_id_number" as="Caller-ID-Number" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="conference-bgdial">
+                       <field name="Dial-Result" type="static" serialize-as="object">
+                               <filters>
+                                       <filter name="Action" type="include" compare="value" value="bgdial-result" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="Result" />
+                                       <field name="Job-UUID" />
+                                       <field name="Peer-UUID" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="conference-vars">
+                       <field name="Conference-Vars" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="Conference-" type="prefix" exclude-prefix="true" />
+                                       <field name="Account-ID" type="first-of"
+                                               value="Account-ID|Conference-Account-ID|variable_ecallmgr_Account-ID" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="conference-channel-vars">
+                       <field name="Conference-Channel-Vars" type="static"
+                               serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="variable_conference_moderator" as="Is-Moderator"
+                                               serialize-as="boolean" />
+                                       <field name="Floor" serialize-as="boolean" />
+                                       <field name="Video" serialize-as="boolean" />
+                                       <field name="See" serialize-as="boolean" />
+                                       <field name="Speak" serialize-as="boolean" />
+                                       <field name="Hear" serialize-as="boolean" />
+                                       <field name="Talking" serialize-as="boolean" />
+                                       <field name="Mute-Detect" serialize-as="boolean" />
+
+                                       <field name="Energy-Level" serialize-as="number" />
+                                       <field name="Current-Energy" serialize-as="number" />
+                                       <field name="Member-ID" serialize-as="number" />
+
+                                       <field name="Member-Ghost" serialize-as="boolean" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="conference-event">
+                       <field name="Event-Category" type="static" value="conference" />
+                       <field name="Event-Name" type="static" value="event" />
+                       <field name="Switch-Nodename" as="Node" />
+                       <field name="Core-UUID" />
+                       <field name="freeswitch-url" type="reference" />
+                       <field name="App-Name" type="static" value="freeswitch" />
+                       <field name="App-Version" type="static" value="1.0" />
+                       <field name="Action" as="Event" />
+                       <field name="Conference-Name" as="Conference-ID" />
+                       <field name="Conference-Unique-ID" as="Instance-ID" />
+                       <field name="Conference-Node" />
+                       <field name="Conference-Profile" as="Profile" />
+                       <field name="Unique-ID" as="Call-ID" />
+                       <field name="Account-ID" type="first-of"
+                               value="Conference-Account-ID|variable_ecallmgr_Account-ID" />
+
+                       <field name="conference-caller-id" type="reference" />
+
+                       <field name="Channel-Presence-ID" />
+                       <field name="Member-ID" as="Participant-ID" serialize-as="number" />
+                       <field name="Custom-Channel-Vars" type="reference" />
+                       <field name="Custom-Application-Vars" type="reference" />
+                       <field name="conference-vars" type="reference" />
+                       <field name="conference-channel-vars" type="reference" />
+                       <field name="conference-bgdial" type="reference" />
+               </definition>
+
+               <definition name="recording_vars">
+                       <field name="Recording" type="static" serialize-as="object">
+                               <filters>
+                                       <filter name="recording" type="include" compare="prefix"
+                                               value="Recording-Variable-" />
+                               </filters>
+                               <fields verbose="false">
+                                       <field name="Recording-Variable-" type="prefix"
+                                               exclude-prefix="true" />
+                               </fields>
+                       </field>
+               </definition>
+
+               <definition name="recording">
+                       <field name="Application-Name" type="static" value="record" />
+                       <field name="Application-Response" type="first-of"
+                               value="Record-File-Path|kazoo_application_response" />
+                       <field name="recording_vars" type="reference" />
+               </definition>
+
+               <definition name="fax_data">
+                       <field name="variable_fax_success" as="Fax-Success"
+                               serialize-as="boolean" />
+                       <field name="variable_has_t38" as="Fax-T38-Used" serialize-as="boolean" />
+                       <field name="variable_fax_t38_status" as="Fax-T38-Status" />
+                       <field name="variable_fax_ecm_used" as="Fax-ECM-Used"
+                               serialize-as="boolean" />
+                       <field name="variable_fax_ecm_requested" as="Fax-ECM-Requested"
+                               serialize-as="boolean" />
+                       <field name="variable_fax_document_transferred_pages" as="Fax-Transferred-Pages"
+                               serialize-as="number" />
+                       <field name="variable_fax_document_total_pages" as="Fax-Total-Pages"
+                               serialize-as="number" />
+                       <field name="variable_fax_bad_rows" as="Fax-Bad-Rows"
+                               serialize-as="number" />
+                       <field name="variable_fax_transfer_rate" as="Fax-Transfer-Rate"
+                               serialize-as="number" />
+                       <field name="variable_fax_local_station_id" as="Fax-Local-Station-ID" />
+                       <field name="variable_fax_remote_station_id" as="Fax-Remote-Station-ID" />
+                       <field name="variable_fax_remote_country" as="Fax-Remote-Country" />
+                       <field name="variable_fax_remote_vendor" as="Fax-Remote-Vendor" />
+                       <field name="variable_fax_remote_model" as="Fax-Remote-Model" />
+                       <field name="variable_fax_image_resolution" as="Fax-Image-Resolution" />
+                       <field name="variable_fax_file_image_resolution" as="Fax-File-Image-Resolution" />
+                       <field name="variable_fax_image_size" as="Fax-Image-Size"
+                               serialize-as="number" />
+                       <field name="variable_fax_image_pixel_size" as="Fax-Image-Pixel-Size" />
+                       <field name="variable_fax_file_image_pixel_size" as="Fax-File-Image-Pixel-Size" />
+                       <field name="variable_fax_longest_bad_row_run" as="Fax-Longest-Bad-Row-Run"
+                               serialize-as="number" />
+                       <field name="variable_fax_encoding" as="Fax-Encoding" />
+                       <field name="variable_fax_encoding_name" as="Fax-Encoding-Name" />
+                       <field name="variable_fax_timezone" as="Fax-Timezone" />
+                       <field name="variable_fax_ident" as="Fax-Identity-Number" />
+                       <field name="variable_fax_header" as="Fax-Identity-Name" />
+                       <field name="variable_fax_doc_id" as="Fax-Doc-ID" />
+                       <field name="variable_fax_doc_database" as="Fax-Doc-DB" />
+
+               </definition>
+
+               <definition name="fax_event">
+                       <field name="call_event_headers" type="reference" />
+                       <field name="Event-Name" type="static" value="CHANNEL_FAX_STATUS" />
+                       <field name="Application-Data" type="static" serialize-as="object">
+                               <fields verbose="false">
+                                       <field name="fax_data" type="reference" />
+                               </fields>
+                       </field>
+                       <field name="user-agent" as="reference" />
+                       <field name="Custom-Channel-Vars" type="reference" />
+                       <field name="Custom-Application-Vars" type="reference" />
+               </definition>
+
+               <definition name="voice_dialplan">
+                       <field name="fetch-info" type="reference" />
+                       <field name="Timestamp" type="expand"
+                               value="${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}"
+                               serialize-as="number" />
+                       <field name="Unique-ID" as="Call-ID" />
+                       <field name="variable_sip_invite_domain" as="Domain-Name" />
+                       <field name="call-direction" type="reference" />
+                       <field name="caller-id" type="reference" />
+                       <field name="from-network" type="reference" />
+                       <field name="user-agent" type="reference" />
+                       <field name="from-to" type="reference" />
+                       <field name="to-did" type="reference" />
+                       <field name="loopback" type="reference" />
+                       <field name="sip-tags" type="reference" />
+                       <field name="freeswitch-url" type="reference" />
+                       <field name="destination-number" type="reference" />
+                       <field name="Resource-Type" type="static" value="audio" />
+                       <field name="hunt-context" type="reference" />
+                       <field name="Call-Setup" type="static" value="true"
+                               serialize-as="boolean" />
+
+                       <field name="Event-Category" type="static" value="dialplan" />
+                       <field name="Event-Name" type="static" value="route_req" />
+                       <field name="Hunt-Context" as="Fetch-Key-Value" />
+               </definition>
+
+       </definitions>
 
 
        <event-handlers>
                                        <fields verbose="false">
                                                <field name="call_event" type="reference" />
                                                <field name="from-to" type="reference" />
-                        <field name="other-leg" type="reference" />
+                                               <field name="other-leg" type="reference" />
                                                <field name="sdp" type="reference" />
                                                <field name="call-duration" type="reference" />
                                                <field name="hangup-fields" type="reference" />
                                                <field name="variable_Media-Recordings" as="Media-Recordings" />
                                                <field name="debug-call" type="reference" />
-                        <field name="transfer-history" type="reference" />
-                        <field name="originated-legs" type="reference" />
-                                               
+                                               <field name="transfer-history" type="reference" />
+                                               <field name="originated-legs" type="reference" />
+
                                        </fields>
                                        <filters>
                                                <filter name="variable_hangup_cause" type="exclude"
 
                                </event>
 
-                <event name="CHANNEL_PROGRESS">
-                    <fields verbose="false">
-                        <field name="call_event" type="reference" />
-                        <field name="from-to" type="reference" />
-                        <field name="debug-call" type="reference" />
-                    </fields>
-                </event>
+                               <event name="CHANNEL_PROGRESS">
+                                       <fields verbose="false">
+                                               <field name="call_event" type="reference" />
+                                               <field name="from-to" type="reference" />
+                                               <field name="debug-call" type="reference" />
+                                       </fields>
+                               </event>
 
                                <event name="CHANNEL_PROGRESS_MEDIA">
                                        <fields verbose="false">
                                        <fields verbose="false">
                                                <field name="call_event" type="reference" />
                                                <field name="Event-Name" type="static" value="CHANNEL_TRANSFEROR" />
-                                               <!-- <field name="Intercepted-By" type="first-of" value="variable_intercepted_by|intercepted_by"/> -->
                                        </fields>
 
                                        <routing-key>
                                        <fields verbose="false">
                                                <field name="call_event" type="reference" />
                                                <field name="Event-Name" type="static" value="CHANNEL_TRANSFEREE" />
-                                               <!-- <field name="Intercepted-By" type="first-of" value="variable_intercepted_by|intercepted_by"/> -->
                                        </fields>
 
                                        <routing-key>
                                </event>
 
                                <event name="conference::maintenance">
-                               <!-- 
-                                       <filters>
-                                               <filter name="Action" type="include" compare="list"
-                                                       value="conference-create|conference-destroy|lock|unlock|add-member|del-member|start-talking|stop-talking|mute-member|unmute-member|deaf-member|undeaf-member" />
-                                       </filters>
-                           -->
                                        <fields verbose="false">
                                                <field name="conference-event" type="reference" />
-                                               <!-- <field name="create-group" type="group"> <filters> <filter name="Action" 
-                                                       type="include" compare="value" value="conference-create" /> </filters> <fields 
-                                                       verbose="false"> <field name="variable_ecallmgr_Ecallmgr-Node" as="Conference-Node" 
-                                                       /> <field name="Conference-Profile-Name" as="Profile" /> </fields> </field> -->
                                        </fields>
                                </event>
 
                                </event>
 
                                <event name="kazoo::masquerade">
-                               <!-- 
-                                       <filters>
-                                               <filter type="exclude" name="kazoo_event_name" compare="value"
-                                                       value="CHANNEL_EXECUTE_COMPLETE" />
-                                       </filters>
-                           -->
                                        <fields verbose="false">
                                                <field name="call_event" type="reference" />
                                                <field name="application-uuid" type="reference" />
                                                        value="variable_endpoint_disposition|variable_originate_disposition|#FAIL" />
                                                <field name="Disposition" type="first-of"
                                                        value="variable_originate_disposition|variable_endpoint_disposition" />
-                        <field name="Bridge-Hangup-Cause" type="first-of" value="variable_bridge_hangup_cause|variable_last_bridge_hangup_cause" />
-                        <field name="variable_endpoint_disposition" as="Endpoint-Disposition" />
-                        <field name="variable_transfer_disposition" as="Transfer-Disposition" />
+                                               <field name="Bridge-Hangup-Cause" type="first-of"
+                                                       value="variable_bridge_hangup_cause|variable_last_bridge_hangup_cause" />
+                                               <field name="variable_endpoint_disposition" as="Endpoint-Disposition" />
+                                               <field name="variable_transfer_disposition" as="Transfer-Disposition" />
                                        </fields>
                                </event>
 
                                <event name="CHANNEL_EXECUTE_COMPLETE">
                                        <filters>
-                        <filter type="exclude" compare="value"
-                            name="Application-UUID" value="null" />
+                                               <filter type="exclude" compare="value" name="Application-UUID"
+                                                       value="null" />
                                                <filter type="include" compare="exists"
                                                        name="variable_Call-Control-Queue" />
-                        <filter type="include" compare="exists"
-                            name="Application-UUID-Name" />
-                        <filter type="exclude" name="Application-UUID-Name" value="set" />
+                                               <filter type="include" compare="exists" name="Application-UUID-Name" />
+                                               <filter type="exclude" name="Application-UUID-Name" value="set" />
                                                <filter type="exclude" name="Application" value="set" />
-                        <filter name="Application" value="park" />
-                        <filter name="Application" value="export" />
-                        <filter name="Application" value="event" />
-                        <filter name="Application" value="unshift" />
-                        <filter name="Application" value="kz_multiset" />
-                        <filter name="Application" value="kz_multiunset" />
-                        <filter name="Application" value="kz_prefix_unset" />
-                        <filter name="Application" value="kz_export" />
-                        <filter name="Application" value="ring_ready" />
-                        <filter name="Application" value="log" />
-                        <filter name="Application" value="execute_extension" />
-                        <filter name="Application" value="bridge" />
+                                               <filter name="Application" value="park" />
+                                               <filter name="Application" value="export" />
+                                               <filter name="Application" value="event" />
+                                               <filter name="Application" value="unshift" />
+                                               <filter name="Application" value="kz_multiset" />
+                                               <filter name="Application" value="kz_multiunset" />
+                                               <filter name="Application" value="kz_prefix_unset" />
+                                               <filter name="Application" value="kz_export" />
+                                               <filter name="Application" value="ring_ready" />
+                                               <filter name="Application" value="log" />
+                                               <filter name="Application" value="execute_extension" />
+                                               <filter name="Application" value="bridge" />
                                        </filters>
 
                                        <fields verbose="false">
                                                        value="Application-Response|variable_originate_disposition|variable_endpoint_disposition|#NONE" />
                                                <field name="Disposition" type="first-of"
                                                        value="variable_originate_disposition|variable_endpoint_disposition" />
-                                               <field name="Bridge-Hangup-Cause" type="first-of" value="variable_bridge_hangup_cause|variable_last_bridge_hangup_cause" />
-                        <field name="variable_endpoint_disposition" as="Endpoint-Disposition" />
-                        <field name="variable_transfer_disposition" as="Transfer-Disposition" />
-                                               
+                                               <field name="Bridge-Hangup-Cause" type="first-of"
+                                                       value="variable_bridge_hangup_cause|variable_last_bridge_hangup_cause" />
+                                               <field name="variable_endpoint_disposition" as="Endpoint-Disposition" />
+                                               <field name="variable_transfer_disposition" as="Transfer-Disposition" />
+
                                                <field name="debug-call" type="reference" />
                                        </fields>
 
                                                <field name="fax_event" type="reference" />
                                                <field name="Application-Name" type="static" value="send_fax" />
                                                <field name="Application-Event" type="static" value="negociateresult" />
-                                               <field name="Call-ID" type="first-of" value="variable_sip_origination_call_uuid|Unique-ID" />
+                                               <field name="Call-ID" type="first-of"
+                                                       value="variable_sip_origination_call_uuid|Unique-ID" />
                                        </fields>
 
                                </event>
                                                <field name="fax_event" type="reference" />
                                                <field name="Application-Name" type="static" value="send_fax" />
                                                <field name="Application-Event" type="static" value="pageresult" />
-                        <field name="Call-ID" type="first-of" value="variable_sip_origination_call_uuid|Unique-ID" />
+                                               <field name="Call-ID" type="first-of"
+                                                       value="variable_sip_origination_call_uuid|Unique-ID" />
                                        </fields>
 
                                </event>
                                                <field name="fax_event" type="reference" />
                                                <field name="Application-Name" type="static" value="send_fax" />
                                                <field name="Application-Event" type="static" value="result" />
-                        <field name="Call-ID" type="first-of" value="variable_sip_origination_call_uuid|Unique-ID" />
+                                               <field name="Call-ID" type="first-of"
+                                                       value="variable_sip_origination_call_uuid|Unique-ID" />
                                        </fields>
 
                                </event>
                                </event>
 
                                <event name="CHANNEL_DATA">
-                                   <filters>
-                        <filter type="exclude" compare="exists" name="API-Command" />
-                    </filters>
+                                       <filters>
+                                               <filter type="exclude" compare="exists" name="API-Command" />
+                                       </filters>
                                        <fields verbose="true">
                                                <field name="call_event" type="reference" />
                                        </fields>
 
                                <event name="loopback::bowout">
                                        <fields verbose="true">
-                        <!-- <field name="call_event_headers" type="reference" /> -->
-                        <field name="call_event" type="reference" />
-                        <field name="Event-Name" type="static" value="CHANNEL_REPLACED"/>                    
-                        <field name="Resigning-UUID" as="Call-ID"/>
-                        <field name="Resigning-UUID"/>
-                        <field name="Resigning-Peer-UUID"/>
-                        <field name="Acquired-UUID"/>
-                        <field name="Acquired-UUID" as="Replaced-By"/>
+                                               <field name="call_event" type="reference" />
+                                               <field name="Event-Name" type="static" value="CHANNEL_REPLACED" />
+                                               <field name="Resigning-UUID" as="Call-ID" />
+                                               <field name="Resigning-UUID" />
+                                               <field name="Resigning-Peer-UUID" />
+                                               <field name="Acquired-UUID" />
+                                               <field name="Acquired-UUID" as="Replaced-By" />
                                        </fields>
                                </event>
 
-                <event name="loopback::direct">
-                    <fields verbose="true">
-                        <!-- <field name="call_event_headers" type="reference" /> -->
-                        <field name="call_event" type="reference" />
-                        <field name="Event-Name" type="static" value="CHANNEL_DIRECT"/>
-                        <field name="Resigning-UUID" as="Call-ID"/>
-                        <field name="Resigning-UUID"/>
-                        <field name="Resigning-Peer-UUID"/>
-                        <field name="Acquired-UUID"/>
-                        <field name="Acquired-UUID" as="Replaced-By"/>
-                        <field name="Connecting-Leg-A-UUID" />
-                        <field name="Connecting-Leg-B-UUID" />
-                    </fields>
-                </event>
+                               <event name="loopback::direct">
+                                       <fields verbose="true">
+                                               <field name="call_event" type="reference" />
+                                               <field name="Event-Name" type="static" value="CHANNEL_DIRECT" />
+                                               <field name="Resigning-UUID" as="Call-ID" />
+                                               <field name="Resigning-UUID" />
+                                               <field name="Resigning-Peer-UUID" />
+                                               <field name="Acquired-UUID" />
+                                               <field name="Acquired-UUID" as="Replaced-By" />
+                                               <field name="Connecting-Leg-A-UUID" />
+                                               <field name="Connecting-Leg-B-UUID" />
+                                       </fields>
+                               </event>
 
                                <event name="HEARTBEAT">
                                        <fields verbose="true">
                                        </fields>
                                </event>
 
-                <event name="CHANNEL_METAFLOW">
-                    <fields verbose="false">
-                        <field name="call_event" type="reference" />
-                               <field name="from-to" type="reference" />                        
-                        <field name="user-agent" type="reference" />
-                        <field name="Metaflow-Collected-Digits"/>
-                    </fields>
-                </event>
+                               <event name="CHANNEL_METAFLOW">
+                                       <fields verbose="false">
+                                               <field name="call_event" type="reference" />
+                                               <field name="from-to" type="reference" />
+                                               <field name="user-agent" type="reference" />
+                                               <field name="Metaflow-Collected-Digits" />
+                                       </fields>
+                               </event>
+
+                               <event name="KZ_CDR">
+                                       <fields verbose="false">
+                                               <field name="Event-Category" type="static" value="cdr" />
+                                               <field name="Event-Name" type="static" value="report" />
+                                               <field name="msg-id" type="reference" />
+                                               <field name="App-Name" type="static" value="freeswitch" />
+                                               <field name="App-Version" type="static" value="1.0" />
+                                               <field name="timestamp" type="reference" />
+                                               <field name="Unique-ID" as="Call-ID" />
+                                               <field name="Caller-Channel-Created-Time" as="Channel-Created-Time"
+                                                       serialize-as="number" />
+                                               <field name="Core-UUID" as="Node" />
+                                               <field name="variable_domain_name" as="Domain-Name" />
+                                               <field name="variable_ecallmgr_Account-ID" as="Account-ID" />
+                                               <field name="call-interaction" type="reference" />
+                                               <field name="call-direction" type="reference" />
+                                               <field name="channel-state" type="reference" />
+                                               <field name="caller-id" type="reference" />
+                                               <field name="caller-context" type="reference" />
+                                               <field name="sip-tags" type="reference" />
+                                               <field name="presence-id" type="reference" />
+                                               <field name="loopback" type="reference" />
+                                               <field name="freeswitch-url" type="reference" />
+                                               <field name="user-agent" type="reference" />
+                                               <field name="Custom-Channel-Vars" type="reference" />
+                                               <field name="Custom-Application-Vars" type="reference" />
+                                               <field name="Control" type="reference" />
+                                               <field name="from-to" type="reference" />
+                                               <field name="other-leg" type="reference" />
+                                               <field name="sdp" type="reference" />
+                                               <field name="call-duration" type="reference" />
+                                               <field name="hangup-fields" type="reference" />
+                                               <field name="variable_Media-Recordings" as="Media-Recordings"
+                                                       as-array="true" />
+                                               <field name="transfer-history" type="reference" />
+                                               <field name="originated-legs" type="reference" />
+                                               <field name="Extended-Data" type="static" serialize-as="object">
+                                                       <fields verbose="false">
+                                                               <field name="_json_callflow" as="Channel-CallFlow"
+                                                                       serialize-as="raw" />
+                                                               <field name="_json_channel_stats" as="Channel-Stats"
+                                                                       serialize-as="raw" />
+                                                               <field name="_json_application_log" as="Channel-Application-Log"
+                                                                       serialize-as="raw" />
+                                                       </fields>
+                                               </field>
+                                               <field name="debug-call" type="reference" />
+                                       </fields>
+                                       <filters>
+                                               <filter name="${variable_Call-Control-Node}" type="include"
+                                                       compare="field" value="Target-Node" />
+                                               <filter name="variable_hangup_cause" type="exclude"
+                                                       compare="value" value="CALL_REJECTED" />
+                                               <filter name="variable_hangup_cause" type="exclude"
+                                                       compare="value" value="WRONG_CALL_STATE" />
+                                       </filters>
+                               </event>
 
                        </events>
                </profile>
 
                <profile name="dialplan" profile-type="fetch">
 
-            <fields verbose="false">
-                <field name="voice_dialplan" type="reference" />
-                <field name="debug-call" type="reference" />
-            </fields>
+                       <fields verbose="false">
+                               <field name="voice_dialplan" type="reference" />
+                               <field name="debug-call" type="reference" />
+                       </fields>
 
                        <params>
                                <param name="fetch-timeout" value="3500000" />
index 955ff5c64eff1d807e2f4608ddb6e1cb54153a5d..180f3e3d48677848039b0ec1bb8caa30542abf93 100644 (file)
@@ -175,7 +175,6 @@ static switch_status_t api_erlang_event_filter(switch_stream_handle_t *stream) {
 
        if (++column > 2) {
                stream->write_function(stream, "\n");
-               column = 0;
        }
 
        while(kazoo_globals.kazoo_var_prefixes[idx] != NULL) {
diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_cdr.c b/src/mod/event_handlers/mod_kazoo/kazoo_cdr.c
new file mode 100644 (file)
index 0000000..f7b0d53
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2012, 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):
+ *
+ * Luis Azedo <luis@2600hz.com>
+ *
+ * mod_hacks.c -- hacks with state handlers
+ *
+ */
+#include "mod_kazoo.h"
+
+#define MY_EVENT_JSON_CDR "KZ_CDR"
+
+#define maybe_add_json_string(_json, _name, _string) \
+       if (!zstr(_string)) cJSON_AddItemToObject(_json, _name, cJSON_CreateString((char *)_string))
+
+static void kz_switch_ivr_set_json_profile_data(cJSON *json, switch_caller_profile_t *caller_profile)
+{
+       cJSON *soft = NULL;
+       profile_node_t *pn = NULL;
+
+       maybe_add_json_string(json, "Username", caller_profile->username);
+       maybe_add_json_string(json, "Dialplan", caller_profile->dialplan);
+       maybe_add_json_string(json, "ANI", caller_profile->ani);
+       maybe_add_json_string(json, "ANIII", caller_profile->aniii);
+       maybe_add_json_string(json, "Caller-ID-Name", caller_profile->caller_id_name);
+       maybe_add_json_string(json, "Caller-ID-Number", caller_profile->caller_id_number);
+       maybe_add_json_string(json, "Caller-ID-Original-Name", caller_profile->orig_caller_id_name);
+       maybe_add_json_string(json, "Caller-ID-Original-Number", caller_profile->orig_caller_id_number);
+       maybe_add_json_string(json, "Network-Address", caller_profile->network_addr);
+       maybe_add_json_string(json, "RDNIS", caller_profile->rdnis);
+       maybe_add_json_string(json, "Destination-Number", caller_profile->destination_number);
+       maybe_add_json_string(json, "Callee-ID-Name", caller_profile->callee_id_name);
+       maybe_add_json_string(json, "Callee-ID-Number", caller_profile->callee_id_number);
+       maybe_add_json_string(json, "UUID", caller_profile->uuid);
+       maybe_add_json_string(json, "Source", caller_profile->source);
+       maybe_add_json_string(json, "Context", caller_profile->context);
+       maybe_add_json_string(json, "Channel-Name", caller_profile->chan_name);
+       maybe_add_json_string(json, "Profile-UUID", caller_profile->uuid_str);
+       maybe_add_json_string(json, "Profile-Clone-Of", caller_profile->clone_of);
+       maybe_add_json_string(json, "Transfer-Source", caller_profile->transfer_source);
+       cJSON_AddItemToObject(json, "Direction", cJSON_CreateString(caller_profile->direction == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"));
+       cJSON_AddItemToObject(json, "Logical-Direction", cJSON_CreateString(caller_profile->logical_direction == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"));
+
+       soft = cJSON_CreateObject();
+       for (pn = caller_profile->soft; pn; pn = pn->next) {
+               maybe_add_json_string(soft, pn->var, pn->val);
+       }
+
+       cJSON_AddItemToObject(json, "Directory", soft);
+}
+
+SWITCH_DECLARE(void) kz_switch_ivr_set_json_call_flaws(cJSON *json, switch_core_session_t *session, switch_media_type_t type)
+{
+       const char *name = (type == SWITCH_MEDIA_TYPE_VIDEO) ? "Video" : "Audio";
+       cJSON *j_stat;
+       switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
+
+       if (!stats) return;
+
+       if (!stats->inbound.error_log && !stats->outbound.error_log) return;
+
+       j_stat = cJSON_CreateObject();
+       cJSON_AddItemToObject(json, name, j_stat);
+
+       if (stats->inbound.error_log) {
+               cJSON *j_err_log, *j_err, *j_in;
+               switch_error_period_t *ep;
+
+               j_in = cJSON_CreateObject();
+               cJSON_AddItemToObject(j_stat, "Inbound", j_in);
+
+               j_err_log = cJSON_CreateArray();
+               cJSON_AddItemToObject(j_in, "Error-Log", j_err_log);
+
+               for(ep = stats->inbound.error_log; ep; ep = ep->next) {
+
+                       if (!(ep->start && ep->stop)) continue;
+
+                       j_err = cJSON_CreateObject();
+
+                       cJSON_AddItemToObject(j_err, "Start", cJSON_CreateNumber(ep->start));
+                       cJSON_AddItemToObject(j_err, "Stop", cJSON_CreateNumber(ep->stop));
+                       cJSON_AddItemToObject(j_err, "Flaws", cJSON_CreateNumber(ep->flaws));
+                       cJSON_AddItemToObject(j_err, "Consecutive-Flaws", cJSON_CreateNumber(ep->consecutive_flaws));
+                       cJSON_AddItemToObject(j_err, "Duration-MS", cJSON_CreateNumber((ep->stop - ep->start) / 1000));
+                       cJSON_AddItemToArray(j_err_log, j_err);
+               }
+       }
+
+       if (stats->outbound.error_log) {
+               cJSON *j_err_log, *j_err, *j_out;
+               switch_error_period_t *ep;
+
+               j_out = cJSON_CreateObject();
+               cJSON_AddItemToObject(j_stat, "Outbound", j_out);
+
+               j_err_log = cJSON_CreateArray();
+               cJSON_AddItemToObject(j_out, "Error-Log", j_err_log);
+
+               for(ep = stats->outbound.error_log; ep; ep = ep->next) {
+
+                       if (!(ep->start && ep->stop)) continue;
+
+                       j_err = cJSON_CreateObject();
+
+                       cJSON_AddItemToObject(j_err, "Start", cJSON_CreateNumber(ep->start));
+                       cJSON_AddItemToObject(j_err, "Stop", cJSON_CreateNumber(ep->stop));
+                       cJSON_AddItemToObject(j_err, "Flaws", cJSON_CreateNumber(ep->flaws));
+                       cJSON_AddItemToObject(j_err, "Consecutive-Flaws", cJSON_CreateNumber(ep->consecutive_flaws));
+                       cJSON_AddItemToObject(j_err, "Duration-MS", cJSON_CreateNumber((ep->stop - ep->start) / 1000));
+                       cJSON_AddItemToArray(j_err_log, j_err);
+               }
+       }
+}
+
+#define add_jstat(_j, _i, _s)                                                                                  \
+       switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
+       cJSON_AddItemToObject(_j, _s, cJSON_CreateNumber(_i))
+
+SWITCH_DECLARE(void) kz_switch_ivr_set_json_call_stats(cJSON *json, switch_core_session_t *session, switch_media_type_t type)
+{
+       const char *name = (type == SWITCH_MEDIA_TYPE_VIDEO) ? "Video" : "Audio";
+       cJSON *j_stat, *j_in, *j_out;
+       switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
+       char var_val[35] = "";
+
+       if (!stats) return;
+
+       j_stat = cJSON_CreateObject();
+       j_in = cJSON_CreateObject();
+       j_out = cJSON_CreateObject();
+
+       cJSON_AddItemToObject(json, name, j_stat);
+       cJSON_AddItemToObject(j_stat, "Inbound", j_in);
+       cJSON_AddItemToObject(j_stat, "Outbound", j_out);
+
+       stats->inbound.std_deviation = sqrt(stats->inbound.variance);
+
+       add_jstat(j_in, stats->inbound.raw_bytes, "Raw-Bytes");
+       add_jstat(j_in, stats->inbound.media_bytes, "Media-Bytes");
+       add_jstat(j_in, stats->inbound.packet_count, "Packet-Count");
+       add_jstat(j_in, stats->inbound.media_packet_count, "Media-Packet-Count");
+       add_jstat(j_in, stats->inbound.skip_packet_count, "Skip-Packet-Count");
+       add_jstat(j_in, stats->inbound.jb_packet_count, "Jitter-Packet-Count");
+       add_jstat(j_in, stats->inbound.dtmf_packet_count, "DTMF-Packet-Count");
+       add_jstat(j_in, stats->inbound.cng_packet_count, "CNG-Packet-Count");
+       add_jstat(j_in, stats->inbound.flush_packet_count, "Flush-Packet-Count");
+       add_jstat(j_in, stats->inbound.largest_jb_size, "Largest-JB-Size");
+       add_jstat(j_in, stats->inbound.min_variance, "Jitter-Min-Variance");
+       add_jstat(j_in, stats->inbound.max_variance, "Jitter-Max-Variance");
+       add_jstat(j_in, stats->inbound.lossrate, "Jitter-Loss-Rate");
+       add_jstat(j_in, stats->inbound.burstrate, "Jitter-Burst-Rate");
+       add_jstat(j_in, stats->inbound.mean_interval, "Mean-Interval");
+       add_jstat(j_in, stats->inbound.flaws, "Flaw-Total");
+       add_jstat(j_in, stats->inbound.R, "Quality-Percentage");
+       add_jstat(j_in, stats->inbound.mos, "MOS");
+
+
+       add_jstat(j_out, stats->outbound.raw_bytes, "Raw-Bytes");
+       add_jstat(j_out, stats->outbound.media_bytes, "Media-Bytes");
+       add_jstat(j_out, stats->outbound.packet_count, "Packet-Count");
+       add_jstat(j_out, stats->outbound.media_packet_count, "Media-Packet-Count");
+       add_jstat(j_out, stats->outbound.skip_packet_count, "Skip-Packet-Count");
+       add_jstat(j_out, stats->outbound.dtmf_packet_count, "DTMF-Packet-Count");
+       add_jstat(j_out, stats->outbound.cng_packet_count, "CNG-Packet-Count");
+       add_jstat(j_out, stats->rtcp.packet_count, "RTCP-Packet-Count");
+       add_jstat(j_out, stats->rtcp.octet_count, "RTCP-Octet-Count");
+}
+
+static switch_status_t kz_report_channel_flaws(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       cJSON *callStats = cJSON_CreateObject();
+
+       kz_switch_ivr_set_json_call_flaws(callStats, session, SWITCH_MEDIA_TYPE_AUDIO);
+       kz_switch_ivr_set_json_call_flaws(callStats, session, SWITCH_MEDIA_TYPE_VIDEO);
+
+       switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "_json_channel_media_errors", cJSON_PrintUnformatted(callStats));
+
+       cJSON_Delete(callStats);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t kz_report_channel_stats(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       cJSON *callStats = cJSON_CreateObject();
+
+       kz_switch_ivr_set_json_call_stats(callStats, session, SWITCH_MEDIA_TYPE_AUDIO);
+       kz_switch_ivr_set_json_call_stats(callStats, session, SWITCH_MEDIA_TYPE_VIDEO);
+
+       switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "_json_channel_stats", cJSON_PrintUnformatted(callStats));
+
+       cJSON_Delete(callStats);
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t kz_report_app_log(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       switch_app_log_t *ap, *app_log = switch_core_session_get_app_log(session);
+       cJSON *j_apps = NULL;
+
+       if (!app_log) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       j_apps = cJSON_CreateArray();
+
+       for (ap = app_log; ap; ap = ap->next) {
+               cJSON *j_application = cJSON_CreateObject();
+               cJSON_AddItemToObject(j_application, "app_name", cJSON_CreateString(ap->app));
+               cJSON_AddItemToObject(j_application, "app_data", cJSON_CreateString(ap->arg));
+               cJSON_AddItemToObject(j_application, "app_stamp", cJSON_CreateNumber(ap->stamp));
+               cJSON_AddItemToArray(j_apps, j_application);
+       }
+
+       switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "_json_application_log", cJSON_PrintUnformatted(j_apps));
+
+       cJSON_Delete(j_apps);
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t kz_report_callflow_extension(switch_caller_profile_t *caller_profile, cJSON *j_profile)
+{
+       cJSON *j_caller_extension, *j_caller_extension_apps, *j_application, *j_inner_extension;
+       if (caller_profile->caller_extension) {
+               switch_caller_application_t *ap;
+
+               j_caller_extension = cJSON_CreateObject();
+               j_caller_extension_apps = cJSON_CreateArray();
+
+               cJSON_AddItemToObject(j_profile, "extension", j_caller_extension);
+
+               cJSON_AddItemToObject(j_caller_extension, "name", cJSON_CreateString(caller_profile->caller_extension->extension_name));
+               cJSON_AddItemToObject(j_caller_extension, "number", cJSON_CreateString(caller_profile->caller_extension->extension_number));
+               cJSON_AddItemToObject(j_caller_extension, "applications", j_caller_extension_apps);
+
+               if (caller_profile->caller_extension->current_application) {
+                       cJSON_AddItemToObject(j_caller_extension, "current_app", cJSON_CreateString(caller_profile->caller_extension->current_application->application_name));
+               }
+
+               for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) {
+                       j_application = cJSON_CreateObject();
+
+                       cJSON_AddItemToArray(j_caller_extension_apps, j_application);
+
+                       if (ap == caller_profile->caller_extension->current_application) {
+                               cJSON_AddItemToObject(j_application, "last_executed", cJSON_CreateString("true"));
+                       }
+                       cJSON_AddItemToObject(j_application, "app_name", cJSON_CreateString(ap->application_name));
+                       cJSON_AddItemToObject(j_application, "app_data", cJSON_CreateString(switch_str_nil(ap->application_data)));
+               }
+
+               if (caller_profile->caller_extension->children) {
+                       switch_caller_profile_t *cp = NULL;
+                       j_inner_extension = cJSON_CreateArray();
+                       cJSON_AddItemToObject(j_caller_extension, "sub_extensions", j_inner_extension);
+                       for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) {
+
+                               if (!cp->caller_extension) {
+                                       continue;
+                               }
+
+                               j_caller_extension = cJSON_CreateObject();
+                               cJSON_AddItemToArray(j_inner_extension, j_caller_extension);
+
+                               cJSON_AddItemToObject(j_caller_extension, "name", cJSON_CreateString(cp->caller_extension->extension_name));
+                               cJSON_AddItemToObject(j_caller_extension, "number", cJSON_CreateString(cp->caller_extension->extension_number));
+
+                               cJSON_AddItemToObject(j_caller_extension, "dialplan", cJSON_CreateString((char *)cp->dialplan));
+
+                               if (cp->caller_extension->current_application) {
+                                       cJSON_AddItemToObject(j_caller_extension, "current_app", cJSON_CreateString(cp->caller_extension->current_application->application_name));
+                               }
+
+                               j_caller_extension_apps = cJSON_CreateArray();
+                               cJSON_AddItemToObject(j_caller_extension, "applications", j_caller_extension_apps);
+                               for (ap = cp->caller_extension->applications; ap; ap = ap->next) {
+                                       j_application = cJSON_CreateObject();
+                                       cJSON_AddItemToArray(j_caller_extension_apps, j_application);
+
+                                       if (ap == cp->caller_extension->current_application) {
+                                               cJSON_AddItemToObject(j_application, "last_executed", cJSON_CreateString("true"));
+                                       }
+                                       cJSON_AddItemToObject(j_application, "app_name", cJSON_CreateString(ap->application_name));
+                                       cJSON_AddItemToObject(j_application, "app_data", cJSON_CreateString(switch_str_nil(ap->application_data)));
+                               }
+                       }
+               }
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t kz_report_callflow(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       switch_caller_profile_t *caller_profile;
+       cJSON *j_main_cp, *j_times, *j_callflow, *j_profile, *j_o;
+
+
+       caller_profile = switch_channel_get_caller_profile(channel);
+
+       j_callflow = cJSON_CreateArray();
+
+       while (caller_profile) {
+
+               j_profile = cJSON_CreateObject();
+
+               if (!zstr(caller_profile->dialplan)) {
+                       cJSON_AddItemToObject(j_profile, "dialplan", cJSON_CreateString((char *)caller_profile->dialplan));
+               }
+
+               if (!zstr(caller_profile->profile_index)) {
+                       cJSON_AddItemToObject(j_profile, "profile_index", cJSON_CreateString((char *)caller_profile->profile_index));
+               }
+
+               kz_report_callflow_extension(caller_profile, j_profile);
+
+               j_main_cp = cJSON_CreateObject();
+               cJSON_AddItemToObject(j_profile, "Caller-Profile", j_main_cp);
+
+               kz_switch_ivr_set_json_profile_data(j_main_cp, caller_profile);
+
+               if (caller_profile->originator_caller_profile) {
+                       j_o = cJSON_CreateObject();
+                       cJSON_AddItemToObject(j_main_cp, "originator", j_o);
+                       kz_switch_ivr_set_json_profile_data(j_o, caller_profile->originator_caller_profile);
+                       kz_report_callflow_extension(caller_profile->originator_caller_profile, j_o);
+               }
+
+               if (caller_profile->originatee_caller_profile) {
+                       j_o = cJSON_CreateObject();
+                       cJSON_AddItemToObject(j_main_cp, "originatee", j_o);
+                       kz_switch_ivr_set_json_profile_data(j_o, caller_profile->originatee_caller_profile);
+                       kz_report_callflow_extension(caller_profile->originatee_caller_profile, j_o);
+               }
+
+               if (caller_profile->times) {
+                       j_times = cJSON_CreateObject();
+                       cJSON_AddItemToObject(j_profile, "Time", j_times);
+                       cJSON_AddItemToObject(j_times, "Created", cJSON_CreateNumber(caller_profile->times->created));
+                       cJSON_AddItemToObject(j_times, "Profile-Created", cJSON_CreateNumber(caller_profile->times->profile_created));
+                       cJSON_AddItemToObject(j_times, "Progress", cJSON_CreateNumber(caller_profile->times->progress));
+                       cJSON_AddItemToObject(j_times, "Progress-Media", cJSON_CreateNumber(caller_profile->times->progress_media));
+                       cJSON_AddItemToObject(j_times, "Answered", cJSON_CreateNumber(caller_profile->times->answered));
+                       cJSON_AddItemToObject(j_times, "Bridged", cJSON_CreateNumber(caller_profile->times->bridged));
+                       cJSON_AddItemToObject(j_times, "Last-Hold", cJSON_CreateNumber(caller_profile->times->last_hold));
+                       cJSON_AddItemToObject(j_times, "Hold-Accumulated", cJSON_CreateNumber(caller_profile->times->hold_accum));
+                       cJSON_AddItemToObject(j_times, "Hangup", cJSON_CreateNumber(caller_profile->times->hungup));
+                       cJSON_AddItemToObject(j_times, "Resurrect", cJSON_CreateNumber(caller_profile->times->resurrected));
+                       cJSON_AddItemToObject(j_times, "Transfer", cJSON_CreateNumber(caller_profile->times->transferred));
+               }
+               cJSON_AddItemToArray(j_callflow, j_profile);
+               caller_profile = caller_profile->next;
+       }
+
+       switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "_json_callflow", cJSON_PrintUnformatted(j_callflow));
+
+       cJSON_Delete(j_callflow);
+
+
+       return SWITCH_STATUS_SUCCESS;
+
+}
+
+
+#define ORIGINATED_LEGS_VARIABLE "originated_legs"
+#define ORIGINATED_LEGS_ITEM_DELIM ';'
+
+#define ORIGINATE_CAUSES_VARIABLE "originate_causes"
+#define ORIGINATE_CAUSES_ITEM_DELIM ';'
+
+static switch_status_t kz_report_originated_legs(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       cJSON *j_originated = cJSON_CreateArray();
+       const char *originated_legs_var = NULL, *originate_causes_var = NULL;
+       int idx = 0;
+
+       while(1) {
+               char *argv_leg[10] = { 0 }, *argv_cause[10] = { 0 };
+               char *originated_legs, *originate_causes;
+               cJSON *j_originated_leg;
+               originated_legs_var = switch_channel_get_variable_dup(channel, ORIGINATED_LEGS_VARIABLE, SWITCH_FALSE, idx);
+               originate_causes_var = switch_channel_get_variable_dup(channel, ORIGINATE_CAUSES_VARIABLE, SWITCH_FALSE, idx);
+
+               if (zstr(originated_legs_var) || zstr(originate_causes_var)) {
+                       break;
+               }
+
+               originated_legs = strdup(originated_legs_var);
+               originate_causes = strdup(originate_causes_var);
+
+               switch_separate_string(originated_legs, ORIGINATED_LEGS_ITEM_DELIM, argv_leg, (sizeof(argv_leg) / sizeof(argv_leg[0])));
+               switch_separate_string(originate_causes, ORIGINATE_CAUSES_ITEM_DELIM, argv_cause, (sizeof(argv_cause) / sizeof(argv_cause[0])));
+
+               j_originated_leg = cJSON_CreateObject();
+               cJSON_AddItemToObject(j_originated_leg, "Call-ID", cJSON_CreateString(argv_leg[0]));
+               cJSON_AddItemToObject(j_originated_leg, "Caller-ID-Name", cJSON_CreateString(argv_leg[1]));
+               cJSON_AddItemToObject(j_originated_leg, "Caller-ID-Number", cJSON_CreateString(argv_leg[2]));
+               cJSON_AddItemToObject(j_originated_leg, "Result", cJSON_CreateString(argv_cause[1]));
+
+               cJSON_AddItemToArray(j_originated, j_originated_leg);
+
+               switch_safe_free(originated_legs);
+               switch_safe_free(originate_causes);
+
+               idx++;
+       }
+
+       switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, "_json_originated_legs", cJSON_PrintUnformatted(j_originated));
+
+       cJSON_Delete(j_originated);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+#define MAX_HISTORY 50
+#define HST_ARRAY_DELIM "|:"
+#define HST_ITEM_DELIM ':'
+
+static void kz_report_transfer_history_item(char* value, cJSON *json)
+{
+       char *argv[4] = { 0 };
+       char *item = strdup(value);
+       int argc = switch_separate_string(item, HST_ITEM_DELIM, argv, (sizeof(argv) / sizeof(argv[0])));
+       cJSON *jitem = cJSON_CreateObject();
+       char *epoch = NULL, *callid = NULL, *type = NULL;
+       int add = 0;
+       if(argc == 4) {
+               add = 1;
+               epoch = argv[0];
+               callid = argv[1];
+               type = argv[2];
+
+               if(!strncmp(type, "bl_xfer", 7)) {
+                       //char *split = strchr(argv[3], '/');
+                       //if(split) *(split++) = '\0';
+                       cJSON_AddItemToObject(jitem, "Caller-Profile-ID", cJSON_CreateString(callid));
+                       cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("blind"));
+                       cJSON_AddItemToObject(jitem, "Extension", cJSON_CreateString(argv[3]));
+                       cJSON_AddItemToObject(jitem, "Timestamp", cJSON_CreateNumber(strtod(epoch, NULL)));
+               } else if(!strncmp(type, "att_xfer", 8)) {
+                       char *split = strchr(argv[3], '/');
+                       if(split) {
+                               *(split++) = '\0';
+                               cJSON_AddItemToObject(jitem, "Caller-Profile-ID", cJSON_CreateString(callid));
+                               cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("attended"));
+                               cJSON_AddItemToObject(jitem, "Transferee", cJSON_CreateString(argv[3]));
+                               cJSON_AddItemToObject(jitem, "Transferer", cJSON_CreateString(split));
+                               cJSON_AddItemToObject(jitem, "Timestamp", cJSON_CreateNumber(strtod(epoch, NULL)));
+                       } else {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item);
+                               add = 0;
+                       }
+               } else if(!strncmp(type, "uuid_br", 7)) {
+                       cJSON_AddItemToObject(jitem, "Caller-Profile-ID", cJSON_CreateString(callid));
+                       cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("bridge"));
+                       cJSON_AddItemToObject(jitem, "Other-Leg", cJSON_CreateString(argv[3]));
+                       cJSON_AddItemToObject(jitem, "Timestamp", cJSON_CreateNumber(strtod(epoch, NULL)));
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item);
+                       add = 0;
+               }
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE SPLIT ERROR %i => %s\n", argc, item);
+       }
+       if(add) {
+               cJSON_AddItemToArray(json, jitem);
+       } else {
+               cJSON_Delete(jitem);
+       }
+       switch_safe_free(item);
+}
+
+static switch_status_t kz_report_transfer_history(switch_core_session_t *session, switch_event_t *cdr_event, const char* var_name)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       cJSON *j_transfer = NULL;
+       char *tmp_history = NULL, *history = NULL, *argv[MAX_HISTORY] = { 0 };
+       char event_header[50];
+       int n, argc = 0;
+       const char *transfer_var = switch_channel_get_variable_dup(channel, var_name, SWITCH_FALSE, -1);
+       if (zstr(transfer_var)) {
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (!(tmp_history = strdup(transfer_var))) {
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       sprintf(event_header, "_json_%s", var_name);
+       history = tmp_history;
+       j_transfer = cJSON_CreateArray();
+
+       if (!strncmp(history, "ARRAY::", 7)) {
+               history += 7;
+               argc = switch_separate_string_string(history, HST_ARRAY_DELIM, argv, (sizeof(argv) / sizeof(argv[0])));
+               for(n=0; n < argc; n++) {
+                       kz_report_transfer_history_item(argv[n], j_transfer);
+               }
+               switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, event_header, cJSON_PrintUnformatted(j_transfer));
+       } else if (strchr(history, HST_ITEM_DELIM)) {
+               kz_report_transfer_history_item(history, j_transfer);
+               switch_event_add_header_string(cdr_event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, event_header, cJSON_PrintUnformatted(j_transfer));
+       }
+       cJSON_Delete(j_transfer);
+       switch_safe_free(tmp_history);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t kz_report(switch_core_session_t *session, switch_event_t *cdr_event)
+{
+       kz_report_app_log(session, cdr_event);
+       kz_report_callflow(session, cdr_event);
+       kz_report_channel_stats(session, cdr_event);
+       kz_report_channel_flaws(session, cdr_event);
+       kz_report_originated_legs(session, cdr_event);
+       kz_report_transfer_history(session, cdr_event, SWITCH_TRANSFER_HISTORY_VARIABLE);
+       kz_report_transfer_history(session, cdr_event, SWITCH_TRANSFER_SOURCE_VARIABLE);
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t kz_cdr_on_reporting(switch_core_session_t *session)
+{
+       switch_event_t *cdr_event = NULL;
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+
+       if (switch_event_create_subclass(&cdr_event, SWITCH_EVENT_CUSTOM, MY_EVENT_JSON_CDR) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "error creating event for report data!\n");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       kz_report(session, cdr_event);
+       switch_channel_event_set_data(channel, cdr_event);
+       switch_event_fire(&cdr_event);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_state_handler_table_t kz_cdr_state_handlers = {
+       /*.on_init */ NULL,
+       /*.on_routing */ NULL,
+       /*.on_execute */ NULL,
+       /*.on_hangup */ NULL,
+       /*.on_exchange_media */ NULL,
+       /*.on_soft_execute */ NULL,
+       /*.on_consume_media */ NULL,
+       /*.on_hibernate */ NULL,
+       /*.on_reset */ NULL,
+       /*.on_park */ NULL,
+       /*.on_reporting */ kz_cdr_on_reporting
+};
+
+
+static void kz_cdr_register_state_handlers()
+{
+       switch_core_add_state_handler(&kz_cdr_state_handlers);
+}
+
+static void kz_cdr_unregister_state_handlers()
+{
+       switch_core_remove_state_handler(&kz_cdr_state_handlers);
+}
+
+static void kz_cdr_register_events()
+{
+       if (switch_event_reserve_subclass(MY_EVENT_JSON_CDR) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_JSON_CDR);
+       }
+}
+
+static void kz_cdr_unregister_events()
+{
+       switch_event_free_subclass(MY_EVENT_JSON_CDR);
+}
+
+
+void kz_cdr_start()
+{
+       kz_cdr_register_events();
+       kz_cdr_register_state_handlers();
+}
+
+void kz_cdr_stop()
+{
+       kz_cdr_unregister_state_handlers();
+       kz_cdr_unregister_events();
+}
+
+/* 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:
+ */
index 3286c34811c8b46e2e7459ab726dd7556fb04a15..bf954d1e6cba527d54b5370ea1722a60f6f49109 100644 (file)
 
 #define MAX_FIRST_OF 25
 
-#define MAX_HISTORY 50
-#define HST_ARRAY_DELIM "|:"
-#define HST_ITEM_DELIM ':'
-
-static void process_history_item(char* value, cJSON *json)
-{
-       char *argv[4] = { 0 };
-       char *item = strdup(value);
-       int argc = switch_separate_string(item, HST_ITEM_DELIM, argv, (sizeof(argv) / sizeof(argv[0])));
-       cJSON *jitem = cJSON_CreateObject();
-       char *epoch = NULL, *callid = NULL, *type = NULL;
-       int add = 0;
-       if(argc == 4) {
-               add = 1;
-               epoch = argv[0];
-               callid = argv[1];
-               type = argv[2];
-
-               if(!strncmp(type, "bl_xfer", 7)) {
-                       char *split = strchr(argv[3], '/');
-                       if(split) *(split++) = '\0';
-                       cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid));
-                       cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("blind"));
-                       cJSON_AddItemToObject(jitem, "Extension", cJSON_CreateString(argv[3]));
-               } else if(!strncmp(type, "att_xfer", 8)) {
-                       char *split = strchr(argv[3], '/');
-                       if(split) {
-                               *(split++) = '\0';
-                               cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid));
-                               cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("attended"));
-                               cJSON_AddItemToObject(jitem, "Transferee", cJSON_CreateString(argv[3]));
-                               cJSON_AddItemToObject(jitem, "Transferer", cJSON_CreateString(split));
-                       } else {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item);
-                               add = 0;
-                       }
-               } else if(!strncmp(type, "uuid_br", 7)) {
-                       cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid));
-                       cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("bridge"));
-                       cJSON_AddItemToObject(jitem, "Other-Leg", cJSON_CreateString(argv[3]));
-
-               } else {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item);
-                       add = 0;
-               }
-       } else {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE SPLIT ERROR %i => %s\n", argc, item);
-       }
-       if(add) {
-               cJSON_AddItemToObject(json, epoch, jitem);
-       } else {
-               cJSON_Delete(jitem);
-       }
-       switch_safe_free(item);
-}
-
-SWITCH_STANDARD_API(kz_json_history)
+SWITCH_STANDARD_API(kz_first_of)
 {
-       char *mycmd = NULL, *argv[MAX_HISTORY] = { 0 };
+       char delim = '|';
+       char *mycmd = NULL, *mycmd_dup = NULL, *argv[MAX_FIRST_OF] = { 0 };
        int n, argc = 0;
-       cJSON *json = cJSON_CreateObject();
-       char* output = NULL;
        switch_event_header_t *header = NULL;
-       if (!zstr(cmd) && (mycmd = strdup(cmd))) {
-               if (!strncmp(mycmd, "ARRAY::", 7)) {
-                       mycmd += 7;
-                       argc = switch_separate_string_string(mycmd, HST_ARRAY_DELIM, argv, (sizeof(argv) / sizeof(argv[0])));
-                       for(n=0; n < argc; n++) {
-                               process_history_item(argv[n], json);
-                       }
-               } else if (strchr(mycmd, HST_ITEM_DELIM)) {
-                       process_history_item(mycmd, json);
-               } else if (stream->param_event) {
-                       header = switch_event_get_header_ptr(stream->param_event, mycmd);
-                       if (header != NULL) {
-                               if(header->idx) {
-                                       for(n = 0; n < header->idx; n++) {
-                                               process_history_item(header->array[n], json);
-                                       }
-                               } else {
-                                       process_history_item(header->value, json);
-                               }
 
-                       } else {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER HISTORY HEADER NOT FOUND => %s\n", mycmd);
-                       }
-               } else {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER HISTORY NOT PARSED => %s\n", mycmd);
-               }
+       if (zstr(cmd)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid arg\n");
+               return SWITCH_STATUS_GENERR;
        }
-       output = cJSON_PrintUnformatted(json);
-       stream->write_function(stream, "%s", output);
-       switch_safe_free(output);
-       cJSON_Delete(json);
 
-       return SWITCH_STATUS_SUCCESS;
-}
-
-SWITCH_STANDARD_API(kz_first_of)
-{
-       char delim = '|';
-       char *mycmd = NULL, *argv[MAX_FIRST_OF] = { 0 };
-       int n, argc = 0;
-       switch_event_header_t *header = NULL;
-       if (!zstr(cmd) && (mycmd = strdup(cmd))) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "FIRST-OF %s\n", mycmd);
-               if (!zstr(mycmd) && *mycmd == '^' && *(mycmd+1) == '^') {
-                       mycmd += 2;
-                       delim = *mycmd++;
-               }
-               argc = switch_separate_string(mycmd, delim, argv, (sizeof(argv) / sizeof(argv[0])));
-               for(n=0; n < argc; n++) {
-                       char* item = argv[n];
-                       if(*item == '#') {
-                               if(*(++item) != '\0') {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING default %s\n", item);
-                                       stream->write_function(stream, item);
-                                       break;
-                               }
-                       } else {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "CHECKING %s\n", item);
-                               header = switch_event_get_header_ptr(stream->param_event, item);
-                               if(header) {
-                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING %s : %s\n", item, header->value);
-                                       stream->write_function(stream, header->value);
-                                       break;
-                               }
+       mycmd_dup = mycmd = strdup(cmd);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "FIRST-OF %s\n", mycmd);
+       if (!zstr(mycmd) && *mycmd == '^' && *(mycmd+1) == '^') {
+               mycmd += 2;
+               delim = *mycmd++;
+       }
+       argc = switch_separate_string(mycmd, delim, argv, (sizeof(argv) / sizeof(argv[0])));
+       for(n=0; n < argc; n++) {
+               char* item = argv[n];
+               if(*item == '#' || *item == '!' || *item == '?') {
+                       if(*(++item) != '\0') {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING default %s\n", item);
+                               stream->write_function(stream, item);
+                               break;
+                       }
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "CHECKING %s\n", item);
+                       header = switch_event_get_header_ptr(stream->param_event, item);
+                       if(header) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING %s : %s\n", item, header->value);
+                               stream->write_function(stream, header->value);
+                               break;
                        }
                }
        }
 
-       switch_safe_free(mycmd);
+       switch_safe_free(mycmd_dup);
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -364,7 +271,6 @@ SWITCH_STANDARD_API(kz_http_put)
        long httpRes = 0;
        struct stat file_info = {0};
        FILE *file_to_put = NULL;
-       int fd;
 
        if (session) {
                pool = switch_core_session_get_pool(session);
@@ -390,7 +296,11 @@ SWITCH_STANDARD_API(kz_http_put)
        /* parse params and get profile */
        url = switch_core_strdup(pool, argv[0]);
        if (*url == '{') {
-               switch_event_create_brackets(url, '{', '}', ',', &params, &url, SWITCH_FALSE);
+               if (switch_event_create_brackets(url, '{', '}', ',', &params, &url, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
+                       status = SWITCH_STATUS_FALSE;
+                       stream->write_function(stream, "-ERR error parsing parameters\n");
+                       goto done;
+               }
        }
 
        filename = switch_core_strdup(pool, argv[1]);
@@ -404,34 +314,26 @@ SWITCH_STANDARD_API(kz_http_put)
        }
 
        buf = switch_mprintf("Content-Type: %s", mime_type);
-
        headers = switch_curl_slist_append(headers, buf);
 
        /* open file and get the file size */
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "opening %s for upload to %s\n", filename, url);
-       fd = open(filename, O_RDONLY);
-       if (fd == -1) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open() error: %s\n", strerror(errno));
-               status = SWITCH_STATUS_FALSE;
-               stream->write_function(stream, "-ERR error opening file\n");
-               goto done;
-       }
-       if (fstat(fd, &file_info) == -1) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "fstat() error: %s\n", strerror(errno));
-               stream->write_function(stream, "-ERR fstat error\n");
-               close(fd);
-               goto done;
-       }
-       close(fd);
 
        /* libcurl requires FILE* */
        file_to_put = fopen(filename, "rb");
        if (!file_to_put) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "fopen() error: %s\n", strerror(errno));
+               stream->write_function(stream, "-ERR error opening file\n");
                status = SWITCH_STATUS_FALSE;
                goto done;
        }
 
+       if (fstat(fileno(file_to_put), &file_info) == -1) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "fstat() error: %s\n", strerror(errno));
+               stream->write_function(stream, "-ERR fstat error\n");
+               goto done;
+       }
+
        curl_handle = switch_curl_easy_init();
        if (!curl_handle) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_curl_easy_init() failure\n");
@@ -503,13 +405,36 @@ done:
 
 SWITCH_STANDARD_API(kz_expand_api)
 {
-       if (!zstr(cmd)) {
-               char * val = kz_expand(cmd);
-               stream->write_function(stream, "+OK %s", val);
-               switch_safe_free(val);
-       } else {
-               stream->write_function(stream, "ERR invalid input");
+       char *p = NULL, *input = NULL;
+       char *uuid = NULL, *mycmd;
+
+       if (zstr(cmd)) {
+               stream->write_function(stream, "-ERR invalid input");
+               return SWITCH_STATUS_GENERR;
        }
+
+       if (!(mycmd = strdup(cmd))) {
+               stream->write_function(stream, "-ERR no memory");
+               return SWITCH_STATUS_GENERR;
+       }
+
+       if (!strncasecmp(mycmd, "uuid:", 5)) {
+               uuid = mycmd + 5;
+               if ((input = strchr(uuid, ' ')) != NULL) {
+                       *input++ = '\0';
+               } else {
+                       stream->write_function(stream, "-ERR invalid argument");
+                       switch_safe_free(mycmd);
+                       return SWITCH_STATUS_GENERR;
+               }
+       }
+
+       p = kz_expand(input, uuid);
+       stream->write_function(stream, "+OK %s", p);
+       if (p != input) {
+               switch_safe_free(p);
+       }
+       switch_safe_free(mycmd);
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -525,7 +450,6 @@ void add_kz_commands(switch_loadable_module_interface_t **module_interface) {
        switch_console_set_complete("add kz_uuid_setvar_encoded ::console::list_uuid");
        SWITCH_ADD_API(api_interface, "kz_http_put", KZ_HTTP_PUT_DESC, kz_http_put, KZ_HTTP_PUT_SYNTAX);
        SWITCH_ADD_API(api_interface, "first-of", KZ_FIRST_OF_DESC, kz_first_of, KZ_FIRST_OF_SYNTAX);
-       SWITCH_ADD_API(api_interface, "kz_json_history", KZ_FIRST_OF_DESC, kz_json_history, KZ_FIRST_OF_SYNTAX);
        SWITCH_ADD_API(api_interface, "kz_expand", KZ_FIRST_OF_DESC, kz_expand_api, KZ_FIRST_OF_SYNTAX);
 }
 
index fcda9012ff21f91c3bfcf36af4b13904c15d1624..a64677074b2c7793c0391ebc16e3dc7409485f85 100644 (file)
@@ -129,6 +129,10 @@ switch_status_t kazoo_config_loglevels(switch_memory_pool_t *pool, switch_xml_t
        loglevels->warn_log_level = SWITCH_LOG_WARNING;
        loglevels->success_log_level = SWITCH_LOG_DEBUG;
        loglevels->time_log_level = SWITCH_LOG_DEBUG1;
+       loglevels->trace_log_level = SWITCH_LOG_DEBUG1;
+       loglevels->debug_log_level = SWITCH_LOG_DEBUG;
+       loglevels->error_log_level = SWITCH_LOG_ERROR;
+       loglevels->hashing_log_level = SWITCH_LOG_DEBUG1;
 
        if ((xml_logging = switch_xml_child(cfg, "logging")) != NULL) {
                for (xml_level = switch_xml_child(xml_logging, "log"); xml_level; xml_level = xml_level->next) {
@@ -159,6 +163,14 @@ switch_status_t kazoo_config_loglevels(switch_memory_pool_t *pool, switch_xml_t
                                loglevels->filtered_event_log_level = log_str2level(val);
                        } else if (!strncmp(var, "filtered-field", 14)) {
                                loglevels->filtered_field_log_level = log_str2level(val);
+                       } else if (!strncmp(var, "trace", 5)) {
+                               loglevels->trace_log_level = log_str2level(val);
+                       } else if (!strncmp(var, "debug", 5)) {
+                               loglevels->debug_log_level = log_str2level(val);
+                       } else if (!strncmp(var, "error", 5)) {
+                               loglevels->error_log_level = log_str2level(val);
+                       } else if (!strncmp(var, "hashing", 7)) {
+                               loglevels->hashing_log_level = log_str2level(val);
                        }
                } /* xml_level for loop */
        }
@@ -247,6 +259,7 @@ switch_status_t kazoo_config_field(kazoo_config_ptr definitions, switch_memory_p
        const char *type = switch_xml_attr(cfg, "type");
        const char *exclude_prefix = switch_xml_attr(cfg, "exclude-prefix");
        const char *serialize_as = switch_xml_attr(cfg, "serialize-as");
+       const char *as_array = switch_xml_attr(cfg, "as-array");
        kazoo_field_ptr cur = (kazoo_field_ptr) switch_core_alloc(pool, sizeof(kazoo_field));
        cur->in_type = FIELD_NONE;
        cur->out_type = JSON_NONE;
@@ -292,6 +305,10 @@ switch_status_t kazoo_config_field(kazoo_config_ptr definitions, switch_memory_p
                }
        }
 
+       if(as_array) {
+               cur->out_type_as_array = switch_true(as_array);
+       }
+
        if(exclude_prefix)
                cur->exclude_prefix = switch_true(exclude_prefix);
 
index 22398554644efe06652b57aa0b637984f97181ce..d5bd64fa9a01c2de21c05aea53da3eee3f3b48b9 100644 (file)
@@ -267,7 +267,7 @@ void kz_uuid_multiset(switch_core_session_t *session, const char* data, int urld
 
        if(delim != '\0') {
                switch_core_session_t *uuid_session = NULL;
-               if ((uuid_session = switch_core_session_force_locate(arg0)) != NULL) {
+               if ((uuid_session = switch_core_session_locate(arg0)) != NULL) {
                        switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session);
                        if (arg) {
                                char *array[256] = {0};
index 53ed9841547a540685ec050367fb6af1f51aed17..80457216269622884ac122cc48fdd0539d85021c 100644 (file)
@@ -238,8 +238,8 @@ switch_status_t kazoo_ei_config(switch_xml_t cfg) {
        }
 
        if ((child = switch_xml_child(cfg, "tweaks"))) {
-               char *default_tweaks = (char *) switch_xml_attr_soft(param, "default");
-               if (default_tweaks) {
+               char *default_tweaks = (char *) switch_xml_attr_soft(child, "default");
+               if (default_tweaks && !zstr(default_tweaks)) {
                        int i, v = switch_true(default_tweaks) ? 1 : 0;
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set tweak default : %s\n", default_tweaks);
                        for (i = 0; i < KZ_TWEAK_MAX; i++) kazoo_globals.tweaks[i] = v;
@@ -516,9 +516,10 @@ switch_status_t kazoo_config_events(kazoo_config_ptr definitions, switch_memory_
                        cur->name = switch_core_strdup(pool, var);
                        kazoo_config_filters(pool, event, &cur->filter);
                        kazoo_config_fields(definitions, pool, event, &cur->fields);
-
+                       if (switch_xml_child(event, "logging") != NULL) {
+                               kazoo_config_loglevels(pool, event, &cur->logging);
+                       }
                }
-
        }
 
        return SWITCH_STATUS_SUCCESS;
index fb655e88609d00583906eddbd88f3f853b61898a..416098b97269a866cf2afd6911626bf82eac09d4 100644 (file)
 
 #ifdef EI_DEBUG
 static void ei_x_print_reg_msg(ei_x_buff *buf, char *dest, int send) {
-    char *mbuf = NULL;
-    int i = 1;
+       char *mbuf = NULL;
+       int i = 1;
 
-    ei_s_print_term(&mbuf, buf->buff, &i);
+       ei_s_print_term(&mbuf, buf->buff, &i);
 
-    if (send) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoded term %s to '%s'\n", mbuf, dest);
-    } else {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Decoded term %s for '%s'\n", mbuf, dest);
-    }
+       if (send) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoded term %s to '%s'\n", mbuf, dest);
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Decoded term %s for '%s'\n", mbuf, dest);
+       }
 
-    free(mbuf);
+       free(mbuf);
 }
 
 static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) {
-    char *pbuf = NULL;
-    int i = 0;
-    ei_x_buff pidbuf;
+       char *pbuf = NULL;
+       int i = 0;
+       ei_x_buff pidbuf;
 
-    ei_x_new(&pidbuf);
-    ei_x_encode_pid(&pidbuf, pid);
+       ei_x_new(&pidbuf);
+       ei_x_encode_pid(&pidbuf, pid);
 
-    ei_s_print_term(&pbuf, pidbuf.buff, &i);
+       ei_s_print_term(&pbuf, pidbuf.buff, &i);
 
-    ei_x_print_reg_msg(buf, pbuf, send);
-    free(pbuf);
+       ei_x_print_reg_msg(buf, pbuf, send);
+       free(pbuf);
 }
 #endif
 
-void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event) {
+void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event)
+{
        ei_encode_switch_event_headers_2(ebuf, event, 1);
 }
 
-void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode) {
-    switch_event_header_t *hp;
-    char *uuid = switch_event_get_header(event, "unique-id");
-    int i;
+void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode)
+{
+       switch_event_header_t *hp;
+       char *uuid = switch_event_get_header(event, "unique-id");
+       int i;
 
-    for (i = 0, hp = event->headers; hp; hp = hp->next, i++);
+       for (i = 0, hp = event->headers; hp; hp = hp->next, i++)
+               ;
 
-    if (event->body)
-        i++;
+       if (event->body)
+               i++;
 
-    ei_x_encode_list_header(ebuf, i + 1);
+       ei_x_encode_list_header(ebuf, i + 1);
 
-    if (uuid) {
+       if (uuid) {
                char *unique_id = switch_event_get_header(event, "unique-id");
                ei_x_encode_binary(ebuf, unique_id, strlen(unique_id));
-    } else {
-        ei_x_encode_atom(ebuf, "undefined");
-    }
-
-    for (hp = event->headers; hp; hp = hp->next) {
-        ei_x_encode_tuple_header(ebuf, 2);
-        ei_x_encode_binary(ebuf, hp->name, strlen(hp->name));
-           if(encode) {
-               switch_url_decode(hp->value);
-           }
-        ei_x_encode_binary(ebuf, hp->value, strlen(hp->value));
-    }
-
-    if (event->body) {
-        ei_x_encode_tuple_header(ebuf, 2);
-        ei_x_encode_binary(ebuf, "body", strlen("body"));
-        ei_x_encode_binary(ebuf, event->body, strlen(event->body));
-    }
-
-    ei_x_encode_empty_list(ebuf);
+       } else {
+               ei_x_encode_atom(ebuf, "undefined");
+       }
+
+       for (hp = event->headers; hp; hp = hp->next) {
+               ei_x_encode_tuple_header(ebuf, 2);
+               ei_x_encode_binary(ebuf, hp->name, strlen(hp->name));
+               if (encode) {
+                       switch_url_decode(hp->value);
+               }
+               ei_x_encode_binary(ebuf, hp->value, strlen(hp->value));
+       }
+
+       if (event->body) {
+               ei_x_encode_tuple_header(ebuf, 2);
+               ei_x_encode_binary(ebuf, "body", strlen("body"));
+               ei_x_encode_binary(ebuf, event->body, strlen(event->body));
+       }
+
+       ei_x_encode_empty_list(ebuf);
 }
 
 int ei_json_child_count(cJSON *JObj)
 {
-       int mask = cJSON_False
-                       | cJSON_True
-                       | cJSON_NULL
-                       | cJSON_Number
-                       | cJSON_String
-                       | cJSON_Array
-                       | cJSON_Object
-                       | cJSON_Raw;
+       int mask = cJSON_False | cJSON_True | cJSON_NULL | cJSON_Number | cJSON_String | cJSON_Array | cJSON_Object | cJSON_Raw;
 
        cJSON *item = JObj->child;
        int i = 0;
-       while(item) {
-               if(item->type & mask)
+       while (item) {
+               if (item->type & mask)
                        i++;
                item = item->next;
        }
@@ -146,154 +142,165 @@ int ei_json_child_count(cJSON *JObj)
 
 }
 
-void ei_encode_json_array(ei_x_buff *ebuf, cJSON *JObj) {
+void ei_encode_json_array(ei_x_buff *ebuf, cJSON *JObj)
+{
        cJSON *item;
        int count = ei_json_child_count(JObj);
 
-    ei_x_encode_list_header(ebuf, count);
-    if(count == 0)
-       return;
-
-    item = JObj->child;
-    while(item) {
-       switch(item->type) {
-       case cJSON_String:
-               ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
-               break;
-
-       case cJSON_Number:
-                       ei_x_encode_double(ebuf, item->valuedouble);
-               break;
-
-       case cJSON_True:
-               ei_x_encode_boolean(ebuf, 1);
-               break;
-
-       case cJSON_False:
-               ei_x_encode_boolean(ebuf, 0);
-               break;
-
-       case cJSON_Object:
-               ei_encode_json(ebuf, item);
-               break;
-
-       case cJSON_Array:
-               ei_encode_json_array(ebuf, item);
-               break;
-
-       case cJSON_Raw:
-       {
-               cJSON *Decoded = cJSON_Parse(item->valuestring);
-               if(!Decoded) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
-                       ei_x_encode_tuple_header(ebuf, 0);
-               } else {
-                       ei_encode_json(ebuf, Decoded);
-                       cJSON_Delete(Decoded);
-               }
-               break;
-       }
-
-       case cJSON_NULL:
-               ei_x_encode_atom(ebuf, "null");
-               break;
-
-       default:
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
-               break;
-
-       }
-       item = item->next;
-    }
-
-    ei_x_encode_empty_list(ebuf);
+       ei_x_encode_list_header(ebuf, count);
+       if (count == 0)
+               return;
+
+       item = JObj->child;
+       while (item) {
+               switch (item->type){
+               case cJSON_String:
+                       ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
+                       break;
+
+               case cJSON_Number:
+                       if ((fabs(((double) item->valueint) - item->valuedouble) <= DBL_EPSILON) && (item->valuedouble <= INT_MAX) && (item->valuedouble >= INT_MIN)) {
+                               ei_x_encode_longlong(ebuf, item->valueint);
+                       } else {
+                               if (fmod(item->valuedouble, 1) == 0) {
+                                       ei_x_encode_ulonglong(ebuf, item->valuedouble);
+                               } else {
+                                       ei_x_encode_double(ebuf, item->valuedouble);
+                               }
+                       }
+                       break;
+
+               case cJSON_True:
+                       ei_x_encode_boolean(ebuf, 1);
+                       break;
+
+               case cJSON_False:
+                       ei_x_encode_boolean(ebuf, 0);
+                       break;
+
+               case cJSON_Object:
+                       ei_encode_json(ebuf, item);
+                       break;
+
+               case cJSON_Array:
+                       ei_encode_json_array(ebuf, item);
+                       break;
+
+               case cJSON_Raw: {
+                       cJSON *Decoded = cJSON_Parse(item->valuestring);
+                       if (!Decoded) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
+                               ei_x_encode_tuple_header(ebuf, 0);
+                       } else {
+                               ei_encode_json(ebuf, Decoded);
+                               cJSON_Delete(Decoded);
+                       }
+                       break;
+               }
+
+               case cJSON_NULL:
+                       ei_x_encode_atom(ebuf, "null");
+                       break;
+
+               default:
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
+                       break;
+
+               }
+               item = item->next;
+       }
+
+       ei_x_encode_empty_list(ebuf);
 
 }
 
-void ei_encode_json(ei_x_buff *ebuf, cJSON *JObj) {
+void ei_encode_json(ei_x_buff *ebuf, cJSON *JObj)
+{
        cJSON *item;
        int count = ei_json_child_count(JObj);
 
-       if(kazoo_globals.json_encoding == ERLANG_TUPLE) {
-           ei_x_encode_tuple_header(ebuf, 1);
-           ei_x_encode_list_header(ebuf, count);
+       if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
+               ei_x_encode_tuple_header(ebuf, 1);
+               ei_x_encode_list_header(ebuf, count);
        } else {
                ei_x_encode_map_header(ebuf, count);
        }
 
-    if(count == 0)
-       return;
-
-    item = JObj->child;
-    while(item) {
-       if(kazoo_globals.json_encoding == ERLANG_TUPLE) {
-               ei_x_encode_tuple_header(ebuf, 2);
-       }
-       ei_x_encode_binary(ebuf, item->string, strlen(item->string));
-
-       switch(item->type) {
-       case cJSON_String:
-               ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
-               break;
-
-       case cJSON_Number:
-               if ((fabs(((double)item->valueint) - item->valuedouble) <= DBL_EPSILON)
-                               && (item->valuedouble <= INT_MAX)
-                               && (item->valuedouble >= INT_MIN)) {
-                       ei_x_encode_longlong(ebuf, item->valueint);
-               } else {
-                       ei_x_encode_double(ebuf, item->valuedouble);
-               }
-               break;
-
-       case cJSON_True:
-               ei_x_encode_boolean(ebuf, 1);
-               break;
-
-       case cJSON_False:
-               ei_x_encode_boolean(ebuf, 0);
-               break;
-
-       case cJSON_Object:
-               ei_encode_json(ebuf, item);
-               break;
-
-       case cJSON_Array:
-               ei_encode_json_array(ebuf, item);
-               break;
-
-       case cJSON_Raw:
-       {
-               cJSON *Decoded = cJSON_Parse(item->valuestring);
-               if(!Decoded) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
-                       ei_x_encode_tuple_header(ebuf, 0);
-               } else {
-                       ei_encode_json(ebuf, Decoded);
-                       cJSON_Delete(Decoded);
-               }
-               break;
-       }
-
-       case cJSON_NULL:
-               ei_x_encode_atom(ebuf, "null");
-               break;
-
-       default:
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
-               break;
-
-       }
-       item = item->next;
-    }
-
-       if(kazoo_globals.json_encoding == ERLANG_TUPLE) {
+       if (count == 0)
+               return;
+
+       item = JObj->child;
+       while (item) {
+               if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
+                       ei_x_encode_tuple_header(ebuf, 2);
+               }
+               ei_x_encode_binary(ebuf, item->string, strlen(item->string));
+
+               switch (item->type){
+               case cJSON_String:
+                       ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring));
+                       break;
+
+               case cJSON_Number:
+                       if ((fabs(((double) item->valueint) - item->valuedouble) <= DBL_EPSILON) && (item->valuedouble <= INT_MAX) && (item->valuedouble >= INT_MIN)) {
+                               ei_x_encode_longlong(ebuf, item->valueint);
+                       } else {
+                               if (fmod(item->valuedouble, 1) == 0) {
+                                       ei_x_encode_ulonglong(ebuf, item->valuedouble);
+                               } else {
+                                       ei_x_encode_double(ebuf, item->valuedouble);
+                               }
+                       }
+                       break;
+
+               case cJSON_True:
+                       ei_x_encode_boolean(ebuf, 1);
+                       break;
+
+               case cJSON_False:
+                       ei_x_encode_boolean(ebuf, 0);
+                       break;
+
+               case cJSON_Object:
+                       ei_encode_json(ebuf, item);
+                       break;
+
+               case cJSON_Array:
+                       ei_encode_json_array(ebuf, item);
+                       break;
+
+               case cJSON_Raw: {
+                       cJSON *Decoded = cJSON_Parse(item->valuestring);
+                       if (!Decoded) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring);
+                               ei_x_encode_tuple_header(ebuf, 0);
+                       } else {
+                               ei_encode_json(ebuf, Decoded);
+                               cJSON_Delete(Decoded);
+                       }
+                       break;
+               }
+
+               case cJSON_NULL:
+                       ei_x_encode_atom(ebuf, "null");
+                       break;
+
+               default:
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type);
+                       break;
+
+               }
+               item = item->next;
+       }
+
+       if (kazoo_globals.json_encoding == ERLANG_TUPLE) {
                ei_x_encode_empty_list(ebuf);
        }
 
 }
 
-void close_socket(switch_socket_t ** sock) {
+void close_socket(switch_socket_t ** sock)
+{
        if (*sock) {
                switch_socket_shutdown(*sock, SWITCH_SHUTDOWN_READWRITE);
                switch_socket_close(*sock);
@@ -301,18 +308,20 @@ void close_socket(switch_socket_t ** sock) {
        }
 }
 
-void close_socketfd(int *sockfd) {
+void close_socketfd(int *sockfd)
+{
        if (*sockfd) {
                shutdown(*sockfd, SHUT_RDWR);
                close(*sockfd);
        }
 }
 
-switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port) {
+switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port)
+{
        switch_sockaddr_t *sa;
        switch_socket_t *socket;
 
-       if(switch_sockaddr_info_get(&sa, kazoo_globals.ip, SWITCH_UNSPEC, port, 0, pool)) {
+       if (switch_sockaddr_info_get(&sa, kazoo_globals.ip, SWITCH_UNSPEC, port, 0, pool)) {
                return NULL;
        }
 
@@ -328,7 +337,7 @@ switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port
                return NULL;
        }
 
-       if (switch_socket_listen(socket, 5)){
+       if (switch_socket_listen(socket, 5)) {
                return NULL;
        }
 
@@ -339,30 +348,32 @@ switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port
        return socket;
 }
 
-switch_socket_t *create_socket(switch_memory_pool_t *pool) {
+switch_socket_t *create_socket(switch_memory_pool_t *pool)
+{
        return create_socket_with_port(pool, 0);
 
 }
 
-switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode) {
-    char hostname[EI_MAXHOSTNAMELEN + 1];
-    char nodename[MAXNODELEN + 1];
-    char cnodename[EI_MAXALIVELEN + 1];
-    char *atsign;
-
-    /* copy the erlang interface nodename into something we can modify */
-    strncpy(cnodename, name, EI_MAXALIVELEN);
-
-    if ((atsign = strchr(cnodename, '@'))) {
-        /* we got a qualified node name, don't guess the host/domain */
-        snprintf(nodename, MAXNODELEN + 1, "%s", name);
-        /* truncate the alivename at the @ */
-        *atsign++ = '\0';
-        strncpy(hostname, atsign, EI_MAXHOSTNAMELEN);
-    } else {
-        strncpy(hostname, kazoo_globals.hostname, EI_MAXHOSTNAMELEN);
-        snprintf(nodename, MAXNODELEN + 1, "%s@%s", name, hostname);
-    }
+switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode)
+{
+       char hostname[EI_MAXHOSTNAMELEN + 1];
+       char nodename[MAXNODELEN + 1];
+       char cnodename[EI_MAXALIVELEN + 1];
+       char *atsign;
+
+       /* copy the erlang interface nodename into something we can modify */
+       strncpy(cnodename, name, EI_MAXALIVELEN);
+
+       if ((atsign = strchr(cnodename, '@'))) {
+               /* we got a qualified node name, don't guess the host/domain */
+               snprintf(nodename, MAXNODELEN + 1, "%s", name);
+               /* truncate the alivename at the @ */
+               *atsign++ = '\0';
+               strncpy(hostname, atsign, EI_MAXHOSTNAMELEN);
+       } else {
+               strncpy(hostname, kazoo_globals.hostname, EI_MAXHOSTNAMELEN);
+               snprintf(nodename, MAXNODELEN + 1, "%s@%s", name, hostname);
+       }
 
        if (kazoo_globals.ei_shortname) {
                char *off;
@@ -373,94 +384,97 @@ switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "creating nodename: %s\n", nodename);
 
-    /* init the ec stuff */
-    if (ei_connect_xinit(ei_cnode, hostname, cnodename, nodename, (Erl_IpAddr) ip_addr, kazoo_globals.ei_cookie, 0) < 0) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the erlang interface connection structure\n");
-        return SWITCH_STATUS_FALSE;
-    }
+       /* init the ec stuff */
+       if (ei_connect_xinit(ei_cnode, hostname, cnodename, nodename, (Erl_IpAddr) ip_addr, kazoo_globals.ei_cookie, 0) < 0) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the erlang interface connection structure\n");
+               return SWITCH_STATUS_FALSE;
+       }
 
-    return SWITCH_STATUS_SUCCESS;
+       return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2) {
-    if ((!strcmp(pid1->node, pid2->node))
-               && pid1->creation == pid2->creation
-               && pid1->num == pid2->num
-               && pid1->serial == pid2->serial) {
-        return SWITCH_STATUS_SUCCESS;
-    } else {
-        return SWITCH_STATUS_FALSE;
-    }
+switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2)
+{
+       if ((!strcmp(pid1->node, pid2->node)) && pid1->creation == pid2->creation && pid1->num == pid2->num && pid1->serial == pid2->serial) {
+               return SWITCH_STATUS_SUCCESS;
+       } else {
+               return SWITCH_STATUS_FALSE;
+       }
 }
 
-void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to) {
-    char msgbuf[2048];
-    char *s;
-    int index = 0;
-
-    index = 5; /* max sizes: */
-    ei_encode_version(msgbuf, &index); /*   1 */
-    ei_encode_tuple_header(msgbuf, &index, 3);
-    ei_encode_long(msgbuf, &index, ERL_LINK);
-    ei_encode_pid(msgbuf, &index, from); /* 268 */
-    ei_encode_pid(msgbuf, &index, to); /* 268 */
-
-    /* 5 byte header missing */
-    s = msgbuf;
-    put32be(s, index - 4); /*   4 */
-    put8(s, ERL_PASS_THROUGH); /*   1 */
-    /* sum:  542 */
-
-    if (write(ei_node->nodefd, msgbuf, index) == -1) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to link to process on %s\n", ei_node->peer_nodename);
-    }
+void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to)
+{
+       char msgbuf[2048];
+       char *s;
+       int index = 0;
+
+       index = 5; /* max sizes: */
+       ei_encode_version(msgbuf, &index); /*   1 */
+       ei_encode_tuple_header(msgbuf, &index, 3);
+       ei_encode_long(msgbuf, &index, ERL_LINK);
+       ei_encode_pid(msgbuf, &index, from); /* 268 */
+       ei_encode_pid(msgbuf, &index, to); /* 268 */
+
+       /* 5 byte header missing */
+       s = msgbuf;
+       put32be(s, index - 4); /*   4 */
+       put8(s, ERL_PASS_THROUGH); /*   1 */
+       /* sum:  542 */
+
+       if (write(ei_node->nodefd, msgbuf, index) == -1) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to link to process on %s\n", ei_node->peer_nodename);
+       }
 }
 
-void ei_encode_switch_event(ei_x_buff *ebuf, switch_event_t *event) {
-    ei_x_encode_tuple_header(ebuf, 2);
-    ei_x_encode_atom(ebuf, "event");
-    ei_encode_switch_event_headers(ebuf, event);
+void ei_encode_switch_event(ei_x_buff *ebuf, switch_event_t *event)
+{
+       ei_x_encode_tuple_header(ebuf, 2);
+       ei_x_encode_atom(ebuf, "event");
+       ei_encode_switch_event_headers(ebuf, event);
 }
 
-int ei_helper_send(ei_node_t *ei_node, erlang_pid *to, ei_x_buff *buf) {
-    int ret = 0;
+int ei_helper_send(ei_node_t *ei_node, erlang_pid *to, ei_x_buff *buf)
+{
+       int ret = 0;
 
-    if (ei_node->nodefd) {
+       if (ei_node->nodefd) {
 #ifdef EI_DEBUG
                ei_x_print_msg(buf, to, 1);
 #endif
-        ret = ei_send(ei_node->nodefd, to, buf->buff, buf->index);
-    }
+               ret = ei_send(ei_node->nodefd, to, buf->buff, buf->index);
+       }
 
-    return ret;
+       return ret;
 }
 
-int ei_decode_atom_safe(char *buf, int *index, char *dst) {
-    int type, size;
+int ei_decode_atom_safe(char *buf, int *index, char *dst)
+{
+       int type, size;
 
-    ei_get_type(buf, index, &type, &size);
+       ei_get_type(buf, index, &type, &size);
 
        if (type != ERL_ATOM_EXT) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size);
-        return -1;
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size);
+               return -1;
        } else if (size > MAXATOMLEN) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN);
-        return -1;
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN);
+               return -1;
        } else {
                return ei_decode_atom(buf, index, dst);
        }
 }
 
-int ei_decode_string_or_binary(char *buf, int *index, char **dst) {
-    int type, size, res;
-    long len;
+int ei_decode_string_or_binary(char *buf, int *index, char **dst)
+{
+       int type, size, res;
+       long len;
 
-    ei_get_type(buf, index, &type, &size);
+       ei_get_type(buf, index, &type, &size);
 
-    if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
-        return -1;
-    }
+       if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
+               return -1;
+       }
 
        *dst = malloc(size + 1);
 
@@ -468,29 +482,30 @@ int ei_decode_string_or_binary(char *buf, int *index, char **dst) {
                res = 0;
                **dst = '\0';
        } else if (type == ERL_BINARY_EXT) {
-        res = ei_decode_binary(buf, index, *dst, &len);
-        (*dst)[len] = '\0';
-    } else {
-        res = ei_decode_string(buf, index, *dst);
-    }
+               res = ei_decode_binary(buf, index, *dst, &len);
+               (*dst)[len] = '\0';
+       } else {
+               res = ei_decode_string(buf, index, *dst);
+       }
 
-    return res;
+       return res;
 }
 
-int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst) {
-    int type, size, res;
-    long len;
+int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst)
+{
+       int type, size, res;
+       long len;
 
-    ei_get_type(buf, index, &type, &size);
+       ei_get_type(buf, index, &type, &size);
 
-    if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
-        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
-        return -1;
-    }
+       if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size);
+               return -1;
+       }
 
        if (size > maxsize) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of %s with size %d into a buffer of size %d\n",
-                                                 type == ERL_BINARY_EXT ? "binary" : "string", size, maxsize);
+                                 type == ERL_BINARY_EXT ? "binary" : "string", size, maxsize);
                return -1;
        }
 
@@ -498,21 +513,21 @@ int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char
                res = 0;
                *dst = '\0';
        } else if (type == ERL_BINARY_EXT) {
-        res = ei_decode_binary(buf, index, dst, &len);
-        dst[len] = '\0'; /* binaries aren't null terminated */
-    } else {
-        res = ei_decode_string(buf, index, dst);
-    }
+               res = ei_decode_binary(buf, index, dst, &len);
+               dst[len] = '\0'; /* binaries aren't null terminated */
+       } else {
+               res = ei_decode_string(buf, index, dst);
+       }
 
-    return res;
+       return res;
 }
 
-
-switch_status_t create_acceptor() {
+switch_status_t create_acceptor()
+{
        switch_sockaddr_t *sa;
        uint16_t port;
-    char ipbuf[48];
-    const char *ip_addr;
+       char ipbuf[48];
+       const char *ip_addr;
 
        /* if the config has specified an erlang release compatibility then pass that along to the erlang interface */
        if (kazoo_globals.ei_compat_rel) {
@@ -527,7 +542,7 @@ switch_status_t create_acceptor() {
        switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor);
 
        port = switch_sockaddr_get_port(sa);
-       ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa);
+       ip_addr = switch_get_addr(ipbuf, sizeof(ipbuf), sa);
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor listening on %s:%u\n", ip_addr, port);
 
@@ -541,7 +556,7 @@ switch_status_t create_acceptor() {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to publish port to epmd, trying to start epmd via system()\n");
                if (system("fs_epmd -daemon")) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
-                               "Failed to start epmd manually! Is epmd in $PATH? If not, start it yourself or run an erl shell with -sname or -name\n");
+                                         "Failed to start epmd manually! Is epmd in $PATH? If not, start it yourself or run an erl shell with -sname or -name\n");
                        return SWITCH_STATUS_SOCKERR;
                }
                switch_yield(100000);
@@ -551,12 +566,14 @@ switch_status_t create_acceptor() {
                }
        }
 
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to epmd and published erlang cnode name %s at port %d\n", kazoo_globals.ei_cnode.thisnodename, port);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to epmd and published erlang cnode name %s at port %d\n", kazoo_globals.ei_cnode.thisnodename,
+                         port);
 
        return SWITCH_STATUS_SUCCESS;
 }
 
-switch_hash_t *create_default_filter() {
+switch_hash_t *create_default_filter()
+{
        switch_hash_t *filter;
 
        switch_core_hash_init(&filter);
@@ -904,7 +921,7 @@ static void fetch_config_handlers(switch_memory_pool_t *pool)
 
 static void *SWITCH_THREAD_FUNC fetch_config_exec(switch_thread_t *thread, void *obj)
 {
-       switch_memory_pool_t *pool = (switch_memory_pool_t *)obj;
+       switch_memory_pool_t *pool = (switch_memory_pool_t *) obj;
        fetch_config_filters(pool);
        fetch_config_handlers(pool);
 
@@ -913,13 +930,13 @@ static void *SWITCH_THREAD_FUNC fetch_config_exec(switch_thread_t *thread, void
        return NULL;
 }
 
-void fetch_config() {
+void fetch_config()
+{
        switch_memory_pool_t *pool;
        switch_thread_t *thread;
        switch_threadattr_t *thd_attr = NULL;
        switch_uuid_t uuid;
 
-
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "fetching kazoo config\n");
 
        switch_core_new_memory_pool(&pool);
@@ -935,35 +952,35 @@ void fetch_config() {
 
 #ifdef WITH_KAZOO_ERL_SHUTDOWN
 #if (ERLANG_MAJOR == 10 && ERLANG_MINOR >= 3) || ERLANG_MAJOR >= 11
-       typedef struct ei_mutex_s {
-       #ifdef __WIN32__
-         HANDLE lock;
-       #elif VXWORKS
-         SEM_ID lock;
-       #else /* unix */
-       #if defined(HAVE_MIT_PTHREAD_H) || defined(HAVE_PTHREAD_H)
-         pthread_mutex_t *lock;
-       #else /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
-         void *dummy;   /* Actually never used */
-       #endif /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
-       #endif /* unix */
-       } ei_mutex_t;
-
-       typedef struct ei_socket_info_s {
-           int socket;
-           ei_socket_callbacks *cbs;
-           void *ctx;
-           int dist_version;
-           ei_cnode cnode;     /* A copy, not a pointer. We don't know when freed */
-           char cookie[EI_MAX_COOKIE_SIZE+1];
-       } ei_socket_info;
-
-       extern ei_socket_info *ei_sockets;
-       extern ei_mutex_t* ei_sockets_lock;
-       extern int ei_n_sockets;
-       extern int ei_sz_sockets;
-
-       int ei_mutex_free(ei_mutex_t *l, int nblock);
+typedef struct ei_mutex_s {
+#ifdef __WIN32__
+       HANDLE lock;
+#elif VXWORKS
+       SEM_ID lock;
+#else /* unix */
+#if defined(HAVE_MIT_PTHREAD_H) || defined(HAVE_PTHREAD_H)
+       pthread_mutex_t *lock;
+#else /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
+       void *dummy; /* Actually never used */
+#endif /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
+#endif /* unix */
+}ei_mutex_t;
+
+typedef struct ei_socket_info_s {
+       int socket;
+       ei_socket_callbacks *cbs;
+       void *ctx;
+       int dist_version;
+       ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */
+       char cookie[EI_MAX_COOKIE_SIZE+1];
+}ei_socket_info;
+
+extern ei_socket_info *ei_sockets;
+extern ei_mutex_t* ei_sockets_lock;
+extern int ei_n_sockets;
+extern int ei_sz_sockets;
+
+int ei_mutex_free(ei_mutex_t *l, int nblock);
 
 #endif
 #endif
@@ -988,10 +1005,11 @@ void kz_erl_shutdown()
 #endif
 }
 
-SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime) {
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime)
+{
        switch_os_socket_t os_socket;
 
-       if(create_acceptor() != SWITCH_STATUS_SUCCESS) {
+       if (create_acceptor() != SWITCH_STATUS_SUCCESS) {
                // TODO: what would we need to clean up here
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to create erlang connection acceptor!\n");
                close_socket(&kazoo_globals.acceptor);
@@ -1018,7 +1036,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Erlang connection acceptor socket error %d %d\n", erl_errno, errno);
                        } else {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
-                                                                 "Erlang node connection failed - ensure your cookie matches '%s' and you are using a good nodename\n", kazoo_globals.ei_cookie);
+                                                 "Erlang node connection failed - ensure your cookie matches '%s' and you are using a good nodename\n", kazoo_globals.ei_cookie);
                        }
                        continue;
                }
index bec5b5e1ea3a46419be8690273bdbd0ba5f8e283..2e111db3af3e35212ca42babb9cc3d57915c0864 100644 (file)
@@ -271,7 +271,7 @@ static switch_call_cause_t kz_endpoint_outgoing_channel(switch_core_session_t *s
        } else if(var_event) {
                const char* uuid_e_session = switch_event_get_header(var_event, "ent_originate_aleg_uuid");
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHECKING ORIGINATE-UUID : %s\n", uuid_e_session);
-               if (uuid_e_session && (e_session = switch_core_session_force_locate(uuid_e_session)) != NULL) {
+               if (uuid_e_session && (e_session = switch_core_session_locate(uuid_e_session)) != NULL) {
                        a_session = e_session;
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FOUND ORIGINATE-UUID : %s\n", uuid_e_session);
                }
index c2a53933ea6b6daaa5879eb3b4bb7171d3d7b309..4f0148340db6f1854e4b08be84d6abf49dbfc086 100644 (file)
@@ -202,14 +202,17 @@ static void event_handler(switch_event_t *event) {
        ei_x_encode_version(ebuf);
 
        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Target-Node", event_binding->stream->node->peer_nodename);
+       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename);
 
        if(event_stream->node->legacy) {
-               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename);
                res = encode_event_old(event, ebuf);
        } else {
                res = encode_event_new(event, ebuf);
        }
 
+       switch_event_del_header(event, "Switch-Nodename");
+       switch_event_del_header(event, "Target-Node");
+
        if(!res) {
                ei_x_free(ebuf);
                switch_safe_free(ebuf);
@@ -391,7 +394,7 @@ ei_event_stream_t *new_event_stream(ei_node_t *ei_node, const erlang_pid *from)
        /* from the memory pool, allocate the event stream structure */
        if (!(event_stream = switch_core_alloc(pool, sizeof (*event_stream)))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory: I may have Alzheimers but at least I dont have Alzheimers.\n");
-               return NULL;
+               goto cleanup;
        }
 
        /* prepare the event stream */
@@ -408,28 +411,24 @@ ei_event_stream_t *new_event_stream(ei_node_t *ei_node, const erlang_pid *from)
        /* create a socket for accepting the event stream client */
     if (!(event_stream->acceptor = create_socket(pool))) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Like car accidents, most hardware problems are due to driver error.\n");
-               /* TODO: clean up */
-        return NULL;
+               goto cleanup;
     }
 
        if (switch_socket_opt_set(event_stream->acceptor, SWITCH_SO_NONBLOCK, TRUE)) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Hey, it compiles!\n");
-               /* TODO: clean up */
-        return NULL;
+               goto cleanup;
        }
 
        /* create a pollset so we can efficiently check for new client connections */
        if (switch_pollset_create(&event_stream->pollset, 1000, pool, 0) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "My software never has bugs. It just develops random features.\n");
-               /* TODO: clean up */
-        return NULL;
+               goto cleanup;
        }
 
        switch_socket_create_pollfd(&event_stream->pollfd, event_stream->acceptor, SWITCH_POLLIN | SWITCH_POLLERR, NULL, pool);
        if (switch_pollset_add(event_stream->pollset, event_stream->pollfd) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "If you saw a heat wave, would you wave back?\n");
-               /* TODO: clean up */
-        return NULL;
+               goto cleanup;
        }
 
        switch_mutex_init(&event_stream->socket_mutex, SWITCH_MUTEX_DEFAULT, pool);
@@ -454,6 +453,26 @@ ei_event_stream_t *new_event_stream(ei_node_t *ei_node, const erlang_pid *from)
        switch_thread_create(&thread, thd_attr, event_stream_loop, event_stream, event_stream->pool);
 
        return event_stream;
+
+cleanup:
+
+       if (event_stream) {
+               /* remove the acceptor pollset */
+               if (event_stream->pollset) {
+                       switch_pollset_remove(event_stream->pollset, event_stream->pollfd);
+               }
+
+               /* close any open sockets */
+               if (event_stream->acceptor) {
+                       close_socket(&event_stream->acceptor);
+               }
+       }
+
+       /* clean up the memory */
+       switch_core_destroy_memory_pool(&pool);
+
+    return NULL;
+
 }
 
 unsigned long get_stream_port(const ei_event_stream_t *event_stream) {
index f48660d6eb6890811a9936ddb92097c34f5af462..0b9efe45d094a6f7d477b83bfb3ede2b9e2c1be8 100644 (file)
@@ -154,6 +154,8 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con
                }
        }
 
+       switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename);
+
        /* prepare the reply collector */
        switch_uuid_get(&uuid);
        switch_uuid_format(reply.uuid_str, &uuid);
@@ -165,7 +167,7 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con
                for(i = 0; fetch_uuid_sources[i] != NULL; i++) {
                        if((fetch_call_id = switch_event_get_header(event, fetch_uuid_sources[i])) != NULL) {
                                switch_core_session_t *session = NULL;
-                               if((session = switch_core_session_force_locate(fetch_call_id)) != NULL) {
+                               if((session = switch_core_session_locate(fetch_call_id)) != NULL) {
                                        switch_channel_t *channel = switch_core_session_get_channel(session);
                                        uint32_t verbose = switch_channel_test_flag(channel, CF_VERBOSE_EVENTS);
                                        switch_channel_set_flag(channel, CF_VERBOSE_EVENTS);
index 6c8111bfe446086b85377b483f1298a19517bfc0..8d17378768e59d02659f5ef2552cc2bac03484f9 100644 (file)
@@ -55,6 +55,10 @@ struct kazoo_log_levels
        switch_log_level_t time_log_level;
        switch_log_level_t filtered_event_log_level;
        switch_log_level_t filtered_field_log_level;
+       switch_log_level_t trace_log_level;
+       switch_log_level_t debug_log_level;
+       switch_log_level_t error_log_level;
+       switch_log_level_t hashing_log_level;
 
 };
 
@@ -138,6 +142,7 @@ struct kazoo_field_t {
        switch_bool_t exclude_prefix;
        kazoo_field_type in_type;
        kazoo_json_field_type out_type;
+       int out_type_as_array;
        kazoo_filter_ptr filter;
 
        kazoo_definition_ptr ref;
@@ -162,6 +167,7 @@ struct kazoo_event {
        char *name;
        kazoo_fields_ptr fields;
        kazoo_filter_ptr filter;
+       kazoo_loglevels_ptr logging;
 
        kazoo_event_t* next;
 };
index a35dfab080f641bcd153f8c1dc00f588ec175bfa..e43d656b4ceb0fd2e10eacaf5172c8c1b5540f9a 100644 (file)
@@ -45,7 +45,7 @@ void kazoo_cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
        cJSON_AddItemToObject(object, string, item);
 }
 
-static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter)
+static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter, kazoo_logging_ptr logging)
 {
        switch_event_header_t *header;
        int hasValue = 0, n;
@@ -55,6 +55,7 @@ static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter)
 
        case FILTER_COMPARE_EXISTS:
                hasValue = switch_event_get_header(evt, filter->name) != NULL ? 1 : 0;
+               switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->trace_log_level, "profile[%s] event %s checking if %s exists => %s\n", logging->profile_name, logging->event_name, filter->name, hasValue ? "true" : "false");
                break;
 
        case FILTER_COMPARE_VALUE:
@@ -64,6 +65,7 @@ static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter)
                        value = switch_event_get_header(evt, filter->name);
                }
                hasValue = value ? !strcmp(value, filter->value) : 0;
+               switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->trace_log_level, "profile[%s] event %s compare value %s to %s => %s == %s => %s\n", logging->profile_name, logging->event_name, filter->name, filter->value, value, filter->value, hasValue ? "true" : "false");
                break;
 
        case FILTER_COMPARE_FIELD:
@@ -73,6 +75,7 @@ static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter)
                        value = switch_event_get_header(evt, filter->name);
                }
                hasValue = value ? !strcmp(value, switch_event_get_header_nil(evt, filter->value)) : 0;
+               switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->trace_log_level, "profile[%s] event %s compare field %s to %s => %s == %s => %s\n", logging->profile_name, logging->event_name, filter->name, filter->value, value, switch_event_get_header_nil(evt, filter->value), hasValue ? "true" : "false");
                break;
 
        case FILTER_COMPARE_PREFIX:
@@ -112,10 +115,10 @@ static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter)
        return hasValue;
 }
 
-static kazoo_filter_ptr inline filter_event(switch_event_t* evt, kazoo_filter_ptr filter)
+static kazoo_filter_ptr inline filter_event(switch_event_t* evt, kazoo_filter_ptr filter, kazoo_logging_ptr logging)
 {
        while(filter) {
-               int hasValue = filter_compare(evt, filter);
+               int hasValue = filter_compare(evt, filter, logging);
                if(filter->type == FILTER_EXCLUDE) {
                        if(hasValue)
                                break;
@@ -132,31 +135,37 @@ static void kazoo_event_init_json_fields(switch_event_t *event, cJSON *json)
 {
        switch_event_header_t *hp;
        for (hp = event->headers; hp; hp = hp->next) {
-               if (hp->idx) {
-                       cJSON *a = cJSON_CreateArray();
-                       int i;
+               if (strncmp(hp->name, "_json_", 6)) {
+                       if (hp->idx) {
+                               cJSON *a = cJSON_CreateArray();
+                               int i;
 
-                       for(i = 0; i < hp->idx; i++) {
-                               cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i]));
-                       }
+                               for(i = 0; i < hp->idx; i++) {
+                                       cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i]));
+                               }
 
-                       cJSON_AddItemToObject(json, hp->name, a);
+                               cJSON_AddItemToObject(json, hp->name, a);
 
-               } else {
-                       cJSON_AddItemToObject(json, hp->name, cJSON_CreateString(hp->value));
+                       } else {
+                               cJSON_AddItemToObject(json, hp->name, cJSON_CreateString(hp->value));
+                       }
                }
        }
 }
 
 static switch_status_t kazoo_event_init_json(kazoo_fields_ptr fields1, kazoo_fields_ptr fields2, switch_event_t* evt, cJSON** clone)
 {
-       switch_status_t status;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
        if( (fields2 && fields2->verbose)
                        || (fields1 && fields1->verbose)
                        || ( (!fields2) &&  (!fields1)) ) {
-               status = switch_event_serialize_json_obj(evt, clone);
+               *clone = cJSON_CreateObject();
+               if((*clone) == NULL) {
+                       status = SWITCH_STATUS_GENERR;
+               } else {
+                       kazoo_event_init_json_fields(evt, *clone);
+               }
        } else {
-               status = SWITCH_STATUS_SUCCESS;
                *clone = cJSON_CreateObject();
                if((*clone) == NULL) {
                        status = SWITCH_STATUS_GENERR;
@@ -185,7 +194,11 @@ static cJSON * kazoo_event_json_value(kazoo_json_field_type type, const char *va
                break;
 
        case JSON_RAW:
-               item = cJSON_CreateRaw(value);
+               item = cJSON_Parse(value);
+               if (!item) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "parse from raw error!\n");
+                       item = cJSON_CreateRaw(value);
+               }
                break;
 
        default:
@@ -210,18 +223,24 @@ cJSON * kazoo_event_add_field_to_json(cJSON *dst, switch_event_t *src, kazoo_fie
 {
        switch_event_header_t *header;
        char *expanded;
-       uint i, n;
+       int i, n;
        cJSON *item = NULL;
 
        switch(field->in_type) {
                case FIELD_COPY:
-                       if((header = switch_event_get_header_ptr(src, field->name)) != NULL) {
+                       if (!strcmp(field->name, "_body")) {
+                               item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, src->body);
+                       } else if((header = switch_event_get_header_ptr(src, field->name)) != NULL) {
                                if (header->idx) {
                                        item = cJSON_CreateArray();
                                        for(i = 0; i < header->idx; i++) {
                                                cJSON_AddItemToArray(item, kazoo_event_json_value(field->out_type, header->array[i]));
                                        }
                                        kazoo_cJSON_AddItemToObject(dst, field->as ? field->as : field->name, item);
+                               } else if (field->out_type_as_array) {
+                                       item = cJSON_CreateArray();
+                                       cJSON_AddItemToArray(item, kazoo_event_json_value(field->out_type, header->value));
+                                       kazoo_cJSON_AddItemToObject(dst, field->as ? field->as : field->name, item);
                                } else {
                                        item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, header->value);
                                }
@@ -299,7 +318,7 @@ static switch_status_t kazoo_event_add_fields_to_json(kazoo_logging_ptr logging,
        while(field) {
                if(field->in_type == FIELD_REFERENCE) {
                        if(field->ref) {
-                               if((filter = filter_event(src, field->ref->filter)) != NULL) {
+                               if((filter = filter_event(src, field->ref->filter, logging)) != NULL) {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->filtered_field_log_level, "profile[%s] event %s, referenced field %s filtered by settings %s : %s\n", logging->profile_name, logging->event_name, field->ref->name, filter->name, filter->value);
                                } else {
                                        kazoo_event_add_fields_to_json(logging, dst, src, field->ref->head);
@@ -308,7 +327,7 @@ static switch_status_t kazoo_event_add_fields_to_json(kazoo_logging_ptr logging,
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "profile[%s] event %s, referenced field %s not found\n", logging->profile_name, logging->event_name, field->name);
                        }
                } else {
-                       if((filter = filter_event(src, field->filter)) != NULL) {
+                       if((filter = filter_event(src, field->filter, logging)) != NULL) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->filtered_field_log_level, "profile[%s] event %s, field %s filtered by settings %s : %s\n", logging->profile_name, logging->event_name, field->name, filter->name, filter->value);
                        } else {
                                item = kazoo_event_add_field_to_json(dst, src, field);
@@ -351,12 +370,9 @@ kazoo_message_ptr kazoo_message_create_event(switch_event_t* evt, kazoo_event_pt
        kazoo_logging_t logging;
 
        logging.levels = profile->logging;
-       logging.event_name = switch_event_get_header_nil(evt, "Event-Name");
+       logging.event_name = evt->subclass_name ? evt->subclass_name : switch_event_get_header_nil(evt, "Event-Name");
        logging.profile_name = profile->name;
 
-       switch_event_add_header_string(evt, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename);
-
-
        message = malloc(sizeof(kazoo_message_t));
        if(message == NULL) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocating memory for serializing event to json\n");
@@ -366,15 +382,19 @@ kazoo_message_ptr kazoo_message_create_event(switch_event_t* evt, kazoo_event_pt
 
        if(profile->filter) {
                // filtering
-               if((filtered = filter_event(evt, profile->filter)) != NULL) {
+               if((filtered = filter_event(evt, profile->filter, &logging)) != NULL) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, logging.levels->filtered_event_log_level, "profile[%s] event %s filtered by profile settings %s : %s\n", logging.profile_name, logging.event_name, filtered->name, filtered->value);
                        kazoo_message_destroy(&message);
                        return NULL;
                }
        }
 
-       if(event && event->filter) {
-               if((filtered = filter_event(evt, event->filter)) != NULL) {
+       if (event->logging) {
+               logging.levels = event->logging;
+       }
+
+       if (event && event->filter) {
+               if((filtered = filter_event(evt, event->filter, &logging)) != NULL) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, logging.levels->filtered_event_log_level, "profile[%s] event %s filtered by event settings %s : %s\n", logging.profile_name, logging.event_name, filtered->name, filtered->value);
                        kazoo_message_destroy(&message);
                        return NULL;
@@ -409,8 +429,6 @@ kazoo_message_ptr kazoo_message_create_fetch(switch_event_t* evt, kazoo_fetch_pr
        logging.event_name = switch_event_get_header_nil(evt, "Event-Name");
        logging.profile_name = profile->name;
 
-       switch_event_add_header_string(evt, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename);
-
        message = malloc(sizeof(kazoo_message_t));
        if(message == NULL) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocating memory for serializing event to json\n");
index e11a48d6ac719841494272ebd5ea7c71a51f689a..15f5ba9224d6365a96f20dde64d87995a9b93c68 100644 (file)
@@ -208,15 +208,13 @@ SWITCH_DECLARE(switch_status_t) kazoo_api_execute(const char *cmd, const char *a
        char *arg_used;
        char *cmd_used;
        int  fire_event = 0;
-       char *arg_expanded;
+       char *arg_expanded = NULL;
        switch_event_t* evt;
 
        switch_assert(stream != NULL);
        switch_assert(stream->data != NULL);
        switch_assert(stream->write_function != NULL);
 
-       arg_expanded = (char *) arg;
-
        switch_event_create(&evt, SWITCH_EVENT_GENERAL);
        arg_expanded = switch_event_expand_headers(evt, arg);
        switch_event_destroy(&evt);
@@ -507,7 +505,7 @@ static switch_status_t build_event(switch_event_t *event, ei_x_buff * buf) {
                        if(!strcasecmp(key, "Call-ID")) {
                                switch_core_session_t *session = NULL;
                                if(!zstr(value)) {
-                                       if ((session = switch_core_session_force_locate(value)) != NULL) {
+                                       if ((session = switch_core_session_locate(value)) != NULL) {
                                                switch_channel_t *channel = switch_core_session_get_channel(session);
                                                switch_channel_event_set_data(channel, event);
                                                switch_core_session_rwunlock(session);
index 2afcdf1a6a2a47888f7996f427da7e9c023f8b34..8b1d19d89c24a347dcc0650488bc304fca846e27 100644 (file)
@@ -102,10 +102,10 @@ static void kz_tweaks_handle_bridge_variables(switch_event_t *event)
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak bridge event handler: variables : %s , %s\n", a_leg, b_leg);
 
-       if (a_leg && (a_session = switch_core_session_force_locate(a_leg)) != NULL) {
+       if (a_leg && (a_session = switch_core_session_locate(a_leg)) != NULL) {
                switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
                if(switch_channel_get_variable_dup(a_channel, bridge_variables[0], SWITCH_FALSE, -1) == NULL) {
-                       if(b_leg && (b_session = switch_core_session_force_locate(b_leg)) != NULL) {
+                       if(b_leg && (b_session = switch_core_session_locate(b_leg)) != NULL) {
                                switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
                                for(i = 0; bridge_variables[i] != NULL; i++) {
                                        const char *val = switch_channel_get_variable_dup(b_channel, bridge_variables[i], SWITCH_FALSE, -1);
@@ -114,7 +114,7 @@ static void kz_tweaks_handle_bridge_variables(switch_event_t *event)
                                switch_core_session_rwunlock(b_session);
                        }
                } else {
-                       if(b_leg && (b_session = switch_core_session_force_locate(b_leg)) != NULL) {
+                       if(b_leg && (b_session = switch_core_session_locate(b_leg)) != NULL) {
                                switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
                                if(switch_channel_get_variable_dup(b_channel, bridge_variables[0], SWITCH_FALSE, -1) == NULL) {
                                        for(i = 0; bridge_variables[i] != NULL; i++) {
@@ -193,7 +193,7 @@ static void kz_tweaks_handle_bridge_replaces_call_id(switch_event_t *event)
        if(a_leg_call_id && replaced_call_id) {
                switch_core_session_t *call_session = NULL;
                const char *call_id = switch_event_get_header(event, "Bridge-B-Unique-ID");
-               if (call_id && (call_session = switch_core_session_force_locate(call_id)) != NULL) {
+               if (call_id && (call_session = switch_core_session_locate(call_id)) != NULL) {
                        switch_channel_t *call_channel = switch_core_session_get_channel(call_session);
                        if (switch_event_create(&my_event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
                                switch_event_add_header_string(my_event, SWITCH_STACK_BOTTOM, "Bridge-A-Unique-ID", switch_core_session_get_uuid(call_session));
@@ -259,13 +259,13 @@ static void kz_tweaks_channel_transferor_event_handler(switch_event_t *event)
        if (!kz_test_tweak(KZ_TWEAK_TRANSFERS)) return;
 
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR : %s , %s , %s, %s, %s , %s , %s \n", uuid, orig_call_id, dest_peer_uuid, dest_call_id, file, func, line);
-       if ((uuid_session = switch_core_session_force_locate(uuid)) != NULL) {
+       if ((uuid_session = switch_core_session_locate(uuid)) != NULL) {
                switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session);
                const char* interaction_id = switch_channel_get_variable_dup(uuid_channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1);
                // set to uuid & peer_uuid
                if(interaction_id != NULL) {
                        switch_core_session_t *session = NULL;
-                       if(dest_call_id && (session = switch_core_session_force_locate(dest_call_id)) != NULL) {
+                       if(dest_call_id && (session = switch_core_session_locate(dest_call_id)) != NULL) {
                                switch_channel_t *channel = switch_core_session_get_channel(session);
                                const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1);
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING UUID PRV : %s : %s\n", prv_interaction_id, interaction_id);
@@ -279,7 +279,7 @@ static void kz_tweaks_channel_transferor_event_handler(switch_event_t *event)
                        } else {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR NO UUID SESSION: %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid);
                        }
-                       if(dest_peer_uuid && (session = switch_core_session_force_locate(dest_peer_uuid)) != NULL) {
+                       if(dest_peer_uuid && (session = switch_core_session_locate(dest_peer_uuid)) != NULL) {
                                switch_channel_t *channel = switch_core_session_get_channel(session);
                                const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1);
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING PEER UUID PRV : %s : %s\n", prv_interaction_id, interaction_id);
@@ -293,7 +293,7 @@ static void kz_tweaks_channel_transferor_event_handler(switch_event_t *event)
                        } else {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR NO PEER SESSION: %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid);
                        }
-                       if(orig_call_id && (session = switch_core_session_force_locate(orig_call_id)) != NULL) {
+                       if(orig_call_id && (session = switch_core_session_locate(orig_call_id)) != NULL) {
                                switch_channel_t *channel = switch_core_session_get_channel(session);
                                const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1);
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING PEER UUID PRV : %s : %s\n", prv_interaction_id, interaction_id);
index 34b33c8ae1e93157b9a8b7fcdfb94f2e85dfce81..1986f8171759463f4a0e899ce7166a6d74539f0e 100644 (file)
@@ -386,7 +386,6 @@ SWITCH_DECLARE(char *) kz_event_expand_headers_check(switch_event_t *event, cons
                                switch_safe_free(expanded_sub_val);
                                sub_val = NULL;
                                vname = NULL;
-                               vtype = 0;
                                br = 0;
                        }
 
@@ -438,21 +437,18 @@ SWITCH_DECLARE(char *) kz_event_expand_headers_pool(switch_memory_pool_t *pool,
        return dup;
 }
 
-SWITCH_DECLARE(char *) kz_event_expand(const char *in)
-{
-       switch_event_t *event = NULL;
-       char *ret = NULL;
-       kz_switch_core_base_headers_for_expand(&event);
-       ret = kz_event_expand_headers_check(event, in, NULL, NULL, 0);
-       switch_event_destroy(&event);
-       return ret;
-}
-
-SWITCH_DECLARE(char *) kz_expand(const char *in)
+SWITCH_DECLARE(char *) kz_expand(const char *in, const char *uuid)
 {
        switch_event_t *event = NULL;
        char *ret = NULL;
        kz_switch_core_base_headers_for_expand(&event);
+       if (uuid != NULL) {
+               switch_core_session_t *nsession = NULL;
+               if ((nsession = switch_core_session_locate(uuid))) {
+                       switch_channel_event_set_data(switch_core_session_get_channel(nsession), event);
+                       switch_core_session_rwunlock(nsession);
+               }
+       }
        ret = kz_event_expand_headers_check(event, in, NULL, NULL, 0);
        switch_event_destroy(&event);
        return ret;
@@ -463,7 +459,7 @@ SWITCH_DECLARE(char *) kz_expand_pool(switch_memory_pool_t *pool, const char *in
        char *expanded;
        char *dup = NULL;
 
-       if(!(expanded = kz_expand(in))) {
+       if(!(expanded = kz_expand(in, NULL))) {
                return NULL;
        }
        dup = switch_core_strdup(pool, expanded);
@@ -584,12 +580,14 @@ void kz_event_decode(switch_event_t *event)
        switch_event_header_t *hp;
        int i;
        for (hp = event->headers; hp; hp = hp->next) {
-               if (hp->idx) {
-                       for(i = 0; i < hp->idx; i++) {
-                               switch_url_decode(hp->array[i]);
+               if (strncmp(hp->name, "_json_", 6)) {
+                       if (hp->idx) {
+                               for(i = 0; i < hp->idx; i++) {
+                                       switch_url_decode(hp->array[i]);
+                               }
+                       } else {
+                               switch_url_decode(hp->value);
                        }
-               } else {
-                       switch_url_decode(hp->value);
                }
        }
 }
index c5ddc3e037f03f21e46481cea09d82dae80cdb17..cb5549c7600a20f8439d12ddffff7a09b9b1da3a 100644 (file)
@@ -26,9 +26,7 @@ SWITCH_DECLARE(char *) kz_event_expand_headers(switch_event_t *event, const char
 
 SWITCH_DECLARE(char *) kz_event_expand_headers_pool(switch_memory_pool_t *pool, switch_event_t *event, char *val);
 
-SWITCH_DECLARE(char *) kz_event_expand(const char *in);
-
-SWITCH_DECLARE(char *) kz_expand(const char *in);
+SWITCH_DECLARE(char *) kz_expand(const char *in, const char *uuid);
 
 SWITCH_DECLARE(char *) kz_expand_pool(switch_memory_pool_t *pool, const char *in);
 
index 93ccb5aaf84377d2b9e08afad991888035f97fa3..15b8fb469cebdc10cf260e9da0c0e777bd30dc0d 100644 (file)
@@ -79,6 +79,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load)
        /* add tweaks */
        kz_tweaks_start();
 
+       /* add our cdr */
+       kz_cdr_start();
+
        /* indicate that the module should continue to be loaded */
        return SWITCH_STATUS_SUCCESS;
 }
@@ -88,6 +91,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown) {
 
        remove_cli_api();
 
+       kz_cdr_stop();
+
        kz_tweaks_stop();
 
        /* stop taking new requests and start shuting down the threads */
index c9f16f4826700fe4fe1d498bf9be43ec949e7e13..37fdd861e78a4f55e65a189c67a970a5a56dbd48 100644 (file)
@@ -58,6 +58,9 @@ switch_status_t kz_json_api(const char * command, cJSON *args, cJSON **res);
 /* kazoo_endpoints.c */
 void add_kz_endpoints(switch_loadable_module_interface_t **module_interface);
 
+/* kazoo_cdr.c */
+void kz_cdr_start();
+void kz_cdr_stop();
 
 /* kazoo_tweaks.c */
 void kz_tweaks_start();