Merge "Alembic: Increase column size of PJSIP AOR "contact"."
authorJoshua Colp <jcolp@digium.com>
Mon, 11 Jan 2016 22:59:10 +0000 (16:59 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Mon, 11 Jan 2016 22:59:11 +0000 (16:59 -0600)
63 files changed:
CHANGES
UPGRADE.txt
apps/app_amd.c
apps/app_dial.c
apps/app_queue.c
apps/app_voicemail.c
cel/cel_radius.c
channels/chan_sip.c
configs/samples/amd.conf.sample
contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py [new file with mode: 0644]
contrib/scripts/sipp-sendfax.xml [new file with mode: 0644]
contrib/scripts/spandspflow2pcap.log [new file with mode: 0644]
contrib/scripts/spandspflow2pcap.py [new file with mode: 0755]
include/asterisk/_private.h
include/asterisk/app.h
include/asterisk/http_websocket.h
include/asterisk/module.h
include/asterisk/stasis_cache_pattern.h
include/asterisk/time.h
main/aoc.c
main/app.c
main/asterisk.c
main/bridge_basic.c
main/cdr.c
main/devicestate.c
main/endpoints.c
main/format_cap.c
main/loader.c
main/manager.c
main/pbx.c
main/pbx_app.c [new file with mode: 0644]
main/pbx_builtins.c [new file with mode: 0644]
main/pbx_functions.c [new file with mode: 0644]
main/pbx_hangup_handler.c [new file with mode: 0644]
main/pbx_private.h [new file with mode: 0644]
main/pbx_switch.c [new file with mode: 0644]
main/pbx_timing.c [new file with mode: 0644]
main/pbx_variables.c [new file with mode: 0644]
main/rtp_engine.c
main/sorcery.c
main/stasis.c
main/stasis_cache_pattern.c
main/stasis_channels.c
main/stdtime/localtime.c
main/utils.c
pbx/pbx_dundi.c
res/res_calendar.c
res/res_crypto.c
res/res_fax.c
res/res_http_websocket.c
res/res_jabber.exports.in [deleted file]
res/res_mwi_external.c
res/res_pjsip/location.c
res/res_pjsip/pjsip_distributor.c
res/res_pjsip_endpoint_identifier_ip.c
res/res_pjsip_history.c [new file with mode: 0644]
res/res_rtp_asterisk.c
res/res_sorcery_memory_cache.c
res/res_stasis.c
res/res_stasis_playback.c
res/res_stasis_recording.c
res/stasis/app.c
tests/test_stasis_endpoints.c

diff --git a/CHANGES b/CHANGES
index dfb1590..8d5f5b3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -202,6 +202,39 @@ Queue
    the queue member was paused.
 
 ------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.7.0 to Asterisk 13.8.0 ------------
+------------------------------------------------------------------------------
+
+res_pjsip_history
+------------------
+ * A new module, res_pjsip_history, has been added that provides SIP history
+   viewing/filtering from the CLI. The module is intended to be used on systems
+   with busy SIP traffic, where existing forms of viewing SIP messages - such
+   as the res_pjsip_logger - may be inadequate. The module provides two new
+   CLI commands:
+   - 'pjsip set history {on|off|clear}' - this enables/disables SIP history
+     capturing, as well as clears an existing history capture. Note that SIP
+     packets captured are stored in memory until cleared. As a result, the
+     history capture should only be used for debugging/viewing purposes, and
+     should *NOT* be left permanently enabled on a system.
+   - 'pjsip show history' - displays the captured SIP history. When invoked
+     with no options, the entire captured history is displayed. Two options
+     are available:
+     -- 'entry <num>' - display a detailed view of a single SIP message in
+        the history
+     -- 'where ...' - filter the history based on some expression. For more
+        information on filtering, view the current CLI help for the
+        'pjsip show history' command.
+
+Voicemail
+------------------
+ * app_voicemail and res_mwi_external can now be built together.  The default
+   remains to build app_voicemail and not res_mwi_external but if they are
+   both built, the load order will cause res_mwi_external to load first and
+   app_voicemail will be skipped.  Use 'preload=app_voicemail.so' in
+   modules.conf to force app_voicemail to be the voicemail provider.
+
+------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.6.0 to Asterisk 13.7.0 ------------
 ------------------------------------------------------------------------------
 
@@ -256,6 +289,14 @@ res_pjsip
    - A TIMER statistic for the RTT time for each qualified contact, e.g.:
        PJSIP.contacts.alice@@127.0.0.1:5061.rtt
 
+res_sorcery_memory_cache
+------------------------
+ * A new caching strategy, full_backend_cache, has been added which caches
+   all stored objects in the backend. When enabled all objects will be
+   expired or go stale according to the configuration. As well when enabled
+   all retrieval operations will be performed against the cache instead of
+   the backend.
+
 func_callerid
 -------------------
  * CALLERID(pres) is now documented as a valid alternative to setting both
index 91d9edc..6fb82c4 100644 (file)
@@ -64,5 +64,15 @@ AMI:
    Commands that fail to execute (no such command, invalid syntax etc.) now
    return an Error response instead of Success.
 
+app_amd:
+ - The 'maximum_number_of_words' configuration option and parameter to the AMD
+   application previously did not match the documented functionality + variable
+   name.  In Asterisk 13, a value of '3' would mean that if '3' words were detected,
+   the result would be detection as a 'MACHINE'.  As of this version, the value
+   reflects the maximum words that if EXCEEDED (rather than reached), would
+   result in detection as a machine.  This means that you should update this
+   value to be one higher than your previos value, if your previous value
+   was working well for you.
+
 ===========================================================
 ===========================================================
index ee421b6..83da533 100644 (file)
@@ -62,19 +62,19 @@ ASTERISK_REGISTER_FILE()
                <syntax>
                        <parameter name="initialSilence" required="false">
                                <para>Is maximum initial silence duration before greeting.</para>
-                               <para>If this is exceeded set as MACHINE</para>
+                               <para>If this is exceeded, the result is detection as a MACHINE</para>
                        </parameter>
                        <parameter name="greeting" required="false">
                                <para>is the maximum length of a greeting.</para>
-                               <para>If this is exceeded set as MACHINE</para>
+                               <para>If this is exceeded, the result is detection as a MACHINE</para>
                        </parameter>
                        <parameter name="afterGreetingSilence" required="false">
                                <para>Is the silence after detecting a greeting.</para>
-                               <para>If this is exceeded set as HUMAN</para>
+                               <para>If this is exceeded, the result is detection as a HUMAN</para>
                        </parameter>
                        <parameter name="totalAnalysis Time" required="false">
                                <para>Is the maximum time allowed for the algorithm</para>
-                               <para>to decide HUMAN or MACHINE</para>
+                               <para>to decide on whether the audio represents a HUMAN, or a MACHINE</para>
                        </parameter>
                        <parameter name="miniumWordLength" required="false">
                                <para>Is the minimum duration of Voice considered to be a word</para>
@@ -85,14 +85,14 @@ ASTERISK_REGISTER_FILE()
                        </parameter>
                        <parameter name="maximumNumberOfWords" required="false">
                                <para>Is the maximum number of words in a greeting</para>
-                               <para>If this is exceeded set as MACHINE</para>
+                               <para>If this is exceeded, then the result is detection as a MACHINE</para>
                        </parameter>
                        <parameter name="silenceThreshold" required="false">
-                               <para>How long do we consider silence</para>
+                               <para>What is the average level of noise from 0 to 32767 which if not exceeded, should be considered silence?</para>
                        </parameter>
                        <parameter name="maximumWordLength" required="false">
                                <para>Is the maximum duration of a word to accept.</para>
-                               <para>If exceeded set as MACHINE</para>
+                               <para>If exceeded, then the result is detection as a MACHINE</para>
                        </parameter>
                </syntax>
                <description>
@@ -130,7 +130,7 @@ ASTERISK_REGISTER_FILE()
                                        </value>
                                        <value name="MAXWORDS">
                                                Word Count - maximum number of words.
-                                       </value>        
+                                       </value>
                                </variable>
                        </variablelist>
                </description>
@@ -154,7 +154,7 @@ static int dfltAfterGreetingSilence = 800;
 static int dfltTotalAnalysisTime    = 5000;
 static int dfltMinimumWordLength    = 100;
 static int dfltBetweenWordsSilence  = 50;
-static int dfltMaximumNumberOfWords = 3;
+static int dfltMaximumNumberOfWords = 2;
 static int dfltSilenceThreshold     = 256;
 static int dfltMaximumWordLength    = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
 
@@ -367,7 +367,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
                                        sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
                                        break;
                                }
-                               if (iWordsCount >= maximumNumberOfWords) {
+                               if (iWordsCount > maximumNumberOfWords) {
                                        ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", ast_channel_name(chan), iWordsCount);
                                        ast_frfree(f);
                                        strcpy(amdStatus , "MACHINE");
index 540f662..11591bd 100644 (file)
@@ -2151,6 +2151,24 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                return -1;
        }
 
+       if (ast_check_hangup_locked(chan)) {
+               /*
+                * Caller hung up before we could dial.  If dial is executed
+                * within an AGI then the AGI has likely eaten all queued
+                * frames before executing the dial in DeadAGI mode.  With
+                * the caller hung up and no pending frames from the caller's
+                * read queue, dial would not know that the call has hung up
+                * until a called channel answers.  It is rather annoying to
+                * whoever just answered the non-existent call.
+                *
+                * Dial should not continue execution in DeadAGI mode, hangup
+                * handlers, or the h exten.
+                */
+               ast_verb(3, "Caller hung up before dial.\n");
+               pbx_builtin_setvar_helper(chan, "DIALSTATUS", "CANCEL");
+               return -1;
+       }
+
        parse = ast_strdupa(data);
 
        AST_STANDARD_APP_ARGS(args, parse);
index a2ed2c9..416ebff 100644 (file)
@@ -5214,6 +5214,11 @@ static int is_our_turn(struct queue_ent *qe)
                res = 0;
        }
 
+       /* Update realtime members if this is the first call and number of avalable members is 0 */
+       if (avl == 0 && qe->pos == 1) {
+               update_realtime_members(qe->parent);
+       }
+
        return res;
 }
 
index f2f7bad..cd55254 100644 (file)
@@ -48,7 +48,6 @@
 
 /*** MODULEINFO
        <defaultenabled>yes</defaultenabled>
-       <conflict>res_mwi_external</conflict>
        <use type="module">res_adsi</use>
        <use type="module">res_smdi</use>
        <support_level>core</support_level>
@@ -14702,10 +14701,14 @@ static int unload_module(void)
  *
  * Module loading including tests for configuration or dependencies.
  * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
- * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
- * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the 
- * configuration file or other non-critical problem return 
- * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
+ * or AST_MODULE_LOAD_SUCCESS.
+ *
+ * If a dependency, allocation or environment variable fails tests, return AST_MODULE_LOAD_FAILURE.
+ *
+ * If the module can't load the configuration file, can't register as a provider or
+ * has another issue not fatal to Asterisk itself, return AST_MODULE_LOAD_DECLINE.
+ *
+ * On success return AST_MODULE_LOAD_SUCCESS.
  */
 static int load_module(void)
 {
@@ -14714,7 +14717,7 @@ static int load_module(void)
        umask(my_umask);
 
        if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
-               return AST_MODULE_LOAD_DECLINE;
+               return AST_MODULE_LOAD_FAILURE;
        }
 
        /* compute the location of the voicemail spool directory */
@@ -14724,8 +14727,10 @@ static int load_module(void)
                ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor.  MWI will not work\n");
        }
 
-       if ((res = load_config(0)))
-               return res;
+       if ((res = load_config(0))) {
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
+       }
 
        res = ast_register_application_xml(app, vm_exec);
        res |= ast_register_application_xml(app2, vm_execmain);
@@ -14746,10 +14751,26 @@ static int load_module(void)
        res |= AST_TEST_REGISTER(test_voicemail_vm_info);
 #endif
 
-       res |= ast_vm_register(&vm_table);
-       res |= ast_vm_greeter_register(&vm_greeter_table);
        if (res) {
-               return res;
+               ast_log(LOG_ERROR, "Failure registering applications, functions or tests\n");
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
+       /* ast_vm_register may return DECLINE if another module registered for vm */
+       res = ast_vm_register(&vm_table);
+       if (res) {
+               ast_log(LOG_ERROR, "Failure registering as a voicemail provider\n");
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
+       /* ast_vm_greeter_register may return DECLINE if another module registered as a greeter */
+       res = ast_vm_greeter_register(&vm_greeter_table);
+       if (res) {
+               ast_log(LOG_ERROR, "Failure registering as a greeter provider\n");
+               unload_module();
+               return AST_MODULE_LOAD_DECLINE;
        }
 
        ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
@@ -14762,7 +14783,7 @@ static int load_module(void)
        ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
        ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
 
-       return res;
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context) 
index 617ca66..3c20e97 100644 (file)
@@ -95,7 +95,7 @@ static rc_handle *rh = NULL;
 
 #define RADIUS_BACKEND_NAME "CEL Radius Logging"
 
-#define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, &y, strlen(y), VENDOR_CODE))
+#define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, (void *)y, strlen(y), VENDOR_CODE))
 
 static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record)
 {
@@ -176,7 +176,7 @@ static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *r
        /* Setting Acct-Session-Id & User-Name attributes for proper generation
           of Acct-Unique-Session-Id on server side */
        /* Channel */
-       if (!rc_avpair_add(rh, send, PW_USER_NAME, &record->channel_name,
+       if (!rc_avpair_add(rh, send, PW_USER_NAME, (void *)record->channel_name,
                        strlen(record->channel_name), 0)) {
                return -1;
        }
index 378774a..b4c2602 100644 (file)
@@ -31510,6 +31510,8 @@ static int reload_config(enum channelreloadreason reason)
        sip_cfg.peer_rtupdate = TRUE;
        global_dynamic_exclude_static = 0;      /* Exclude static peers */
        sip_cfg.tcp_enabled = FALSE;
+       sip_cfg.websocket_enabled = TRUE;
+       sip_cfg.websocket_write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT;
 
        /* Session-Timers */
        global_st_mode = SESSION_TIMER_MODE_ACCEPT;
index d7323ec..d1764b5 100644 (file)
@@ -3,17 +3,25 @@
 ;
 
 [general]
+total_analysis_time = 5000     ; Maximum time allowed for the algorithm to decide
+                               ; on whether the audio represents a HUMAN, or a MACHINE
+silence_threshold = 256                ; If the average level of noise in a sample does not reach
+                               ; this value, from a scale of 0 to 32767, then we will consider
+                               ; it to be silence.
+
+; Greeting ;
 initial_silence = 2500         ; Maximum silence duration before the greeting.
-                               ; If exceeded then MACHINE.
-greeting = 1500                        ; Maximum length of a greeting. If exceeded then MACHINE.
+                               ; If exceeded, then the result is detection as a MACHINE.
 after_greeting_silence = 800   ; Silence after detecting a greeting.
-                               ; If exceeded then HUMAN
-total_analysis_time = 5000     ; Maximum time allowed for the algorithm to decide
-                               ; on a HUMAN or MACHINE
+                               ; If exceeded, then the result is detection as a HUMAN
+greeting = 1500                        ; Maximum length of a greeting. If exceeded, then the
+                               ; result is detection as a MACHINE.
+
+; Word detection ;
 min_word_length = 100          ; Minimum duration of Voice to considered as a word
+maximum_word_length = 5000     ; Maximum duration of a single Voice utterance allowed.
 between_words_silence = 50     ; Minimum duration of silence after a word to consider
                                ; the audio what follows as a new word
-maximum_number_of_words = 3    ; Maximum number of words in the greeting.
-                               ; If exceeded then MACHINE
-maximum_word_length = 5000      ; Maximum duration of a single Voice utterance allowed.
-silence_threshold = 256
+
+maximum_number_of_words = 2    ; Maximum number of words in the greeting
+                               ; If exceeded, then the result is detection as a MACHINE
diff --git a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py
new file mode 100644 (file)
index 0000000..ba972b6
--- /dev/null
@@ -0,0 +1,22 @@
+"""add_keep_alive_interval
+
+Revision ID: 189a235b3fd7
+Revises: 28ce1e718f05
+Create Date: 2015-12-16 11:23:16.994523
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '189a235b3fd7'
+down_revision = '339a3bdf53fc'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+    op.add_column('ps_globals', sa.Column('keep_alive_interval', sa.Integer))
+
+
+def downgrade():
+    op.drop_column('ps_globals', 'keep_alive_interval')
diff --git a/contrib/scripts/sipp-sendfax.xml b/contrib/scripts/sipp-sendfax.xml
new file mode 100644 (file)
index 0000000..a249808
--- /dev/null
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+<scenario name="INVITE (optional auth), re-INVITE to T38 and send a Fax, Walter Doekes 2012-2013">
+
+  <!--
+
+  NOTE: Creating a sipp-sendfax.pcap is as easy as:
+  - receive a fax with asterisk
+  - get the incoming side of the spansdp.log (use 'fax set debug on',
+    check your logger.conf)
+  - feed it to spandspflow2pcap.py
+
+  NOTE: sipp-sendfax.xml requires image pcap play support in SIPp. This
+  means a version above 3.5.0, or the master git branch from
+  https://github.com/SIPp/sipp.
+
+  -->
+
+  <label id="invite"/>
+
+  <send retrans="500" start_txn="invite">
+    <![CDATA[
+
+      INVITE sip:[tel]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sip:[service]@[local_ip]:[local_port];tag=[pid]SIPpTag00[call_number]
+      To: sip:[tel]@[remote_ip]:[remote_port]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] INVITE
+      Max-Forwards: 70
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=- 144969 144969 IN IP[local_ip_type] [local_ip]
+      s=-
+      c=IN IP[media_ip_type] [media_ip]
+      t=0 0
+      m=audio [media_port] RTP/AVP 8 0
+      a=rtpmap:8 PCMA/8000
+      a=rtpmap:0 PCMU/8000
+
+    ]]>
+  </send>
+
+  <recv response="100" optional="true" response_txn="invite"/>
+
+  <recv response="180" optional="true" response_txn="invite"/>
+
+  <recv response="181" optional="true" response_txn="invite"/>
+
+  <recv response="183" optional="true" response_txn="invite"/>
+
+  <recv response="200" optional="true" rrs="true" response_txn="invite" next="invite-ack"/>
+
+  <recv response="401" optional="true" rrs="true" next="invite-with-auth" auth="true" rrs="true" response_txn="invite"/>
+
+  <recv response="407" auth="true" rrs="true" response_txn="invite"/>
+
+  <label id="invite-with-auth"/>
+
+  <send ack_txn="invite">
+    <![CDATA[
+
+      ACK sip:[tel]@[remote_ip]:[remote_port] SIP/2.0
+      [last_Via:]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] ACK
+      Max-Forwards: 70
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <send retrans="500" start_txn="invite">
+    <![CDATA[
+
+      INVITE sip:[tel]@[remote_ip]:[remote_port] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      From: sip:[service]@[local_ip]:[local_port];tag=[pid]SIPpTag00[call_number]
+      To: sip:[tel]@[remote_ip]:[remote_port]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      [authentication]
+      Call-ID: [call_id]
+      CSeq: [cseq] INVITE
+      Max-Forwards: 70
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=- 144969 144969 IN IP[local_ip_type] [local_ip]
+      s=-
+      c=IN IP[media_ip_type] [media_ip]
+      t=0 0
+      m=audio [media_port] RTP/AVP 8 0
+      a=rtpmap:8 PCMA/8000
+      a=rtpmap:0 PCMU/8000
+
+    ]]>
+  </send>
+
+  <recv response="100" response_txn="invite"/>
+
+  <recv response="180" optional="true" response_txn="invite"/>
+
+  <recv response="181" optional="true" response_txn="invite"/>
+
+  <recv response="183" optional="true" response_txn="invite"/>
+
+  <recv response="200" rrs="true" response_txn="invite"/>
+
+  <label id="invite-ack"/>
+
+  <send ack_txn="invite">
+    <![CDATA[
+
+      ACK [next_url] SIP/2.0
+      [last_Via:]
+      [routes]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] ACK
+      Max-Forwards: 70
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- Send a bit of noise to start the RTP. You may need to use
+       the -i MY_IP command line option. -->
+  <pause milliseconds="500"/>
+
+  <nop>
+    <action>
+      <exec play_pcap_audio="g711a.pcap"/>
+    </action>
+  </nop>
+
+  <pause milliseconds="500"/>
+
+
+  <!-- *****************************************************************
+
+  Initiate re-INVITE to T38.
+
+  ****************************************************************** -->
+
+  <send start_txn="t38invite">
+    <![CDATA[
+
+      INVITE [next_url] SIP/2.0
+      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+      [routes]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] INVITE
+      Max-Forwards: 70
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=- 145280 145280 IN IP[local_ip_type] [local_ip]
+      s=-
+      c=IN IP[media_ip_type] [media_ip]
+      t=0 0
+      m=image [media_port] udptl t38
+      a=T38FaxVersion:0
+      a=T38MaxBitRate:14400
+      a=T38FaxRateManagement:transferredTCF
+      a=T38FaxMaxBuffer:200
+      a=T38FaxMaxDatagram:200
+      a=T38FaxUdpEC:t38UDPRedundancy
+
+    ]]>
+  </send>
+
+  <recv response="100" optional="true" response_txn="t38invite"/>
+
+  <recv response="488" optional="true" response_txn="t38invite" next="abort"/>
+
+  <recv response="200" response_txn="t38invite"/>
+
+  <send ack_txn="t38invite">
+    <![CDATA[
+
+      ACK [next_url] SIP/2.0
+      [last_Via:]
+      [routes]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] ACK
+      Max-Forwards: 70
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <!-- Enable the nop/action below to replay the FAX image. You may need to use
+       the -i MY_IP command line option. -->
+  <pause milliseconds="500"/>
+
+  <nop>
+    <action>
+      <exec play_pcap_image="sipp-sendfax.pcap"/>
+    </action>
+  </nop>
+
+
+  <!-- *****************************************************************
+
+  Wait for re-INVITE back to audio.
+
+  ****************************************************************** -->
+
+  <recv request="INVITE"/>
+
+  <send retrans="500">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_Record-Route:]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Max-Forwards: 70
+      Content-Type: application/sdp
+      Content-Length: [len]
+
+      v=0
+      o=- 146312 146312 IN IP[local_ip_type] [local_ip]
+      s=-
+      c=IN IP[media_ip_type] [media_ip]
+      t=0 0
+      m=audio [media_port] RTP/AVP 8 0
+      a=rtpmap:8 PCMA/8000
+      a=rtpmap:0 PCMU/8000
+
+    ]]>
+  </send>
+
+  <recv request="ACK"/>
+
+  <recv request="BYE"/>
+
+  <send next="done">
+    <![CDATA[
+
+      SIP/2.0 200 OK
+      [last_Via:]
+      [last_Record-Route:]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      [last_Call-ID:]
+      [last_CSeq:]
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+
+  <!-- *****************************************************************
+
+  Abort the call ourselves
+
+  ****************************************************************** -->
+
+  <label id="abort"/>
+
+  <send ack_txn="t38invite">
+    <![CDATA[
+
+      ACK [next_url] SIP/2.0
+      [last_Via:]
+      [routes]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] ACK
+      Max-Forwards: 70
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <send start_txn="bye">
+    <![CDATA[
+
+      BYE [next_url] SIP/2.0
+      [last_Via:]
+      [routes]
+      [last_From:]
+      [last_To:]
+      Contact: sip:[service]@[local_ip]:[local_port]
+      Call-ID: [call_id]
+      CSeq: [cseq] BYE
+      Max-Forwards: 70
+      Content-Length: 0
+
+    ]]>
+  </send>
+
+  <recv response="200" response_txn="bye" next="done"/>
+
+
+  <!-- *****************************************************************
+
+  Finalize
+
+  ****************************************************************** -->
+
+  <label id="done"/>
+
+  <!-- Keep call open to be able to retransmit stuff -->
+  <timewait milliseconds="2000"/>
+
+</scenario><!-- vim: set ts=8 sw=2 sts=2 et ai: -->
diff --git a/contrib/scripts/spandspflow2pcap.log b/contrib/scripts/spandspflow2pcap.log
new file mode 100644 (file)
index 0000000..7ed0ed9
--- /dev/null
@@ -0,0 +1,605 @@
+[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     0: indicator no-signal
+[2015-12-02 11:55:55] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     1: indicator ced
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     2: IFP 00
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     2: indicator no-signal
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     3: IFP 06
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     3: indicator v21-preamble
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 1
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 1
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_A_CED to T30_PHASE_B_RX
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4
+[2015-12-02 11:55:58] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     4: IFP c0 01 80 00 00 ff
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     4: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     5: IFP c0 01 80 00 00 c0
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     5: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     6: IFP c0 01 80 00 00 c2
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     6: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     7: IFP c0 01 80 00 00 76
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     7: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     8: IFP c0 01 80 00 00 ee
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     8: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     9: IFP c0 01 80 00 00 f6
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx     9: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    10: IFP c0 01 80 00 00 76
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    10: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    11: IFP c0 01 80 00 00 d6
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    11: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    12: IFP c0 01 80 00 00 76
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    12: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    13: IFP c0 01 80 00 00 ae
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    13: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    14: IFP c0 01 80 00 00 04
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    14: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    15: IFP c0 01 80 00 00 04
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    15: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    16: IFP c0 01 80 00 00 04
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    16: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    17: IFP c0 01 80 00 00 04
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    17: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    18: IFP c0 01 80 00 00 04
+[2015-12-02 11:55:59] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    18: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    19: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    19: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    20: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    20: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    21: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    21: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    22: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    22: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    23: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    23: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    24: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    24: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    25: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    25: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    26: IFP c0 01 80 00 00 04
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    26: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    27: IFP c0 01 20
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    27: (0) data v21/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type TSI - CRC OK (clean)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  TSI without final frame tag
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 43 6e 77 6f 6e 6b 6e 75 20 20 20 20 20 20 20 20 20 20 20 20 20
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Remote gave TSI as: "unknown"
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    28: IFP c0 01 80 00 00 ff
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    28: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    29: IFP c0 01 80 00 00 c8
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    29: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    30: IFP c0 01 80 00 00 c1
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    30: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    31: IFP c0 01 80 00 00 00
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    31: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    32: IFP c0 01 80 00 00 46
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    32: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    33: IFP c0 01 80 00 00 1f
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    33: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    34: IFP c0 01 80 00 00 22
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    34: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    35: IFP c0 01 40
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    35: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCS - CRC OK, sig end (clean)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  DCS with final frame tag
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 13 83 00 62 f8 44
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 1
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS before DIS
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 DCS:
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... ...0= Store and forward Internet fax (T.37): Not set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... .0..= Real-time Internet fax (T.38): Not set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... 0...= 3G mobile network: Not set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... ..1.= Receive fax: Set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   ..10 00..= Selected data signalling rate: V.17 14400bps
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .1.. ....= R8x7.7lines/mm and/or 200x200pels/25.4mm: Set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   0... ....= 2-D coding: Not set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... ..00= Recording width: 215mm +- 1%
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... 10..= Recording length: Unlimited
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .111 ....= Minimum scan line time: 0ms
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   1... ....= Extension indicator: Set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... ..0.= Compressed/uncompressed mode: Compressed
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... .1..= Error correction mode (ECM): ECM
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .... 0...= Frame size: 256 octets
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   .1.. ....= T.6 coding: Set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30   0... ....= Extension indicator: Not set
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Selected compression T.6 (3)
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Get document at 14400bps, modem 7
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 1 to 7
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 7
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_RX to T30_PHASE_C_NON_ECM_RX
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    36: IFP 00
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    36: indicator no-signal
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    37: IFP 1e
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    37: indicator v17-14400-long-training
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present
+[2015-12-02 11:56:00] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    38: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    38: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Training succeeded (-4) in state 7
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    39: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    39: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    40: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    40: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    41: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    41: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    42: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    42: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    43: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    43: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    44: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    44: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    45: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    45: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    46: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    46: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    47: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    47: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    48: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    48: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    49: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    49: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    50: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    50: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    51: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    51: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    52: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    52: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    53: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    53: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    54: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    54: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    55: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    55: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    56: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    56: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    57: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    57: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    58: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    58: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    59: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    59: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    60: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    60: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    61: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    61: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    62: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:02] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    62: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    63: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    63: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    64: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    64: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    65: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    65: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    66: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    66: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    67: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    67: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    68: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    68: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    69: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    69: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    70: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    70: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    71: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    71: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    72: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    72: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    73: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    73: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    74: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    74: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    75: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    75: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    76: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    76: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    77: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    77: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    78: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    78: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    79: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    79: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    80: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    80: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    81: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    81: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    82: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    82: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    83: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    83: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    84: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    84: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    85: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    85: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    86: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    86: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    87: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    87: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    88: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    88: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    89: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    89: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    90: IFP d0 01 e0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    90: (0) data v17-14400/t4-non-ecm-data + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    91: IFP d0 01 f0 00 35 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    91: (0) data v17-14400/t4-non-ecm-sig-end + 54 byte(s)
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Receive complete in phase T30_PHASE_C_NON_ECM_RX, state 7
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Non-ECM signal status is Carrier down (-1) in state 7
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Trainability (TCF) test result - 23328 total bits. longest run of zeros was 23328
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_NON_ECM_RX to T30_PHASE_B_TX
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 7 to 8
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx:  CFR with final frame tag
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx:  ff 13 84
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    92: IFP 00
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    92: indicator no-signal
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     2: indicator no-signal
+[2015-12-02 11:56:03] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     3: indicator v21-preamble
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     4: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     4: IFP c0 01 80 00 00 ff
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     5: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     5: IFP c0 01 80 00 00 c8
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     6: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     6: IFP c0 01 80 00 00 21
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     7: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     7: IFP c0 01 40
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_B_TX, state 8
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 8 to 12
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_B_TX to T30_PHASE_C_ECM_RX
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 7
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:04] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     8: indicator no-signal
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    93: IFP 1c
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    93: indicator v17-14400-short-training
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (51520 remaining)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    94: IFP d0 01 80 00 35 ff c0 60 00 ff ff ff ff ff ff ff ff 2b 92 8a 4c c2 9d 8b 22 38 68 23 a8 22 87 0c 8e 90 60 81 21 10 c8 ea da b1 91 d5 06 e1 38 55 04 ed b6 b5 49 7b df c2 45 90 c9
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    94: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    95: IFP d0 01 80 00 35 17 45 d1 84 54 91 74 5d 18 45 2d 17 44 55 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 74 76 24 8b a2 e8 c2 25 08 ba 2e 8b a2 e8 ba 2e 8b a2 e8 ba 2e 8b a3 b1 24 61 17
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    95: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    96: IFP d0 01 80 00 35 44 b1 17 45 d1 74 5d 17 45 d1 74 5d 17 45 d1 75 ed b2 ba 11 1c 8c 81 51 1c ce c1 51 1c 08 23 a2 2e 88 e1 9c 8e 8a 9a 08 49 98 28 71 11 11 11 11 11 06 76 a1 11 c3
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    96: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    97: IFP d0 01 80 00 35 39 1d 04 22 22 22 22 22 24 f6 a0 a1 c4 48 a3 94 06 50 e2 22 22 22 22 22 0f a4 08 a1 d0 41 46 10 51 a1 1c 47 1b c4 60 8a 1e 84 64 75 1f 77 8c 20 a2 d3 23 a4 1a 60
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    97: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    98: IFP d0 01 80 00 2b 8a 1d a0 dd 30 8a 1d f5 50 54 30 45 0e 30 45 0f 23 a0 a3 82 28 79 1d 61 06 3d db a2 3a b5 42 0e 23 50 8a 1f 11 84 50 ed 03 5a 54 11
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    98: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    99: IFP d0 01 20
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx    99: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 00 ff ff ff ff ff ff ff ff d4 49 51 32 43 b9 d1 44 1c 16 c4 15 44 e1 30 71 09 06 81 84 08 13 57 5b 8d 89 ab 60 87 1c aa 20 b7 6d ad 92 de fb 43 a2 09 93 e8 a2 8b 21 2a 89 2e ba 18 a2 b4 e8 22 aa e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b 2e 6e 24 d1 45 17 43 a4 10 5d 74 d1 45 17 5d 74 d1 45 17 5d 74 d1 c5 8d 24 86 e8 22 8d e8 a2 8b 2e ba e8 a2 8b 2e ba e8 a2 8b ae b7 4d 5d 88 38 31 81 8a 38 73 83 8a 38 10 c4 45 74 11 87 39 71 51 59 10 92 19 14 8e 88 88 88 88 88 60 6e 85 88 c3 9c b8 20 44 44 44 44 44 24 6f 05 85 23 12 c5 29 60 0a 47 44 44 44 44 44 f0 25 10 85 0b 82 62 08 8a 85 38 e2 d8 23 06 51 78 21 26 ae f8 ee 31 04 45 cb c4 25 58 06 51 b8 05 bb 0c 51 b8 af 0a 2a 0c a2 70 0c a2 f0 c4 05 c5 41 14 9e b8 86 60 bc db 45 5c ad 42 70 c4 0a 51 f8 88 21 0a b7 c0 5a 2a 88
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 0, length 256
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   100: IFP d0 01 80 00 35 ff c0 60 80 43 c5 25 0a 10 61 5c 10 63 41 56 1a d9 0d 04 2f b0 8a 1d 84 50 fd be de d2 d2 2a 11 1d 2e 15 dd 42 84 50 f5 23 ae d1 74 f4 28 a5 f5 7c 34 19 02 40 af
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   100: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   101: IFP d0 01 80 00 35 0c 6c 22 87 61 14 3e 11 50 10 ac 23 08 48 e8 ba ad 42 a1 e1 42 51 0c 78 8b 74 08 10 88 df 0e 18 22 87 84 50 f8 6e 11 43 bf 4a 29 74 93 8e 96 e1 14 3f bb f7 60 bd
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   101: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   102: IFP d0 01 80 00 35 84 50 ef 1a af fe 6b 0d 30 8a 1d 63 09 48 e8 22 87 56 ea f0 c8 31 6c 22 87 21 b2 24 75 8c 83 ec a0 a1 c8 6c 89 1d 48 3e ca 88 6c 86 c8 60 c1 52 32 49 35 d8 20 45
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   102: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   103: IFP d0 01 80 00 35 5a 61 06 d5 23 e8 fa 60 83 69 1e 47 d0 45 0e 10 45 5e 8f a3 e8 f2 19 5c a9 18 45 d1 74 47 44 74 47 44 74 47 44 74 47 44 74 47 58 22 9d 97 45 d1 74 47 44 74 47 44
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   103: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   104: IFP d0 01 80 00 2b 74 5d 17 40 8a 79 74 61 02 28 70 cb a2 ea 88 e8 5e 10 6f a1 1a 23 a3 09 b6 c4 5a 16 1d 08 8c c8 c0 72 28 1c e8 1a 44 69 11 c3 0a 77
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   104: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   105: IFP d0 01 20
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   105: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 01 c2 a3 a4 50 08 86 3a 08 c6 82 6a 58 9b b0 20 f4 0d 51 b8 21 0a bf 7d 7b 4b 4b 54 88 b8 74 a8 bb 42 21 0a af c4 75 8b 2e 2f 14 a5 af 3e 2c 98 40 02 f5 30 36 44 e1 86 28 7c 88 0a 08 35 c4 10 12 17 5d b5 42 85 87 42 8a 30 1e d1 2e 10 08 11 fb 70 18 44 e1 21 0a 1f 76 88 c2 fd 52 94 2e c9 71 69 87 28 fc dd ef 06 bd 21 0a f7 58 f5 7f d6 b0 0c 51 b8 c6 90 12 17 44 e1 6a 57 0f 13 8c 36 44 e1 84 4d 24 ae 31 c1 37 05 85 13 36 91 b8 12 7c 53 11 36 61 13 06 83 4a 4c 92 ac 1b 04 a2 5a 86 60 ab c4 17 5f 06 c1 96 78 e2 0b a2 70 08 a2 7a f1 c5 17 4f 98 3a 95 18 a2 8b 2e e2 22 2e e2 22 2e e2 22 2e e2 22 2e e2 1a 44 b9 e9 a2 8b 2e e2 22 2e e2 22 2e ba e8 02 51 9e 2e 86 40 14 0e d3 45 57 11 17 7a 08 f6 85 58 c4 c5 90 6d 23 5a 68 b8 10 31 13 03 4e 14 38 17 58 22 96 88 c3 50 ee
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 1, length 256
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   106: IFP d0 01 80 00 35 ff c0 60 40 40 53 3a a2 3a 23 82 82 3a 29 03 90 60 e4 74 77 c0 a6 49 a2 38 30 47 44 59 11 c3 61 1d 12 e0 a6 8a 1d 0b 84 8b a0 45 45 54 8e 82 42 21 d2 08 a1 d2 28
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   106: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   107: IFP d0 01 80 00 35 74 b4 e1 c3 08 28 b6 d0 71 11 06 99 1d 21 a6 08 12 11 61 05 11 64 75 0c 58 20 8a 76 d0 88 45 3c 8e 9d c5 a0 8a 79 1d 3b 45 d0 b0 db ea 94 45 50 52 3a 4d 76 e2 35
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   107: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   108: IFP d0 01 80 00 35 41 18 42 d0 48 ba 1b 7c 24 5d 0d aa 42 d5 6f c1 14 3e db 6c 8e ae c2 64 74 08 a1 de 23 b8 b7 db 8b bd 58 45 0e eb f1 d0 41 91 d5 d2 40 87 1e 77 a2 23 ad 69 14 3d
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   108: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   109: IFP d0 01 80 00 35 25 c8 e9 57 1a bf 69 ec 6d 82 28 74 e9 91 d2 78 8b 7b 63 be e3 b6 df d6 81 14 3a 5b 76 b4 c2 5a 54 11 43 d9 0c 3d 68 22 87 6b 09 a5 ef bb 76 c3 4a ec 8e bf a1 78
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   109: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   110: IFP d0 01 80 00 2b 4e c3 a1 77 23 a0 8a 1e 11 43 dc 8e bd 6b 4a 92 a4 08 a1 d8 45 0f d5 48 e8 fa 23 a2 3a 08 a1 ed 17 5e 47 44 74 47 44 74 5d 29 a2 23
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   110: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   111: IFP d0 01 20
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   111: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 02 02 ca 5c 45 5c c4 41 41 5c 94 c0 09 06 27 2e ee 03 65 92 45 1c 0c e2 22 9a 88 c3 86 b8 48 07 65 51 b8 d0 21 d1 05 a2 a2 2a 71 41 42 84 4b 10 85 4b 14 2e 2d 87 c3 10 14 6d 0b 8e 88 60 99 b8 84 65 10 48 88 86 a0 88 26 ae 30 1a 04 51 6e 0b 11 a2 3c 71 b9 a3 05 51 9e b8 dc a2 0b 0d db 57 29 a2 0a 4a 5c b2 6e 47 ac 82 18 42 0b 12 5d d8 3e 24 ba b0 55 42 ab f6 83 28 7c db 36 71 75 43 26 2e 10 85 7b c4 1d ed db d1 bd 1a a2 70 d7 8f 0b 82 89 ab 4b 02 e1 78 ee 45 c4 b5 96 28 bc a4 13 97 ea 58 fd 96 37 b6 41 14 2e 97 89 4b 1e d1 de c6 7d c7 6d fb 6b 81 28 5c da 6e 2d 43 5a 2a 88 c2 9b 30 bc 16 44 e1 d6 90 a5 f7 dd 6e c3 52 37 71 fd 85 1e 72 c3 85 ee c4 05 51 78 88 c2 3b 71 bd d6 52 49 25 10 85 1b a2 f0 ab 12 17 5f c4 45 5c 10 85 b7 e8 7a e2 22 2e e2 22 2e ba 94 45 c4
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 2, length 256
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   112: IFP d0 01 80 00 35 ff c0 60 c0 a2 3a 2e 82 28 7d 97 44 74 47 44 74 5d 34 5d 1e 44 74 47 44 74 3a 19 1d 11 d1 1d 11 d1 75 b0 8a 1d d8 45 0e ed 86 1b 23 aa 23 a7 61 b7 db 42 10 4c 43
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   112: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   113: IFP d0 01 80 00 35 08 21 6c 22 9c 21 c2 28 71 11 10 cc 22 3a 68 ba 08 28 88 63 c4 44 58 91 d1 75 88 41 31 16 11 4e e2 22 21 97 44 75 48 6a 9a ae e8 70 90 4b 04 50 eb 6c 11 43 a1 12
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   113: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   114: IFP d0 01 80 00 35 3a c6 0c 71 6c 11 51 43 1a 6c 52 8c 6f ff 6d ad c3 7c 6b 23 a0 45 0e c5 ca 74 5d 0e 83 23 a2 ea c1 14 3b 08 a1 db 64 74 61 64 74 83 6e 0c 8e b9 1d 04 50 f2 3a c2
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   114: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   115: IFP d0 01 80 00 35 ee 8a 1e 47 41 14 3a a4 95 a0 aa 2d e2 3c 62 47 49 36 35 16 91 85 88 45 0e 9a b2 eb 89 c4 47 0a e2 db b4 47 41 14 3c 5b 8a 6a c8 ea ee 9f 08 a1 df 21 aa e5 6c 3d
+[2015-12-02 11:56:05] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   115: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   116: IFP d0 01 80 00 2b f1 0c 76 c2 28 7c 43 23 ae f9 ad 1d 01 70 a0 ca e2 04 0b e3 3b ad 1c 02 0d a3 68 da 36 82 28 77 08 19 56 50 e4 33 d9 56 55 95 65 6c
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   116: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   117: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   117: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 03 45 5c 74 41 14 be e9 22 2e e2 22 2e ba 2c ba 78 22 2e e2 22 2e 5c 98 b8 88 8b b8 88 8b ae 0d 51 b8 1b a2 70 b7 61 d8 c4 55 c4 e5 86 ed db 42 08 32 c2 10 84 36 44 39 84 43 14 8e 88 08 33 44 5c 16 5d 10 14 11 c6 23 22 1a 89 8b ae 11 82 8c 68 88 72 47 44 84 e9 22 ae 12 56 59 75 17 0e 09 d2 20 0a d7 36 88 c2 85 48 5c 63 30 8e 36 88 8a c2 58 36 4a 31 f6 ff b6 b5 c3 3e d6 c4 05 a2 70 a3 53 2e ba 70 c1 c4 45 57 83 28 dc 10 85 db 26 2e 86 26 2e c1 76 30 71 9d b8 20 0a 4f 5c 43 77 51 78 e2 82 28 5c 25 a9 05 55 b4 47 3c 46 e2 92 6c ac 68 89 a1 11 a2 70 59 4d d7 91 23 e2 50 47 db 2d e2 82 28 3c da 51 56 13 57 77 f9 10 85 fb 84 55 a7 36 bc 8f 30 6e 43 14 3e c2 c4 75 9f b5 b8 80 0e 05 53 47 20 d0 c7 dc b5 38 40 b0 c5 16 5b 6c 41 14 ee 10 98 6a 0a 27 cc 9b 6a aa a9 a6 36
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 3, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   118: IFP d0 01 80 00 35 ff c0 60 20 4c a1 d1 75 a7 5c 3a 5d 3f 1c 8e ae e4 74 9e 08 10 98 45 d1 74 11 4f 90 d1 46 08 10 84 54 23 68 ba 2e 8b a2 e8 ba 2e 91 50 74 ed c1 02 10 8a 74 08 10
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   118: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   119: IFP d0 01 80 00 35 88 89 74 c8 67 43 90 60 38 20 42 21 84 08 10 88 88 d0 ee fd 91 d5 f6 d9 1d 5d dd c2 28 78 84 50 f0 8a 1e 22 22 2e 91 74 8a 1d 08 d0 88 88 88 88 40 83 29 ca 20 a7
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   119: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   120: IFP d0 01 80 00 35 48 21 16 84 42 08 c2 0f 91 d0 45 42 23 a1 c4 ed 4d 05 49 42 28 7f 69 75 74 92 a6 47 51 86 39 1d 0d db 42 2f 62 22 2d 87 b7 10 8a 77 88 a2 85 ae f8 df 64 74 42 03
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   120: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   121: IFP d0 01 80 00 35 5b ee 11 43 86 47 44 18 35 ee ed d2 4d 05 54 5d 3d 06 9a a0 82 16 b1 2e 8b ac 11 43 85 e9 71 85 f5 1b 4f f8 77 76 f5 16 ec 22 87 61 14 eb 61 3e 47 42 3b 57 bf 91
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   121: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   122: IFP d0 01 80 00 2b d5 de dc 34 fb ef 91 d2 91 d1 84 92 c2 a4 87 1a 5c 8e 8d 49 3b c1 14 3a 4b d6 f4 b4 92 ad 2f b8 d8 ed ee e4 11 17 44 74 47 44 74 47
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   122: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   123: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   123: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 04 32 85 8b ae e5 3a 5c ba fc 38 71 75 27 2e 79 10 08 19 a2 8b 2e 88 f2 09 8b 62 10 08 21 2a c4 16 5d 74 d1 45 17 5d 74 89 0a 2e b7 83 40 08 51 2e 10 08 11 91 2e 13 e6 c2 09 06 1c 04 42 84 21 10 08 11 11 0b 77 bf 89 ab 6f 9b b8 ba bb 43 14 1e 21 0a 0f 51 78 44 44 74 89 2e 51 b8 10 0b 11 11 11 11 02 c1 94 53 04 e5 12 84 68 21 42 10 43 f0 89 0b a2 42 c4 85 23 b7 b2 a0 92 42 14 fe 96 ae 2e 49 65 e2 8a 61 9c b8 b0 db 42 f4 46 44 b4 e1 ed 08 51 ee 11 45 a1 75 1f fb 26 2e 42 c0 da 77 88 c2 61 e2 22 18 ac 77 b7 4b b2 a0 2a ba bc 60 59 05 41 68 8d 74 d1 35 88 c2 a1 97 8e a1 af d8 f2 1f ee 6e af 68 37 44 e1 86 28 d7 86 7c e2 42 dc ea fd 89 ab 7b 3b 2c df f7 89 4b 89 8b 21 49 43 25 e1 58 3a 71 b1 92 dc 83 28 5c d2 6b 2f 2d 49 b5 f4 1d 1b b7 77 27 88 e8 22 2e e2 22 2e e2
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 4, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   124: IFP d0 01 80 00 35 ff c0 60 a0 44 74 47 44 74 08 a1 ee 47 4d c4 19 1d 11 d1 1d 11 d1 1d 04 14 6c 86 c1 ca 72 8a ed b6 d0 45 0e dd bd b7 76 1f be e4 75 08 a1 e4 75 91 d5 17 55 45 d2
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   124: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   125: IFP d0 01 80 00 35 e0 81 31 11 11 11 11 a4 34 84 44 44 46 85 89 1d 60 8a 1c 2a c6 b4 50 f2 3a 5a 4b 7f d4 22 87 71 bb 08 a1 d8 dd 8b 76 21 43 db b0 7b 0b c1 14 fc 49 01 a4 de e1 14
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   125: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   126: IFP d0 01 80 00 35 3b 2a 03 4e f6 9c 48 61 a4 47 55 04 50 f1 a4 92 49 22 52 82 c2 49 58 64 75 82 28 74 a4 75 42 b9 02 46 11 38 66 52 b4 d1 ad 18 44 e1 97 5a 82 29 e6 a4 61 13 86 64
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   126: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   127: IFP d0 01 80 00 35 38 b9 1d 53 bb b6 10 4e ef 84 50 e3 2e b6 8b a6 c3 de 22 11 57 23 ad c8 e9 a2 3a c4 4f 24 54 07 76 1a 1a 11 45 47 69 84 50 f2 3a fe 9c 22 9d 78 86 32 3a c1 14 3c
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   127: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   128: IFP d0 01 80 00 2b 76 15 62 11 56 d6 c1 15 08 71 14 54 2e 83 09 48 e8 a8 42 8a 89 1d 42 28 77 b8 de 11 43 bb 04 50 f1 c8 ea f0 8a 71 91 d5 b0 b1 08 a1
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   128: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   129: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   129: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 05 22 2e e2 22 2e 10 85 77 e2 b2 23 98 b8 88 8b b8 88 8b b8 20 28 36 61 83 53 4e 51 b7 6d 0b a2 70 bb bd ed 6e f8 7d 27 ae 10 85 27 ae 89 ab e8 aa a2 4b 07 81 8c 88 88 88 88 25 2c 21 22 22 62 a1 91 b8 06 51 38 54 63 2d 0a 4f 5c 5a d2 fe 2b 44 e1 8e dd 10 85 1b bb d1 6e 84 c2 db 0d de d0 83 28 3f 92 80 25 7b 87 28 dc 54 c0 72 6f 39 12 86 25 e2 aa 20 0a 8f 25 49 92 44 4a 41 43 92 1a 26 ae 41 14 2e 25 ae 42 9d 40 62 88 1c 66 4a 2d 8b b5 18 22 87 e9 5a 41 94 67 25 86 c8 61 26 1c 9d b8 ca dd 6d 08 72 f7 21 0a c7 74 6d d1 65 c3 7b 44 88 ea c4 b5 13 97 45 5c 23 f2 24 2a e0 6e 58 58 88 a2 e2 96 21 0a 4f 5c 7f 39 44 b9 1e 61 4c 5c 83 28 3c 6e a8 46 88 6a 6b 83 a8 10 8e 28 2a 74 c1 90 12 17 15 42 51 91 b8 42 14 ee 1d 7b 88 c2 dd 20 0a 8f 13 57 0f 51 8e 89 ab 0d 8d 10 85
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 5, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   130: IFP d0 01 80 00 35 ff c0 60 60 f9 17 42 11 59 7c 42 2b 48 83 d6 11 47 2a 22 22 7c 33 c6 3d 2c 69 27 51 4b 1b a0 45 0e 94 cd 1b 43 e2 2f a8 9b 40 8a 1e 1f c8 e8 4d a1 57 b8 22 9e fe
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   130: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   131: IFP d0 01 80 00 35 e0 8a 7b 0d bb 6c 8e b6 9b 23 a1 1b c2 29 fb 91 d0 8b 61 14 ed bc 46 c2 29 f5 15 d5 71 50 45 0e 8c 2a a0 d9 75 82 28 74 5d 50 82 28 75 8b d6 34 34 95 84 50 e8 5e
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   131: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   132: IFP d0 01 80 00 35 df 6d b7 6a c3 1f 0d 8e 34 36 3e d8 68 8e a1 ab 61 85 64 74 38 45 3f a4 95 24 90 55 5c 11 58 c8 eb 04 50 e1 29 1d 6a 11 43 a1 14 81 14 3f 1a 10 45 0f 1f 16 f6 ed
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   132: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   133: IFP d0 01 80 00 35 bc 36 f1 0d ee d8 22 87 b8 ed 91 d0 ee d8 dd d2 f2 eb ac 22 87 55 41 15 0f 04 50 eb 1f f1 ae c2 55 7b b1 bb c2 09 b2 ea da 23 a1 08 ab 76 c2 61 af 76 a4 75 84 50
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   133: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   134: IFP d0 01 80 00 2b ed fe 96 95 22 1b 03 8a 62 b2 0b ee 9a a4 ab a7 51 08 a1 e3 4a bb 6e 1b ec 11 b4 61 3a 0d e8 c2 26 88 3e 11 43 dc 22 87 e1 14 3c 22
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   134: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   135: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   135: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 06 9f e8 42 88 9a 3e 42 d4 12 c1 6b 88 e2 54 44 44 3e cc 63 bc 34 96 e4 8a d2 d8 05 a2 70 29 b3 d8 c2 47 f4 15 d9 02 51 78 f8 13 17 b2 85 ea 1d 44 79 7f 07 51 de b0 dd 36 71 6d d9 c4 85 d8 43 94 df 89 0b d1 86 28 b7 3d 62 43 94 af a8 ab 8e 0a a2 70 31 54 05 9b ae 41 14 2e ba 0a 41 14 ae d1 6b 2c 2c a9 21 0a 17 7a fb b6 ed 56 c3 f8 b0 71 2c 6c 7c 1b 16 71 85 d5 86 a1 26 2e 1c a2 fc 25 a9 24 09 aa 3a 88 1a 13 d7 20 0a 87 94 b8 56 88 c2 85 28 81 28 fc 58 08 a2 f0 f8 68 6f b7 3d 6c 8f b0 77 1b 44 e1 1d b7 89 0b 77 1b bb 4b 4f d7 35 44 e1 aa 82 a8 f0 20 0a d7 f8 8f 75 43 aa de 8d dd 43 90 4d 57 5b c4 85 10 d5 6e 43 86 f5 6e 25 ae 21 0a b7 7f 69 a9 44 d8 c0 51 46 4d d0 77 59 25 d5 e5 8a 10 85 c7 52 dd 76 d8 37 88 2d 86 5c b0 17 43 64 11 7c 88 c2 3b 44 e1 87 28 3c 44
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 6, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   136: IFP d0 01 80 00 35 ff c0 60 e0 87 6e d4 3d ec 82 81 d5 6a a9 02 04 22 11 43 c2 28 75 a8 41 09 18 8b a2 e8 84 46 10 f6 d5 be e3 82 28 74 5d 12 11 26 82 91 d5 02 28 74 4b 10 58 45 0f
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   136: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   137: IFP d0 01 80 00 35 7d cb a6 db b1 1d b2 3a b2 3a 3a 22 e8 ba 63 38 85 84 25 d0 41 34 61 3e 47 47 44 5d 17 49 36 47 49 17 59 50 88 e8 8e 88 e8 83 41 5b 23 a6 c4 20 84 ba 2e 87 16 cb
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   137: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   138: IFP d0 01 80 00 35 a1 a3 a2 23 a2 3a 23 a0 82 78 d2 4b 0e aa b5 14 c5 21 60 c4 90 81 03 10 82 88 62 47 4f 62 29 04 50 e8 22 9d 82 28 74 38 20 4c 62 47 41 04 e9 82 28 70 81 02 68 4d
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   138: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   139: IFP d0 01 80 00 35 68 15 b1 3e 82 91 d0 20 4c 62 47 42 bc 39 1d 37 64 74 47 4b 6d 91 d7 21 88 6d 91 d1 a2 04 09 03 23 a0 8a 1c 33 08 ba 04 09 94 38 6c 31 27 41 14 3b 86 47 46 88 b9
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   139: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   140: IFP d0 01 80 00 2b 91 d3 44 74 30 c8 e9 c8 eb 65 0e 18 97 41 04 e1 b2 3a 08 27 14 19 1d 11 d1 74 10 43 c3 23 a6 84 42 0c 4b a3 a2 0b 5c 69 14 38 c4 8e
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   140: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   141: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   141: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 07 e1 76 2b bc 37 41 81 ab 56 95 40 20 44 88 c2 43 14 ae 15 82 90 18 d1 45 17 21 62 08 6f ab 7d c7 41 14 2e ba 48 88 64 41 89 ab 40 14 2e d2 08 1a a2 f0 be d3 65 db 8d b8 4d 5c 4d 5c 5c 44 17 5d c6 1c a1 21 a4 0b 82 2c 86 7c e2 e2 22 ba e8 92 6c e2 92 e8 9a 0a 11 17 71 11 17 c1 82 da c4 65 23 04 21 5d 74 e1 68 d3 85 c5 45 c4 45 5c c4 05 41 1e 4b d2 70 55 ad 28 a3 84 06 23 09 81 c0 08 41 11 46 e2 f2 46 94 20 0a 17 44 b9 41 14 2e 1c 04 32 46 e2 82 20 97 41 14 0e 81 40 16 b2 16 a8 8d 7c 41 89 0b 04 32 46 e2 42 3d 9c b8 ec 26 2e e2 d2 b6 89 eb 84 11 b6 89 8b 45 20 90 c0 c4 05 51 38 cc 10 5d 20 90 29 1c 36 8c e4 82 28 dc 61 e2 62 11 9d 89 cb 22 2e 0c 13 97 13 d7 a6 70 18 e9 82 20 87 4d 5c 10 e4 28 98 b8 88 8b 2e 08 c2 c3 c4 65 21 42 30 d2 c5 45 d0 3a 96 28 1c 23 71
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 7, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   142: IFP d0 01 80 00 35 ff c0 60 10 8b a5 49 0c 8e 8c 22 e8 ba 50 8a 1e e4 75 65 d1 74 08 13 16 2c 31 10 82 10 87 06 47 45 d0 41 0a 15 65 d1 74 08 14 5a 65 d1 74 47 45 d1 74 5d 17 45 d1
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   142: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   143: IFP d0 01 80 00 35 74 5d 26 5d 02 42 44 23 08 c2 04 50 f2 3a 2e 98 31 23 a2 3a 2e 8b a6 a3 04 09 a0 45 0e 23 48 ba 23 a2 3a 08 21 04 82 29 d9 74 08 a1 e0 8a 1c 18 91 d1 1d 11 d1 74
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   143: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   144: IFP d0 01 80 00 35 47 41 05 15 6d f1 62 23 6d 88 88 8d c2 29 dc 44 47 11 71 11 1b 11 11 71 11 11 11 11 10 c8 e8 31 16 10 88 88 89 16 65 0e 22 22 29 88 c8 e9 88 88 88 c8 e8 62 22 c6
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   144: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   145: IFP d0 01 80 00 35 22 22 22 2a d2 4a b5 82 28 74 2d 91 d6 47 48 a1 d0 45 0f 5b a5 68 ba 51 08 a1 d0 c2 09 70 d3 61 bf 76 ec 5c 76 ef bc 5a 69 dc ba 84 53 a7 23 aa a5 54 12 fa 54 ad
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   145: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   146: IFP d0 01 80 00 2b 61 14 3a 7d 20 90 c7 23 ac 6d db 0f 86 1b b7 7b fb 74 47 54 47 41 b7 a8 aa 4b 5a 54 e1 14 3a a4 50 f2 3a d1 4e 12 c2 68 42 28 74 2c
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   146: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   147: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   147: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 08 d1 a5 92 30 71 31 44 17 5d 0a 51 78 27 ae a6 8b 2e 10 c8 68 34 8c 08 41 08 e1 60 e2 a2 0b 82 50 a8 a6 8b 2e 10 28 5a a6 8b 2e e2 a2 8b 2e ba e8 a2 8b 2e ba 64 ba 40 42 22 c4 10 43 20 0a 4f 5c 74 19 8c c4 45 5c 74 d1 65 c5 20 90 05 a2 70 c4 12 5d c4 45 5c 10 84 20 41 94 9b 2e 10 85 07 51 38 18 89 8b b8 88 8b 2e e2 82 a0 a8 b6 8f 46 c4 b6 11 11 b1 43 94 3b 22 e2 88 8e 88 d8 88 88 8e 88 88 88 88 08 13 17 8c 68 08 11 11 91 68 a6 70 44 44 94 11 13 97 11 11 11 13 17 46 44 63 44 44 44 54 4b 52 ad 41 14 2e b4 89 6b e2 12 85 0b a2 f0 da a5 16 5d 8a 10 85 0b 43 90 0e cb 86 fd 6e 37 3a 6e f7 3d 5a 96 3b 5d 21 ca e5 c4 55 a5 2a 48 5f 2a b5 86 28 5c be 04 09 e3 c4 35 b6 db f0 61 d8 ed de df 2e e2 2a e2 82 ed 15 55 d2 5a 2a 87 28 5c 25 0a 4f 5c 8b 72 48 43 16 42 14 2e 34
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 8, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   148: IFP d0 01 80 00 35 ff c0 60 90 2a 87 69 c3 76 ee 47 4c 3b 10 f4 2d e2 d3 d0 45 45 da ad 3e d5 04 53 ca 12 42 8a 1d 04 53 ae b5 5d 04 35 09 14 3a 41 72 3a bb 7b 16 85 45 b2 3a 17 0d
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   148: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   149: IFP d0 01 80 00 35 b4 47 4d 38 6b 72 3a 69 a1 da 23 aa 42 8a 1d 24 ea 8a 1e 12 4d 5a 48 5d 5a 2e 95 84 28 a1 d2 4c 2a 1b 8e e1 15 09 c5 b6 88 e8 36 0e 11 50 81 84 db 86 10 bc 21 0c
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   149: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   150: IFP d0 01 80 00 35 20 c2 30 83 09 85 69 f1 0e 47 54 18 4a 3b 42 1a 2e 83 08 c2 08 a7 0b 0c 2d 14 38 46 13 09 82 10 d3 08 c2 e4 74 11 4e ad a1 b7 6a c2 29 d0 45 3a 08 21 08 a7 40 81
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   150: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   151: IFP d0 01 80 00 35 08 86 b0 8a 74 5d 62 1a 10 d1 74 11 4e 88 e9 a2 3a 08 a8 08 74 23 45 d2 41 15 01 34 08 ab 08 c2 a6 10 86 10 86 10 88 68 51 43 84 61 24 34 2d 22 9c 10 45 3a 11 06
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   151: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   152: IFP d0 01 80 00 2b 10 82 2a c2 11 45 38 45 d4 1a 06 08 5c 4c c1 c9 08 22 9c 21 45 79 06 0e 08 41 84 61 04 55 82 08 ae 20 88 28 21 53 20 9e 52 b2 bc 83
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   152: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   153: IFP d0 01 20
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   153: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 09 54 e1 96 c3 6e 77 e2 32 dc 08 2f b4 47 cb 0b a2 a2 5b b5 7c ab 20 ca 53 48 42 51 b8 20 ca 75 ad ba 20 ac 90 28 5c 82 4e 5c dd de 68 a1 a2 4d 5c e8 b0 2d e2 b2 1c d6 4e 5c 96 85 5b c4 55 42 51 b8 24 57 51 78 48 b2 5a 12 ba 5a 74 a9 21 14 85 4b 32 54 d8 71 87 a8 90 a3 6d 11 17 6c 70 88 0a 81 21 db 61 08 3d 84 30 04 43 0c c1 90 a1 96 8f 70 e2 2a 18 52 dc 42 58 74 c1 10 43 10 e5 d0 30 b4 28 1c 62 c8 90 41 08 cb 10 43 27 2e 88 72 b5 85 ed 56 43 94 0b a2 5c 10 84 10 e5 02 81 10 61 0d 51 2e ba 46 58 08 8b 2e 88 72 11 97 45 5c 10 15 10 2e c4 a2 4b 82 a8 80 2c 10 d5 10 43 65 08 61 08 61 08 11 16 8a c2 21 86 24 2c b4 44 39 08 a2 5c 88 60 08 41 54 43 88 a2 1c a2 2b 58 60 10 3a 32 83 93 10 44 39 84 a2 9e 60 70 10 82 21 86 20 aa 41 10 75 04 11 14 84 ca 04 79 4a 4d 3d c1
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 9, length 256
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   154: IFP d0 01 80 00 35 ff c0 60 50 ac 90 7d 83 08 8d 05 38 82 29 c2 12 70 c0 9f 08 46 d2 2a 64 1f 65 a5 61 08 58 43 0b d6 22 47 41 48 d2 08 aa 8a 82 a4 90 a2 e5 39 52 17 2a a2 a0 a1 32
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   154: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   155: IFP d0 01 80 00 35 ab 28 50 a4 e5 59 40 a5 56 55 94 df 8a 72 93 95 05 6c a0 ad 0a 82 84 8a 72 aa 2a 0a d9 51 41 95 05 0d 14 e5 27 2a 0a 5d 02 d8 88 88 88 88 88 88 88 88 88 88 88 88
+[2015-12-02 11:56:06] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   155: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   156: IFP d0 01 80 00 35 88 88 88 88 88 8c ae 28 8b a0 94 20 9b 23 a2 3a 7b 18 82 28 7c 11 43 86 47 45 d3 71 88 65 d0 4a 84 7a dd 05 6a 14 8e ad 0f 84 53 a8 d1 75 0c 21 86 8b a8 68 60 8a
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   156: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   157: IFP d0 01 80 00 35 b0 8b a8 84 52 61 58 9f 46 14 47 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   157: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   158: IFP d0 01 80 00 2b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   158: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   159: IFP d0 01 20
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   159: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 0a 35 09 be c1 10 b1 a0 1c 41 94 43 48 0e 03 f9 10 62 4b 54 26 f8 a6 a5 86 10 1a c2 d0 6b 44 e2 82 12 4b 10 55 51 41 25 09 45 a7 9c 4a e8 54 45 05 85 4c d5 14 0a 25 a7 9a 02 a5 6a aa 29 fb 51 4e c9 a9 a0 36 05 b5 50 41 21 51 4e 55 54 50 9b 8a 82 a9 a0 b0 28 a7 e4 54 50 ba 40 1b 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 31 75 14 d1 05 29 04 d9 c4 45 5c de 18 41 14 3e 88 c2 61 e2 a2 cb 8e 11 a6 0b 52 21 5e bb a0 56 28 71 b5 f0 21 ca 15 8b ae 30 84 61 d1 15 16 06 51 0d d1 15 21 4a 86 1a f9 62 28 e2 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 10, length 256
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   160: IFP d0 01 80 00 35 ff c0 60 d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   160: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   161: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   161: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   162: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   162: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   163: IFP d0 01 80 00 35 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff fe 00 20 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   163: (0) data v17-14400/hdlc-data + 54 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   164: IFP d0 01 80 00 2b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   164: (0) data v17-14400/hdlc-data + 44 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   165: IFP d0 01 20
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   165: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type FCD - CRC OK (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  FCD without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 06 0b ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7f 00 04 c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Storing ECM frame 11, length 256
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   166: IFP d0 01 80 00 02 ff c0 61
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   166: (0) data v17-14400/hdlc-data + 3 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   167: IFP d0 01 20
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   167: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop none (0 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  RCP without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 86
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 12 to 13
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   168: IFP d0 01 80 00 02 ff c0 61
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   168: (0) data v17-14400/hdlc-data + 3 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   169: IFP d0 01 20
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   169: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  RCP without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 86
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   170: IFP d0 01 80 00 02 ff c0 61
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   170: (0) data v17-14400/hdlc-data + 3 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   171: IFP d0 01 20
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   171: (0) data v17-14400/hdlc-fcs-OK + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  RCP without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 86
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   172: IFP d0 01 80 00 02 ff c0 61
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   172: (0) data v17-14400/hdlc-data + 3 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   173: IFP d0 01 40
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   173: (0) data v17-14400/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type RCP - CRC OK, sig end (clean)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2 (55840 remaining)
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  RCP without final frame tag
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 03 86
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 13
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_C_ECM_RX to T30_PHASE_D_RX
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   174: IFP 00
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   174: indicator no-signal
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   175: IFP 06
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   175: indicator v21-preamble
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 13
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 13
+[2015-12-02 11:56:07] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T2A
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   176: IFP c0 01 80 00 00 ff
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   176: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   177: IFP c0 01 80 00 00 c8
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   177: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   178: IFP c0 01 80 00 00 fd
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   178: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   179: IFP c0 01 80 00 00 f4
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   179: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   180: IFP c0 01 80 00 00 00
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   180: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   181: IFP c0 01 80 00 00 00
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   181: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   182: IFP c0 01 80 00 00 d0
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   182: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   183: IFP c0 01 40
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   183: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type PPS - CRC OK, sig end (clean)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T2A (16960 remaining)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  PPS with final frame tag
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 13 bf 2f 00 00 0b
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 13
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Received PPS + EOP - page 0, block 0, 12 frames
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Partial page OK - committing block 0, 12 frames
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Page no = 1
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image size = 1728 x 2292 pixels
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Image resolution = 8031/m x 7700/m
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compression = T.6 (3)
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Compressed image size = 2998 bytes
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 13 to 14
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx:  MCF with final frame tag
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Tx:  ff 13 8c
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 14
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_D_TX
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 4
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:56:08] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx     9: indicator v21-preamble
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   184: IFP 00
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   184: indicator no-signal
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    10: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    10: IFP c0 01 80 00 00 ff
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    11: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    11: IFP c0 01 80 00 00 c8
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    12: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    12: IFP c0 01 80 00 00 31
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    13: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    13: IFP c0 01 40
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_D_TX, state 14
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_TX to T30_PHASE_D_RX
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 4
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 0
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4
+[2015-12-02 11:56:09] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Tx    14: indicator no-signal
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   185: IFP 06
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   185: indicator v21-preamble
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 A signal is present
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier up (-2) in state 14
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Framing OK (-6) in state 14
+[2015-12-02 11:56:10] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Start T4A
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   186: IFP c0 01 80 00 00 ff
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   186: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   187: IFP c0 01 80 00 00 c8
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   187: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   188: IFP c0 01 80 00 00 df
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   188: (0) data v21/hdlc-data + 1 byte(s)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   189: IFP c0 01 40
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38 Rx   189: (0) data v21/hdlc-fcs-OK-sig-end + 0 byte(s)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Type DCN - CRC OK, sig end (clean)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Stop T4A (15680 remaining)
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  DCN with final frame tag
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx:  ff 13 fb
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Rx final frame in state 14
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Disconnecting
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_D_RX to T30_PHASE_E
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 0
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 1
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 14 to 2
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 HDLC signal status is Carrier down (-1) in state 2
+[2015-12-02 11:56:11] FAX[13876][C-00000001] res_fax.c: FLOW T.30 No signal is present
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Send complete in phase T30_PHASE_E, state 2
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from state 2 to 32
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.30 Changing from phase T30_PHASE_E to T30_PHASE_CALL_FINISHED
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set rx type 9
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T Set tx type 9
+[2015-12-02 11:56:12] FAX[13876][C-00000001] res_fax.c: FLOW T.38T FAX exchange complete
diff --git a/contrib/scripts/spandspflow2pcap.py b/contrib/scripts/spandspflow2pcap.py
new file mode 100755 (executable)
index 0000000..a6546b6
--- /dev/null
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+# vim: set ts=8 sw=4 sts=4 et ai tw=79:
+'''
+Usage: ./spandspflow2pcap.py SPANDSP_LOG SENDFAX_PCAP
+
+Takes a log from Asterisk with SpanDSP, extracts the "received" data
+and puts it in a pcap file. Use 'fax set debug on' and configure
+logger.conf to get fax logs.
+
+Input data should look something like this::
+
+    [2013-08-07 15:17:34] FAX[23479] res_fax.c: FLOW T.38 Rx     5: IFP c0 01 ...
+
+Output data will look like a valid pcap file ;-)
+
+This allows you to reconstruct received faxes into replayable pcaps.
+
+Replaying is expected to be done by SIPp with sipp-sendfax.xml. The
+SIPp binary used for replaying must have image (fax) support. This means
+you'll need a version higher than 3.5.0 (unreleased when writing this),
+or the git master branch: https://github.com/SIPp/sipp
+
+
+Author: Walter Doekes, OSSO B.V. (2013,2015,2016)
+License: Public Domain
+'''
+from base64 import b16decode
+from datetime import datetime, timedelta
+from re import search
+from time import mktime
+from struct import pack
+import sys
+
+
+LOSSY = False
+EMPTY_RECOVERY = False
+
+
+def n2b(text):
+    return b16decode(text.replace(' ', '').replace('\n', '').upper())
+
+
+class FaxPcap(object):
+    PCAP_PREAMBLE = n2b('d4 c3 b2 a1 02 00 04 00'
+                        '00 00 00 00 00 00 00 00'
+                        'ff ff 00 00 71 00 00 00')
+
+    def __init__(self, outfile):
+        self.outfile = outfile
+        self.date = None
+        self.dateoff = timedelta(seconds=0)
+        self.seqno = None
+        self.udpseqno = 128
+        self.prev_data = None
+
+        # Only do this if at pos 0?
+        self.outfile.write(self.PCAP_PREAMBLE)
+
+    def data2packet(self, date, udpseqno, seqno, data, prev_data):
+        sum16 = '\x43\x21'  # checksum is irrelevant for sipp sending
+
+        new_prev = data  # without seqno..
+        data = '%s%s' % (pack('>H', seqno), data)
+        if prev_data:
+            if LOSSY and (seqno % 3) == 2:
+                return '', new_prev
+            if EMPTY_RECOVERY:
+                # struct ast_frame f[16], we have room for a few
+                # packets.
+                packets = 14
+                data += '\x00%c%s%s' % (
+                    chr(packets + 1), '\x00' * packets, prev_data)
+            else:
+                # Add 1 previous packet, without the seqno.
+                data += '\x00\x01' + prev_data
+
+        kwargs = {'udpseqno': pack('>H', udpseqno), 'sum16': sum16}
+
+        kwargs['data'] = data
+        kwargs['lenb16'] = pack('>H', len(kwargs['data']) + 8)
+        udp = '\x00\x01\x00\x02%(lenb16)s%(sum16)s%(data)s' % kwargs
+
+        kwargs['data'] = udp
+        kwargs['lenb16'] = pack('>H', len(kwargs['data']) + 20)
+        ip = ('\x45\xb8%(lenb16)s%(udpseqno)s\x00\x00\xf9\x11%(sum16)s\x01'
+              '\x01\x01\x01\x02\x02\x02\x02%(data)s') % kwargs
+
+        kwargs['data'] = ip
+        frame = ('\x00\x00\x00\x01\x00\x06\x00\x30\x48\xb1\x1c\x34\x00\x00'
+                 '\x08\x00%(data)s') % kwargs
+
+        kwargs['data'] = frame
+        sec = mktime(date.timetuple())
+        msec = date.microsecond
+        datalen = len(kwargs['data'])
+        kwargs['pre'] = pack('<IIII', sec, msec, datalen, datalen)
+        packet = '%(pre)s%(data)s' % kwargs
+
+        return (packet, new_prev)
+
+    def add(self, date, seqno, data):
+        if self.seqno is None:
+            self.seqno = 0
+            for i in range(seqno):
+                # In case the first zeroes were dropped, add them.
+                self.add(date, i, '\x00')
+        assert seqno == self.seqno, '%s != %s' % (seqno, self.seqno)
+
+        # Data is prepended by len(data).
+        data = chr(len(data)) + data
+
+        # Auto-increasing dates
+        if self.date is None or date > self.date:
+            # print 'date is larger', date, self.date
+            self.date = date
+        elif (date < self.date.replace(microsecond=0)):
+            assert False, ('We increased too fast.. decrease delta: %r/%r' %
+                           (date, self.date))
+        else:
+            self.date += timedelta(microseconds=9000)
+
+        print seqno, '\t', self.date + self.dateoff
+
+        # Make packet.
+        packet, prev_data = self.data2packet(self.date + self.dateoff,
+                                             self.udpseqno, self.seqno,
+                                             data, self.prev_data)
+        self.outfile.write(packet)
+
+        # Increase values.
+        self.udpseqno += 1
+        self.seqno += 1
+        self.prev_data = prev_data
+
+    def add_garbage(self, date):
+        if self.date is None or date > self.date:
+            self.date = date
+
+        packet, ignored = self.data2packet(self.date, self.udpseqno,
+                                           0xffff, 'GARBAGE', '')
+        self.udpseqno += 1
+
+        self.outfile.write(packet)
+
+
+with open(sys.argv[1], 'r') as infile:
+    with open(sys.argv[2], 'wb') as outfile:
+        first = True
+        p = FaxPcap(outfile)
+        # p.add(datetime.now(), 0, n2b('06'))
+        # p.add(datetime.now(), 1, n2b('c0 01 80 00 00 ff'))
+
+        for lineno, line in enumerate(infile):
+            # Look for lines like:
+            # [2013-08-07 15:17:34] FAX[23479] res_fax.c: \
+            #   FLOW T.38 Rx     5: IFP c0 01 80 00 00 ff
+            if 'FLOW T.38 Rx' not in line:
+                continue
+            if 'IFP' not in line:
+                continue
+
+            match = search(r'(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)', line)
+            assert match
+            date = datetime(*[int(i) for i in match.groups()])
+
+            match = search(r'Rx\s*(\d+):', line)
+            assert match
+            seqno = int(match.groups()[0])
+
+            match = search(r': IFP ([0-9a-f ]+)', line)
+            assert match
+            data = n2b(match.groups()[0])
+
+            # Have the file start a second early.
+            if first:
+                p.add_garbage(date)
+                first = False
+
+            # Add the packets.
+            #
+            # T.38 basic format of UDPTL payload section with redundancy:
+            #
+            # UDPTL_SEQNO
+            # - 2 sequence number (big endian)
+            # UDPTL_PRIMARY_PAYLOAD (T30?)
+            # - 1 subpacket length (excluding this byte)
+            # - 1 type of message (e.g. 0xd0 for data(?))
+            # - 1 items in data field (e.g. 0x01)
+            # - 2 length of data (big endian)
+            # - N data
+            # RECOVERY (optional)
+            # - 2 count of previous seqno packets (big endian)
+            # - N UDPTL_PRIMARY_PAYLOAD of (seqno-1)
+            # - N UDPTL_PRIMARY_PAYLOAD of (seqno-2)
+            # - ...
+            #
+            p.add(date, seqno, data)
index 2966f87..7963f31 100644 (file)
 
 int load_modules(unsigned int);                /*!< Provided by loader.c */
 int load_pbx(void);                    /*!< Provided by pbx.c */
+int load_pbx_builtins(void);   /*!< Provided by pbx_builtins.c */
+int load_pbx_functions_cli(void);      /*!< Provided by pbx_functions.c */
+int load_pbx_variables(void);  /*!< Provided by pbx_variables.c */
+int load_pbx_switch(void);             /*!< Provided by pbx_switch.c */
+int load_pbx_app(void);                /*!< Provided by pbx_app.c */
+int load_pbx_hangup_handler(void);     /*!< Provided by pbx_hangup_handler.c */
 int init_logger(void);                 /*!< Provided by logger.c */
 void close_logger(void);               /*!< Provided by logger.c */
 void logger_queue_start(void);         /*!< Provided by logger.c */
index 3975fda..d86b633 100644 (file)
@@ -580,6 +580,7 @@ int ast_vm_is_registered(void);
  *
  * \retval 0 on success.
  * \retval -1 on error.
+ * \retval AST_MODULE_LOAD_DECLINE if there's already another provider registered.
  */
 int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module *module);
 
@@ -648,6 +649,7 @@ int ast_vm_greeter_is_registered(void);
  *
  * \retval 0 on success.
  * \retval -1 on error.
+ * \retval AST_MODULE_LOAD_DECLINE if there's already another greeter registered.
  */
 int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module);
 
index 23492ff..cd49dbe 100644 (file)
@@ -266,12 +266,12 @@ AST_OPTIONAL_API(int, ast_websocket_read_string,
  * \param session Pointer to the WebSocket session
  * \param opcode WebSocket operation code to place in the frame
  * \param payload Optional pointer to a payload to add to the frame
- * \param actual_length Length of the payload (0 if no payload)
+ * \param payload_size Length of the payload (0 if no payload)
  *
  * \retval 0 if successfully written
  * \retval -1 if error occurred
  */
-AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;});
+AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size), { errno = ENOSYS; return -1;});
 
 /*!
  * \brief Construct and transmit a WebSocket frame containing string data.
index 9fbeb5e..d5616e9 100644 (file)
@@ -68,7 +68,7 @@ enum ast_module_unload_mode {
 enum ast_module_load_result {
        AST_MODULE_LOAD_SUCCESS = 0,    /*!< Module loaded and configured */
        AST_MODULE_LOAD_DECLINE = 1,    /*!< Module is not configured */
-       AST_MODULE_LOAD_SKIP = 2,       /*!< Module was skipped for some reason */
+       AST_MODULE_LOAD_SKIP = 2,       /*!< Module was skipped for some reason (For loader.c use only. Should never be returned by modules)*/
        AST_MODULE_LOAD_PRIORITY = 3,   /*!< Module is not loaded yet, but is added to prioity heap */
        AST_MODULE_LOAD_FAILURE = -1,   /*!< Module could not be loaded properly */
 };
index 2ea643e..e61d3e9 100644 (file)
@@ -109,6 +109,8 @@ struct stasis_cp_single;
 /*!
  * \brief Create the 'one' side of the cache pattern.
  *
+ * Create the 'one' and forward to all's topic and topic_cached.
+ *
  * Dispose of using stasis_cp_single_unsubscribe().
  *
  * \param all Corresponding all side.
@@ -119,6 +121,23 @@ struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
        const char *name);
 
 /*!
+ * \brief Create a sink in the cache pattern
+ *
+ * Create the 'one' but do not automatically forward to the all's topic.
+ * This is useful when aggregating other topic's messages created with
+ * \c stasis_cp_single_create in another caching topic without replicating
+ * those messages in the all's topics.
+ *
+ * Dispose of using stasis_cp_single_unsubscribe().
+ *
+ * \param all Corresponding all side.
+ * \param name Base name for the topics.
+ * \return One side instance
+ */
+struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all,
+       const char *name);
+
+/*!
  * \brief Stops caching and forwarding messages.
  *
  * \param one One side of the cache pattern.
index 5294906..f49d689 100644 (file)
 
 /* We have to let the compiler learn what types to use for the elements of a
    struct timeval since on linux, it's time_t and suseconds_t, but on *BSD,
-   they are just a long. */
-extern struct timeval tv;
-typedef typeof(tv.tv_sec) ast_time_t;
-typedef typeof(tv.tv_usec) ast_suseconds_t;
+   they are just a long.
+   note:dummy_tv_var_for_types never actually gets exported, only used as
+   local place holder. */
+extern struct timeval dummy_tv_var_for_types;
+typedef typeof(dummy_tv_var_for_types.tv_sec) ast_time_t;
+typedef typeof(dummy_tv_var_for_types.tv_usec) ast_suseconds_t;
 
 /*!
  * \brief Computes the difference (in seconds) between two \c struct \c timeval instances.
index ba44fbf..54edafa 100644 (file)
@@ -1667,11 +1667,11 @@ static struct ast_json *charge_to_json(const struct ast_aoc_decoded *decoded)
        }
 
        return ast_json_pack(
-               "{s:s, s:s, s:s, s:O}",
+               "{s:s, s:s, s:s, s:o}",
                "Type", aoc_charge_type_str(decoded->charge_type),
                "BillingID", aoc_billingid_str(decoded->billing_id),
                "TotalType", aoc_type_of_totaling_str(decoded->total_type),
-               obj_type, obj);
+               obj_type, ast_json_ref(obj));
 }
 
 static struct ast_json *association_to_json(const struct ast_aoc_decoded *decoded)
@@ -1738,10 +1738,10 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
                                        "Scale", decoded->aoc_s_entries[i].rate.duration.granularity_time_scale);
                        }
 
-                       type = ast_json_pack("{s:O, s:s, s:O, s:O}", "Currency", currency, "ChargingType",
+                       type = ast_json_pack("{s:o, s:s, s:o, s:o}", "Currency", ast_json_ref(currency), "ChargingType",
                                             decoded->aoc_s_entries[i].rate.duration.charging_type ?
-                                            "StepFunction" : "ContinuousCharging", "Time", time,
-                                            "Granularity", granularity ? granularity : ast_json_null());
+                                            "StepFunction" : "ContinuousCharging", "Time", ast_json_ref(time),
+                                            "Granularity", granularity ? ast_json_ref(granularity) : ast_json_ref(ast_json_null()));
 
                        break;
                }
@@ -1751,7 +1751,7 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
                                decoded->aoc_s_entries[i].rate.flat.amount,
                                decoded->aoc_s_entries[i].rate.flat.multiplier);
 
-                       type = ast_json_pack("{s:O}", "Currency", currency);
+                       type = ast_json_pack("{s:o}", "Currency", ast_json_ref(currency));
                        break;
                case AST_AOC_RATE_TYPE_VOLUME:
                        currency = currency_to_json(
@@ -1760,9 +1760,9 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
                                decoded->aoc_s_entries[i].rate.volume.multiplier);
 
                        type = ast_json_pack(
-                               "{s:s, s:O}", "Unit", aoc_volume_unit_str(
+                               "{s:s, s:o}", "Unit", aoc_volume_unit_str(
                                        decoded->aoc_s_entries[i].rate.volume.volume_unit),
-                               "Currency", currency);
+                               "Currency", ast_json_ref(currency));
                        break;
                case AST_AOC_RATE_TYPE_SPECIAL_CODE:
                        type = ast_json_pack("{s:i}", "SpecialCode",
@@ -1772,8 +1772,8 @@ static struct ast_json *s_to_json(const struct ast_aoc_decoded *decoded)
                        break;
                }
 
-               rate = ast_json_pack("{s:s, s:O}", "Chargeable", charge_item,
-                                    aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), type);
+               rate = ast_json_pack("{s:s, s:o}", "Chargeable", charge_item,
+                                    aoc_rate_type_str(decoded->aoc_s_entries[i].rate_type), ast_json_ref(type));
                if (ast_json_array_append(rates, rate)) {
                        break;
                }
index dabf15d..36330ac 100644 (file)
@@ -494,7 +494,7 @@ int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module
        if (table) {
                ast_log(LOG_WARNING, "Voicemail provider already registered by %s.\n",
                        table->module_name);
-               return -1;
+               return AST_MODULE_LOAD_DECLINE;
        }
 
        table = ao2_alloc_options(sizeof(*table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
@@ -605,7 +605,7 @@ int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, s
        if (table) {
                ast_log(LOG_WARNING, "Voicemail greeter provider already registered by %s.\n",
                        table->module_name);
-               return -1;
+               return AST_MODULE_LOAD_DECLINE;
        }
 
        table = ao2_alloc_options(sizeof(*table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
index 93937af..a7842a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2015, Digium, Inc.
+ * Copyright (C) 1999 - 2016, Digium, Inc.
  *
  * Mark Spencer <markster@digium.com>
  *
@@ -53,7 +53,7 @@
  *
  * \section copyright Copyright and Author
  *
- * Copyright (C) 1999 - 2015, Digium, Inc.
+ * Copyright (C) 1999 - 2016, Digium, Inc.
  * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
  * of <a rel="nofollow" href="http://www.digium.com">Digium, Inc</a>.
  *
@@ -302,7 +302,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 
 /*! \brief Welcome message when starting a CLI interface */
 #define WELCOME_MESSAGE \
-    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2015, Digium, Inc. and others.\n" \
+    ast_verbose("Asterisk %s, Copyright (C) 1999 - 2016, Digium, Inc. and others.\n" \
                 "Created by Mark Spencer <markster@digium.com>\n" \
                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
                 "This is free software, with components licensed under the GNU General Public\n" \
@@ -3365,7 +3365,7 @@ static int show_version(void)
 
 static int show_cli_help(void)
 {
-       printf("Asterisk %s, Copyright (C) 1999 - 2015, Digium, Inc. and others.\n", ast_get_version());
+       printf("Asterisk %s, Copyright (C) 1999 - 2016, Digium, Inc. and others.\n", ast_get_version());
        printf("Usage: asterisk [OPTIONS]\n");
        printf("Valid Options:\n");
        printf("   -V              Display version number and exit\n");
@@ -4595,6 +4595,36 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
                exit(1);
        }
 
+       if (load_pbx_builtins()) {
+               printf("Failed: load_pbx_builtins\n%s", term_quit());
+               exit(1);
+       }
+
+       if (load_pbx_functions_cli()) {
+               printf("Failed: load_pbx_functions_cli\n%s", term_quit());
+               exit(1);
+       }
+
+       if (load_pbx_variables()) {
+               printf("Failed: load_pbx_variables\n%s", term_quit());
+               exit(1);
+       }
+
+       if (load_pbx_switch()) {
+               printf("Failed: load_pbx_switch\n%s", term_quit());
+               exit(1);
+       }
+
+       if (load_pbx_app()) {
+               printf("Failed: load_pbx_app\n%s", term_quit());
+               exit(1);
+       }
+
+       if (load_pbx_hangup_handler()) {
+               printf("Failed: load_pbx_hangup_handler\n%s", term_quit());
+               exit(1);
+       }
+
        if (ast_local_init()) {
                printf("Failed: ast_local_init\n%s", term_quit());
                exit(1);
index 5e20f30..cd19915 100644 (file)
@@ -3383,35 +3383,46 @@ static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_c
 /*! \brief Internal built in feature for blind transfers */
 static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
-       char exten[AST_MAX_EXTENSION] = "";
+       char xfer_exten[AST_MAX_EXTENSION] = "";
        struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
-       const char *context;
+       const char *xfer_context;
        char *goto_on_blindxfr;
 
        ast_bridge_channel_write_hold(bridge_channel, NULL);
 
        ast_channel_lock(bridge_channel->chan);
-       context = ast_strdupa(get_transfer_context(bridge_channel->chan,
+       xfer_context = ast_strdupa(get_transfer_context(bridge_channel->chan,
                blind_transfer ? blind_transfer->context : NULL));
        goto_on_blindxfr = ast_strdupa(S_OR(pbx_builtin_getvar_helper(bridge_channel->chan,
                "GOTO_ON_BLINDXFR"), ""));
        ast_channel_unlock(bridge_channel->chan);
 
        /* Grab the extension to transfer to */
-       if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+       if (grab_transfer(bridge_channel->chan, xfer_exten, sizeof(xfer_exten), xfer_context)) {
                ast_bridge_channel_write_unhold(bridge_channel);
                return 0;
        }
 
        if (!ast_strlen_zero(goto_on_blindxfr)) {
+               const char *chan_context;
+               const char *chan_exten;
+               int chan_priority;
+
                ast_debug(1, "After transfer, transferer %s goes to %s\n",
                                ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
-               ast_bridge_set_after_go_on(bridge_channel->chan, NULL, NULL, 0, goto_on_blindxfr);
+
+               ast_channel_lock(bridge_channel->chan);
+               chan_context = ast_strdupa(ast_channel_context(bridge_channel->chan));
+               chan_exten = ast_strdupa(ast_channel_exten(bridge_channel->chan));
+               chan_priority = ast_channel_priority(bridge_channel->chan);
+               ast_channel_unlock(bridge_channel->chan);
+               ast_bridge_set_after_go_on(bridge_channel->chan,
+                       chan_context, chan_exten, chan_priority, goto_on_blindxfr);
        }
 
-       if (ast_bridge_transfer_blind(0, bridge_channel->chan, exten, context, blind_transfer_cb,
-                       bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS &&
-                       !ast_strlen_zero(goto_on_blindxfr)) {
+       if (ast_bridge_transfer_blind(0, bridge_channel->chan, xfer_exten, xfer_context,
+               blind_transfer_cb, bridge_channel->chan) != AST_BRIDGE_TRANSFER_SUCCESS
+               && !ast_strlen_zero(goto_on_blindxfr)) {
                ast_bridge_discard_after_goto(bridge_channel->chan);
        }
 
index 5e24075..b6a0b42 100644 (file)
@@ -1359,10 +1359,10 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
 
        ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
 
-       /* Ignore any snapshots from a dead or dying channel */
+       /* Finalize the CDR if we're in hangup logic and we're set to do so */
        if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
-                       && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
-               cdr_object_check_party_a_hangup(cdr);
+               && ast_test_flag(&mod_cfg->general->settings, CDR_END_BEFORE_H_EXTEN)) {
+               cdr_object_finalize(cdr);
                return 0;
        }
 
@@ -2976,7 +2976,7 @@ int ast_cdr_setvar(const char *channel_name, const char *name, const char *value
                for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                        struct varshead *headp = NULL;
 
-                       if (it_cdr->fn_table == &finalized_state_fn_table) {
+                       if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
                                continue;
                        }
                        if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
index aba6159..400d655 100644 (file)
@@ -214,6 +214,7 @@ static pthread_t change_thread = AST_PTHREADT_NULL;
 
 /*! \brief Flag for the queue */
 static ast_cond_t change_pending;
+static volatile int shuttingdown;
 
 struct stasis_subscription *devstate_message_sub;
 
@@ -548,7 +549,7 @@ static void *do_devstate_changes(void *data)
 {
        struct state_change *next, *current;
 
-       for (;;) {
+       while (!shuttingdown) {
                /* This basically pops off any state change entries, resets the list back to NULL, unlocks, and processes each state change */
                AST_LIST_LOCK(&state_changes);
                if (AST_LIST_EMPTY(&state_changes))
@@ -626,6 +627,18 @@ static void devstate_change_cb(void *data, struct stasis_subscription *sub, stru
                device_state->cachable, NULL);
 }
 
+static void device_state_engine_cleanup(void)
+{
+       shuttingdown = 1;
+       AST_LIST_LOCK(&state_changes);
+       ast_cond_signal(&change_pending);
+       AST_LIST_UNLOCK(&state_changes);
+
+       if (change_thread != AST_PTHREADT_NULL) {
+               pthread_join(change_thread, NULL);
+       }
+}
+
 /*! \brief Initialize the device state engine in separate thread */
 int ast_device_state_engine_init(void)
 {
@@ -634,6 +647,7 @@ int ast_device_state_engine_init(void)
                ast_log(LOG_ERROR, "Unable to start device state change thread.\n");
                return -1;
        }
+       ast_register_cleanup(device_state_engine_cleanup);
 
        return 0;
 }
index 2132656..b73edd3 100644 (file)
@@ -303,13 +303,14 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
                return NULL;
        }
 
-       endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(),
-               endpoint->id);
-       if (!endpoint->topics) {
-               return NULL;
-       }
-
        if (!ast_strlen_zero(resource)) {
+
+               endpoint->topics = stasis_cp_single_create(ast_endpoint_cache_all(),
+                       endpoint->id);
+               if (!endpoint->topics) {
+                       return NULL;
+               }
+
                endpoint->router = stasis_message_router_create_pool(ast_endpoint_topic(endpoint));
                if (!endpoint->router) {
                        return NULL;
@@ -325,9 +326,16 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
 
                endpoint->tech_forward = stasis_forward_all(stasis_cp_single_topic(endpoint->topics),
                        stasis_cp_single_topic(tech_endpoint->topics));
+
                endpoint_publish_snapshot(endpoint);
                ao2_link(endpoints, endpoint);
        } else {
+               endpoint->topics = stasis_cp_sink_create(ast_endpoint_cache_all(),
+                       endpoint->id);
+               if (!endpoint->topics) {
+                       return NULL;
+               }
+
                ao2_link(tech_endpoints, endpoint);
        }
 
index 9e16aa3..d3e87fa 100644 (file)
@@ -218,6 +218,7 @@ int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_typ
 
        for (id = 1; id < ast_codec_get_max(); ++id) {
                struct ast_codec *codec = ast_codec_get_by_id(id);
+               struct ast_codec *codec2 = NULL;
                struct ast_format *format;
                int res;
 
@@ -238,10 +239,14 @@ int ast_format_cap_append_by_type(struct ast_format_cap *cap, enum ast_media_typ
                        continue;
                }
 
-               if (!format || (codec != ast_format_get_codec(format))) {
+               if (format) {
+                       codec2 = ast_format_get_codec(format);
+               }
+               if (codec != codec2) {
                        ao2_cleanup(format);
                        format = ast_format_create(codec);
                }
+               ao2_cleanup(codec2);
                ao2_ref(codec, -1);
 
                if (!format) {
index b2bdd4a..954b288 100644 (file)
@@ -846,10 +846,10 @@ static void publish_reload_message(const char *name, enum ast_module_reload_resu
        event_object = ast_json_pack("{s: s, s: s}",
                        "Module", S_OR(name, "All"),
                        "Status", res_buffer);
-       json_object = ast_json_pack("{s: s, s: i, s: O}",
+       json_object = ast_json_pack("{s: s, s: i, s: o}",
                        "type", "Reload",
                        "class_type", EVENT_FLAG_SYSTEM,
-                       "event", event_object);
+                       "event", ast_json_ref(event_object));
 
        if (!json_object) {
                return;
index 544f4fd..6c692d5 100644 (file)
@@ -8538,6 +8538,8 @@ static void manager_shutdown(void)
                manager_free_user(user);
        }
        acl_change_stasis_unsubscribe();
+
+       ast_free(manager_channelvars);
 }
 
 
index 202940e..c5de3fb 100644 (file)
@@ -73,6 +73,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
 #include "asterisk/vector.h"
+#include "pbx_private.h"
 
 /*!
  * \note I M P O R T A N T :
@@ -96,637 +97,6 @@ ASTERISK_REGISTER_FILE()
  */
 
 /*** DOCUMENTATION
-       <application name="Answer" language="en_US">
-               <synopsis>
-                       Answer a channel if ringing.
-               </synopsis>
-               <syntax>
-                       <parameter name="delay">
-                               <para>Asterisk will wait this number of milliseconds before returning to
-                               the dialplan after answering the call.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>If the call has not been answered, this application will
-                       answer it. Otherwise, it has no effect on the call.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="BackGround" language="en_US">
-               <synopsis>
-                       Play an audio file while waiting for digits of an extension to go to.
-               </synopsis>
-               <syntax>
-                       <parameter name="filenames" required="true" argsep="&amp;">
-                               <argument name="filename1" required="true" />
-                               <argument name="filename2" multiple="true" />
-                       </parameter>
-                       <parameter name="options">
-                               <optionlist>
-                                       <option name="s">
-                                               <para>Causes the playback of the message to be skipped
-                                               if the channel is not in the <literal>up</literal> state (i.e. it
-                                               hasn't been answered yet). If this happens, the
-                                               application will return immediately.</para>
-                                       </option>
-                                       <option name="n">
-                                               <para>Don't answer the channel before playing the files.</para>
-                                       </option>
-                                       <option name="m">
-                                               <para>Only break if a digit hit matches a one digit
-                                               extension in the destination context.</para>
-                                       </option>
-                               </optionlist>
-                       </parameter>
-                       <parameter name="langoverride">
-                               <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
-                       </parameter>
-                       <parameter name="context">
-                               <para>This is the dialplan context that this application will use when exiting
-                               to a dialed extension.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
-                       while waiting for an extension to be dialed by the calling channel. To continue waiting
-                       for digits after this application has finished playing files, the <literal>WaitExten</literal>
-                       application should be used.</para>
-                       <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
-                       <para>This application sets the following channel variable upon completion:</para>
-                       <variablelist>
-                               <variable name="BACKGROUNDSTATUS">
-                                       <para>The status of the background attempt as a text string.</para>
-                                       <value name="SUCCESS" />
-                                       <value name="FAILED" />
-                               </variable>
-                       </variablelist>
-               </description>
-               <see-also>
-                       <ref type="application">ControlPlayback</ref>
-                       <ref type="application">WaitExten</ref>
-                       <ref type="application">BackgroundDetect</ref>
-                       <ref type="function">TIMEOUT</ref>
-               </see-also>
-       </application>
-       <application name="Busy" language="en_US">
-               <synopsis>
-                       Indicate the Busy condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="timeout">
-                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
-                               Otherwise, this application will wait until the calling channel hangs up.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will indicate the busy condition to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="Congestion" language="en_US">
-               <synopsis>
-                       Indicate the Congestion condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="timeout">
-                               <para>If specified, the calling channel will be hung up after the specified number of seconds.
-                               Otherwise, this application will wait until the calling channel hangs up.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will indicate the congestion condition to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-                       <ref type="application">Hangup</ref>
-               </see-also>
-       </application>
-       <application name="ExecIfTime" language="en_US">
-               <synopsis>
-                       Conditional application execution based on the current time.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="day_condition" required="true">
-                               <argument name="times" required="true" />
-                               <argument name="weekdays" required="true" />
-                               <argument name="mdays" required="true" />
-                               <argument name="months" required="true" />
-                               <argument name="timezone" required="false" />
-                       </parameter>
-                       <parameter name="appname" required="true" hasparams="optional">
-                               <argument name="appargs" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will execute the specified dialplan application, with optional
-                       arguments, if the current time matches the given time specification.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Exec</ref>
-                       <ref type="application">ExecIf</ref>
-                       <ref type="application">TryExec</ref>
-                       <ref type="application">GotoIfTime</ref>
-               </see-also>
-       </application>
-       <application name="Goto" language="en_US">
-               <synopsis>
-                       Jump to a particular priority, extension, or context.
-               </synopsis>
-               <syntax>
-                       <parameter name="context" />
-                       <parameter name="extensions" />
-                       <parameter name="priority" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will set the current context, extension, and priority in the channel structure.
-                       After it completes, the pbx engine will continue dialplan execution at the specified location.
-                       If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
-                       <replaceable>context</replaceable>, are specified, then this application will
-                       just set the specified <replaceable>priority</replaceable> of the current extension.</para>
-                       <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
-                       return a <literal>-1</literal>, and the channel and call will be terminated.</para>
-                       <para>If the location that is put into the channel information is bogus, and asterisk cannot
-                       find that location in the dialplan, then the execution engine will try to find and execute the code in
-                       the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
-                       <literal>h</literal> extension. If neither the <literal>h</literal> nor <literal>i</literal> extensions
-                       have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
-                       What this means is that, for example, you specify a context that does not exist, then
-                       it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
-                       and the call will terminate!</para>
-               </description>
-               <see-also>
-                       <ref type="application">GotoIf</ref>
-                       <ref type="application">GotoIfTime</ref>
-                       <ref type="application">Gosub</ref>
-                       <ref type="application">Macro</ref>
-               </see-also>
-       </application>
-       <application name="GotoIf" language="en_US">
-               <synopsis>
-                       Conditional goto.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="condition" required="true" />
-                       <parameter name="destination" required="true" argsep=":">
-                               <argument name="labeliftrue">
-                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                               <argument name="labeliffalse">
-                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will set the current context, extension, and priority in the channel structure
-                       based on the evaluation of the given condition. After this application completes, the
-                       pbx engine will continue dialplan execution at the specified location in the dialplan.
-                       The labels are specified with the same syntax as used within the Goto application.
-                       If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
-                       next instruction. If the target location is bogus, and does not exist, the execution engine will try
-                       to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
-                       If that does not exist, it will try to execute the <literal>h</literal> extension.
-                       If neither the <literal>h</literal> nor <literal>i</literal> extensions have been defined,
-                       the channel is hung up, and the execution of instructions on the channel is terminated.
-                       Remember that this command can set the current context, and if the context specified
-                       does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
-                       the channel and call will both be terminated!.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Goto</ref>
-                       <ref type="application">GotoIfTime</ref>
-                       <ref type="application">GosubIf</ref>
-                       <ref type="application">MacroIf</ref>
-               </see-also>
-       </application>
-       <application name="GotoIfTime" language="en_US">
-               <synopsis>
-                       Conditional Goto based on the current time.
-               </synopsis>
-               <syntax argsep="?">
-                       <parameter name="condition" required="true">
-                               <argument name="times" required="true" />
-                               <argument name="weekdays" required="true" />
-                               <argument name="mdays" required="true" />
-                               <argument name="months" required="true" />
-                               <argument name="timezone" required="false" />
-                       </parameter>
-                       <parameter name="destination" required="true" argsep=":">
-                               <argument name="labeliftrue">
-                                       <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                               <argument name="labeliffalse">
-                                       <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.
-                                       Takes the form similar to Goto() of [[context,]extension,]priority.</para>
-                               </argument>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will set the context, extension, and priority in the channel structure
-                       based on the evaluation of the given time specification. After this application completes,
-                       the pbx engine will continue dialplan execution at the specified location in the dialplan.
-                       If the current time is within the given time specification, the channel will continue at
-                       <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
-                       If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
-                       instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
-                       Further information on the time specification can be found in examples
-                       illustrating how to do time-based context includes in the dialplan.</para>
-               </description>
-               <see-also>
-                       <ref type="application">GotoIf</ref>
-                       <ref type="application">Goto</ref>
-                       <ref type="function">IFTIME</ref>
-                       <ref type="function">TESTTIME</ref>
-               </see-also>
-       </application>
-       <application name="ImportVar" language="en_US">
-               <synopsis>
-                       Import a variable from a channel into a new variable.
-               </synopsis>
-               <syntax argsep="=">
-                       <parameter name="newvar" required="true" />
-                       <parameter name="vardata" required="true">
-                               <argument name="channelname" required="true" />
-                               <argument name="variable" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application imports a <replaceable>variable</replaceable> from the specified
-                       <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
-                       (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
-                       application). Variables created by this application have the same inheritance properties as those
-                       created with the <literal>Set</literal> application.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Set</ref>
-               </see-also>
-       </application>
-       <application name="Hangup" language="en_US">
-               <synopsis>
-                       Hang up the calling channel.
-               </synopsis>
-               <syntax>
-                       <parameter name="causecode">
-                               <para>If a <replaceable>causecode</replaceable> is given the channel's
-                               hangup cause will be set to the given value.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application will hang up the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Answer</ref>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-               </see-also>
-       </application>
-       <application name="Incomplete" language="en_US">
-               <synopsis>
-                       Returns AST_PBX_INCOMPLETE value.
-               </synopsis>
-               <syntax>
-                       <parameter name="n">
-                               <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
-                               <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>Signals the PBX routines that the previous matched extension is incomplete
-                       and that further input should be allowed before matching can be considered
-                       to be complete.  Can be used within a pattern match when certain criteria warrants
-                       a longer match.</para>
-               </description>
-       </application>
-       <application name="NoOp" language="en_US">
-               <synopsis>
-                       Do Nothing (No Operation).
-               </synopsis>
-               <syntax>
-                       <parameter name="text">
-                               <para>Any text provided can be viewed at the Asterisk CLI.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application does nothing. However, it is useful for debugging purposes.</para>
-                       <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Verbose</ref>
-                       <ref type="application">Log</ref>
-               </see-also>
-       </application>
-       <application name="Proceeding" language="en_US">
-               <synopsis>
-                       Indicate proceeding.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that a proceeding message be provided to the calling channel.</para>
-               </description>
-       </application>
-       <application name="Progress" language="en_US">
-               <synopsis>
-                       Indicate progress.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that in-band progress information be provided to the calling channel.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Ringing</ref>
-                       <ref type="application">Playtones</ref>
-               </see-also>
-       </application>
-       <application name="RaiseException" language="en_US">
-               <synopsis>
-                       Handle an exceptional condition.
-               </synopsis>
-               <syntax>
-                       <parameter name="reason" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
-                       dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
-               </description>
-               <see-also>
-                       <ref type="function">Exception</ref>
-               </see-also>
-       </application>
-       <application name="Ringing" language="en_US">
-               <synopsis>
-                       Indicate ringing tone.
-               </synopsis>
-               <syntax />
-               <description>
-                       <para>This application will request that the channel indicate a ringing tone to the user.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Busy</ref>
-                       <ref type="application">Congestion</ref>
-                       <ref type="application">Progress</ref>
-                       <ref type="application">Playtones</ref>
-               </see-also>
-       </application>
-       <application name="SayAlpha" language="en_US">
-               <synopsis>
-                       Say Alpha.
-               </synopsis>
-               <syntax>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the letters
-                       of the given <replaceable>string</replaceable>. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive),
-                       then this application will react to DTMF in the same way as
-                       <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayAlphaCase" language="en_US">
-               <synopsis>
-                       Say Alpha.
-               </synopsis>
-               <syntax>
-                       <parameter name="casetype" required="true" >
-                               <enumlist>
-                                       <enum name="a">
-                                               <para>Case sensitive (all) pronunciation.
-                                               (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
-                                       </enum>
-                                       <enum name="l">
-                                               <para>Case sensitive (lower) pronunciation.
-                                               (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
-                                       </enum>
-                                       <enum name="n">
-                                               <para>Case insensitive pronunciation. Equivalent to SayAlpha.
-                                               (Ex: SayAlphaCase(n,aBc) - a b c).</para>
-                                       </enum>
-                                       <enum name="u">
-                                               <para>Case sensitive (upper) pronunciation.
-                                               (Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
-                                       </enum>
-                               </enumlist>
-                       </parameter>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the letters of the
-                       given <replaceable>string</replaceable>.  Optionally, a <replaceable>casetype</replaceable> may be
-                       specified.  This will be used for case-insensitive or case-sensitive pronunciations. If the channel
-                       variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayDigits" language="en_US">
-               <synopsis>
-                       Say Digits.
-               </synopsis>
-               <syntax>
-                       <parameter name="digits" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the digits of
-                       the given number. This will use the language that is currently set for the channel.
-                       If the channel variable <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true'
-                       (case insensitive), then this application will react to DTMF in the same way as
-                       <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayNumber</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayNumber" language="en_US">
-               <synopsis>
-                       Say Number.
-               </synopsis>
-               <syntax>
-                       <parameter name="digits" required="true" />
-                       <parameter name="gender" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds that correspond to the given
-                       <replaceable>digits</replaceable>. Optionally, a <replaceable>gender</replaceable> may be
-                       specified. This will use the language that is currently set for the channel. See the CHANNEL()
-                       function for more information on setting the language for the channel. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayPhonetic</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="SayPhonetic" language="en_US">
-               <synopsis>
-                       Say Phonetic.
-               </synopsis>
-               <syntax>
-                       <parameter name="string" required="true" />
-               </syntax>
-               <description>
-                       <para>This application will play the sounds from the phonetic alphabet that correspond to the
-                       letters in the given <replaceable>string</replaceable>. If the channel variable
-                       <variable>SAY_DTMF_INTERRUPT</variable> is set to 'true' (case insensitive), then this
-                       application will react to DTMF in the same way as <literal>Background</literal>.</para>
-               </description>
-               <see-also>
-                       <ref type="application">SayAlpha</ref>
-                       <ref type="application">SayDigits</ref>
-                       <ref type="application">SayNumber</ref>
-               </see-also>
-       </application>
-       <application name="Set" language="en_US">
-               <synopsis>
-                       Set channel variable or function value.
-               </synopsis>
-               <syntax argsep="=">
-                       <parameter name="name" required="true" />
-                       <parameter name="value" required="true" />
-               </syntax>
-               <description>
-                       <para>This function can be used to set the value of channel variables or dialplan functions.
-                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
-                       the variable will be inherited into channels created from the current channel.
-                       If the variable name is prefixed with <literal>__</literal>, the variable will be
-                       inherited into channels created from the current channel and all children channels.</para>
-                       <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
-                       a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
-                       the behavior of this app changes, and strips surrounding quotes from the right hand side as
-                       it did previously in 1.4.
-                       The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
-                       were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
-                       protect separators and quotes in various database access strings has been greatly
-                       reduced by these changes.</para></note>
-               </description>
-               <see-also>
-                       <ref type="application">MSet</ref>
-                       <ref type="function">GLOBAL</ref>
-                       <ref type="function">SET</ref>
-                       <ref type="function">ENV</ref>
-               </see-also>
-       </application>
-       <application name="MSet" language="en_US">
-               <synopsis>
-                       Set channel variable(s) or function value(s).
-               </synopsis>
-               <syntax>
-                       <parameter name="set1" required="true" argsep="=">
-                               <argument name="name1" required="true" />
-                               <argument name="value1" required="true" />
-                       </parameter>
-                       <parameter name="set2" multiple="true" argsep="=">
-                               <argument name="name2" required="true" />
-                               <argument name="value2" required="true" />
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This function can be used to set the value of channel variables or dialplan functions.
-                       When setting variables, if the variable name is prefixed with <literal>_</literal>,
-                       the variable will be inherited into channels created from the current channel
-                       If the variable name is prefixed with <literal>__</literal>, the variable will be
-                       inherited into channels created from the current channel and all children channels.
-                       MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
-                       prone to doing things that you may not expect. For example, it strips surrounding
-                       double-quotes from the right-hand side (value). If you need to put a separator
-                       character (comma or vert-bar), you will need to escape them by inserting a backslash
-                       before them. Avoid its use if possible.</para>
-               </description>
-               <see-also>
-                       <ref type="application">Set</ref>
-               </see-also>
-       </application>
-       <application name="SetAMAFlags" language="en_US">
-               <synopsis>
-                       Set the AMA Flags.
-               </synopsis>
-               <syntax>
-                       <parameter name="flag" />
-               </syntax>
-               <description>
-                       <para>This application will set the channel's AMA Flags for billing purposes.</para>
-                       <warning><para>This application is deprecated. Please use the CHANNEL function instead.</para></warning>
-               </description>
-               <see-also>
-                       <ref type="function">CDR</ref>
-                       <ref type="function">CHANNEL</ref>
-               </see-also>
-       </application>
-       <application name="Wait" language="en_US">
-               <synopsis>
-                       Waits for some time.
-               </synopsis>
-               <syntax>
-                       <parameter name="seconds" required="true">
-                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-                               application to wait for 1.5 seconds.</para>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
-               </description>
-       </application>
-       <application name="WaitExten" language="en_US">
-               <synopsis>
-                       Waits for an extension to be entered.
-               </synopsis>
-               <syntax>
-                       <parameter name="seconds">
-                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
-                               application to wait for 1.5 seconds.</para>
-                       </parameter>
-                       <parameter name="options">
-                               <optionlist>
-                                       <option name="m">
-                                               <para>Provide music on hold to the caller while waiting for an extension.</para>
-                                               <argument name="x">
-                                                       <para>Specify the class for music on hold. <emphasis>CHANNEL(musicclass) will
-                                                       be used instead if set</emphasis></para>
-                                               </argument>
-                                       </option>
-                               </optionlist>
-                       </parameter>
-               </syntax>
-               <description>
-                       <para>This application waits for the user to enter a new extension for a specified number
-                       of <replaceable>seconds</replaceable>.</para>
-                       <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
-               </description>
-               <see-also>
-                       <ref type="application">Background</ref>
-                       <ref type="function">TIMEOUT</ref>
-               </see-also>
-       </application>
        <function name="EXCEPTION" language="en_US">
                <synopsis>
                        Retrieve the details of the current dialplan exception.
@@ -850,48 +220,15 @@ ASTERISK_REGISTER_FILE()
 
 #define SWITCH_DATA_LENGTH 256
 
-#define VAR_BUF_SIZE 4096
-
 #define        VAR_NORMAL              1
 #define        VAR_SOFTTRAN    2
 #define        VAR_HARDTRAN    3
 
-#define BACKGROUND_SKIP                (1 << 0)
-#define BACKGROUND_NOANSWER    (1 << 1)
-#define BACKGROUND_MATCHEXTEN  (1 << 2)
-#define BACKGROUND_PLAYBACK    (1 << 3)
-
-AST_APP_OPTIONS(background_opts, {
-       AST_APP_OPTION('s', BACKGROUND_SKIP),
-       AST_APP_OPTION('n', BACKGROUND_NOANSWER),
-       AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
-       AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
-});
-
-#define WAITEXTEN_MOH          (1 << 0)
-#define WAITEXTEN_DIALTONE     (1 << 1)
-
-AST_APP_OPTIONS(waitexten_opts, {
-       AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
-       AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
-});
-
 struct ast_context;
 struct ast_app;
 
 AST_THREADSTORAGE(switch_data);
 AST_THREADSTORAGE(extensionstate_buf);
-/*!
- * \brief A thread local indicating whether the current thread can run
- * 'dangerous' dialplan functions.
- */
-AST_THREADSTORAGE(thread_inhibit_escalations_tl);
-
-/*!
- * \brief Set to true (non-zero) to globally allow all dangerous dialplan
- * functions to run.
- */
-static int live_dangerously;
 
 /*!
    \brief ast_exten: An extension
@@ -985,24 +322,6 @@ struct ast_context {
        char name[0];                           /*!< Name of the context */
 };
 
-/*! \brief ast_app: A registered application */
-struct ast_app {
-       int (*execute)(struct ast_channel *chan, const char *data);
-       AST_DECLARE_STRING_FIELDS(
-               AST_STRING_FIELD(synopsis);     /*!< Synopsis text for 'show applications' */
-               AST_STRING_FIELD(description);  /*!< Description (help text) for 'show application &lt;name&gt;' */
-               AST_STRING_FIELD(syntax);       /*!< Syntax text for 'core show applications' */
-               AST_STRING_FIELD(arguments);    /*!< Arguments description */
-               AST_STRING_FIELD(seealso);      /*!< See also */
-       );
-#ifdef AST_XML_DOCS
-       enum ast_doc_src docsrc;                /*!< Where the documentation come from. */
-#endif
-       AST_RWLIST_ENTRY(ast_app) list;         /*!< Next app in list */
-       struct ast_module *module;              /*!< Module this app belongs to */
-       char name[0];                           /*!< Name of the application */
-};
-
 /*! \brief ast_state_cb: An extension state notify register item */
 struct ast_state_cb {
        /*! Watcher ID returned when registered. */
@@ -1263,34 +582,10 @@ struct pbx_exception {
        int priority;                           /*!< Priority associated with this exception */
 };
 
-static int pbx_builtin_answer(struct ast_channel *, const char *);
-static int pbx_builtin_goto(struct ast_channel *, const char *);
-static int pbx_builtin_hangup(struct ast_channel *, const char *);
-static int pbx_builtin_background(struct ast_channel *, const char *);
-static int pbx_builtin_wait(struct ast_channel *, const char *);
-static int pbx_builtin_waitexten(struct ast_channel *, const char *);
-static int pbx_builtin_incomplete(struct ast_channel *, const char *);
-static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
-static int pbx_builtin_ringing(struct ast_channel *, const char *);
-static int pbx_builtin_proceeding(struct ast_channel *, const char *);
-static int pbx_builtin_progress(struct ast_channel *, const char *);
-static int pbx_builtin_congestion(struct ast_channel *, const char *);
-static int pbx_builtin_busy(struct ast_channel *, const char *);
-static int pbx_builtin_noop(struct ast_channel *, const char *);
-static int pbx_builtin_gotoif(struct ast_channel *, const char *);
-static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
-static int pbx_builtin_execiftime(struct ast_channel *, const char *);
-static int pbx_builtin_saynumber(struct ast_channel *, const char *);
-static int pbx_builtin_saydigits(struct ast_channel *, const char *);
-static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
-static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *);
-static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
 static int matchcid(const char *cidpattern, const char *callerid);
 #ifdef NEED_DEBUG
 static void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
 #endif
-static int pbx_builtin_importvar(struct ast_channel *, const char *);
-static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
 static void new_find_extension(const char *str, struct scoreboard *score,
                struct match_char *tree, int length, int spec, const char *callerid,
                const char *label, enum ext_match_t action);
@@ -1418,10 +713,6 @@ static unsigned int hashtab_hash_labels(const void *obj)
        return ast_hashtab_hash_string(S_OR(ac->label, ""));
 }
 
-
-AST_RWLOCK_DEFINE_STATIC(globalslock);
-static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
-
 static int autofallthrough = 1;
 static int extenpatternmatchnew = 0;
 static char *overrideswitch = NULL;
@@ -1435,50 +726,6 @@ AST_MUTEX_DEFINE_STATIC(maxcalllock);
 static int countcalls;
 static int totalcalls;
 
-/*!
- * \brief Registered functions container.
- *
- * It is sorted by function name.
- */
-static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
-
-/*! \brief Declaration of builtin applications */
-static struct pbx_builtin {
-       char name[AST_MAX_APP];
-       int (*execute)(struct ast_channel *chan, const char *data);
-} builtins[] =
-{
-       /* These applications are built into the PBX core and do not
-          need separate modules */
-
-       { "Answer",         pbx_builtin_answer },
-       { "BackGround",     pbx_builtin_background },
-       { "Busy",           pbx_builtin_busy },
-       { "Congestion",     pbx_builtin_congestion },
-       { "ExecIfTime",     pbx_builtin_execiftime },
-       { "Goto",           pbx_builtin_goto },
-       { "GotoIf",         pbx_builtin_gotoif },
-       { "GotoIfTime",     pbx_builtin_gotoiftime },
-       { "ImportVar",      pbx_builtin_importvar },
-       { "Hangup",         pbx_builtin_hangup },
-       { "Incomplete",     pbx_builtin_incomplete },
-       { "NoOp",           pbx_builtin_noop },
-       { "Proceeding",     pbx_builtin_proceeding },
-       { "Progress",       pbx_builtin_progress },
-       { "RaiseException", pbx_builtin_raise_exception },
-       { "Ringing",        pbx_builtin_ringing },
-       { "SayAlpha",       pbx_builtin_saycharacters },
-       { "SayAlphaCase",   pbx_builtin_saycharacters_case },
-       { "SayDigits",      pbx_builtin_saydigits },
-       { "SayNumber",      pbx_builtin_saynumber },
-       { "SayPhonetic",    pbx_builtin_sayphonetic },
-       { "Set",            pbx_builtin_setvar },
-       { "MSet",           pbx_builtin_setvar_multiple },
-       { "SetAMAFlags",    pbx_builtin_setamaflags },
-       { "Wait",           pbx_builtin_wait },
-       { "WaitExten",      pbx_builtin_waitexten }
-};
-
 static struct ast_context *contexts;
 static struct ast_hashtab *contexts_table = NULL;
 
@@ -1495,15 +742,6 @@ AST_MUTEX_DEFINE_STATIC(conlock);
  */
 AST_MUTEX_DEFINE_STATIC(context_merge_lock);
 
-/*!
- * \brief Registered applications container.
- *
- * It is sorted by application name.
- */
-static AST_RWLIST_HEAD_STATIC(apps, ast_app);
-
-static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
-
 static int stateid = 1;
 /*!
  * \note When holding this container's lock, do _not_ do
@@ -1693,93 +931,13 @@ int check_contexts(char *file, int line )
 }
 #endif
 
-/*
-   \note This function is special. It saves the stack so that no matter
-   how many times it is called, it returns to the same place */
-int pbx_exec(struct ast_channel *c,    /*!< Channel */
-            struct ast_app *app,       /*!< Application */
-            const char *data)          /*!< Data for execution */
+static inline int include_valid(struct ast_include *i)
 {
-       int res;
-       struct ast_module_user *u = NULL;
-       const char *saved_c_appl;
-       const char *saved_c_data;
+       if (!i->hastime)
+               return 1;
 
-       /* save channel values */
-       saved_c_appl= ast_channel_appl(c);
-       saved_c_data= ast_channel_data(c);
-
-       ast_channel_lock(c);
-       ast_channel_appl_set(c, app->name);
-       ast_channel_data_set(c, data);
-       ast_channel_publish_snapshot(c);
-       ast_channel_unlock(c);
-
-       if (app->module)
-               u = __ast_module_user_add(app->module, c);
-       res = app->execute(c, S_OR(data, ""));
-       if (app->module && u)
-               __ast_module_user_remove(app->module, u);
-       /* restore channel values */
-       ast_channel_appl_set(c, saved_c_appl);
-       ast_channel_data_set(c, saved_c_data);
-       return res;
-}
-
-static struct ast_app *pbx_findapp_nolock(const char *name)
-{
-       struct ast_app *cur;
-       int cmp;
-
-       AST_RWLIST_TRAVERSE(&apps, cur, list) {
-               cmp = strcasecmp(name, cur->name);
-               if (cmp > 0) {
-                       continue;
-               }
-               if (!cmp) {
-                       /* Found it. */
-                       break;
-               }
-               /* Not in container. */
-               cur = NULL;
-               break;
-       }
-
-       return cur;
-}
-
-struct ast_app *pbx_findapp(const char *app)
-{
-       struct ast_app *ret;
-
-       AST_RWLIST_RDLOCK(&apps);
-       ret = pbx_findapp_nolock(app);
-       AST_RWLIST_UNLOCK(&apps);
-
-       return ret;
-}
-
-static struct ast_switch *pbx_findswitch(const char *sw)
-{
-       struct ast_switch *asw;
-
-       AST_RWLIST_RDLOCK(&switches);
-       AST_RWLIST_TRAVERSE(&switches, asw, list) {
-               if (!strcasecmp(asw->name, sw))
-                       break;
-       }
-       AST_RWLIST_UNLOCK(&switches);
-
-       return asw;
-}
-
-static inline int include_valid(struct ast_include *i)
-{
-       if (!i->hastime)
-               return 1;
-
-       return ast_check_timing(&(i->timing));
-}
+       return ast_check_timing(&(i->timing));
+}
 
 static void pbx_destroy(struct ast_pbx *p)
 {
@@ -3514,291 +2672,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        return NULL;
 }
 
-/*!
- * \brief extract offset:length from variable name.
- * \return 1 if there is a offset:length part, which is
- * trimmed off (values go into variables)
- */
-static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
-{
-       int parens = 0;
-
-       *offset = 0;
-       *length = INT_MAX;
-       *isfunc = 0;
-       for (; *var; var++) {
-               if (*var == '(') {
-                       (*isfunc)++;
-                       parens++;
-               } else if (*var == ')') {
-                       parens--;
-               } else if (*var == ':' && parens == 0) {
-                       *var++ = '\0';
-                       sscanf(var, "%30d:%30d", offset, length);
-                       return 1; /* offset:length valid */
-               }
-       }
-       return 0;
-}
-
-/*!
- *\brief takes a substring. It is ok to call with value == workspace.
- * \param value
- * \param offset < 0 means start from the end of the string and set the beginning
- *   to be that many characters back.
- * \param length is the length of the substring, a value less than 0 means to leave
- * that many off the end.
- * \param workspace
- * \param workspace_len
- * Always return a copy in workspace.
- */
-static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
-{
-       char *ret = workspace;
-       int lr; /* length of the input string after the copy */
-
-       ast_copy_string(workspace, value, workspace_len); /* always make a copy */
-
-       lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
-
-       /* Quick check if no need to do anything */
-       if (offset == 0 && length >= lr)        /* take the whole string */
-               return ret;
-
-       if (offset < 0) {       /* translate negative offset into positive ones */
-               offset = lr + offset;
-               if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
-                       offset = 0;
-       }
-
-       /* too large offset result in empty string so we know what to return */
-       if (offset >= lr)
-               return ret + lr;        /* the final '\0' */
-
-       ret += offset;          /* move to the start position */
-       if (length >= 0 && length < lr - offset)        /* truncate if necessary */
-               ret[length] = '\0';
-       else if (length < 0) {
-               if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
-                       ret[lr + length - offset] = '\0';
-               else
-                       ret[0] = '\0';
-       }
-
-       return ret;
-}
-
-static const char *ast_str_substring(struct ast_str *value, int offset, int length)
-{
-       int lr; /* length of the input string after the copy */
-
-       lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
-
-       /* Quick check if no need to do anything */
-       if (offset == 0 && length >= lr)        /* take the whole string */
-               return ast_str_buffer(value);
-
-       if (offset < 0) {       /* translate negative offset into positive ones */
-               offset = lr + offset;
-               if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
-                       offset = 0;
-       }
-
-       /* too large offset result in empty string so we know what to return */
-       if (offset >= lr) {
-               ast_str_reset(value);
-               return ast_str_buffer(value);
-       }
-
-       if (offset > 0) {
-               /* Go ahead and chop off the beginning */
-               memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
-               lr -= offset;
-       }
-
-       if (length >= 0 && length < lr) {       /* truncate if necessary */
-               char *tmp = ast_str_buffer(value);
-               tmp[length] = '\0';
-               ast_str_update(value);
-       } else if (length < 0) {
-               if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
-                       char *tmp = ast_str_buffer(value);
-                       tmp[lr + length] = '\0';
-                       ast_str_update(value);
-               } else {
-                       ast_str_reset(value);
-               }
-       } else {
-               /* Nothing to do, but update the buffer length */
-               ast_str_update(value);
-       }
-
-       return ast_str_buffer(value);
-}
-
-/*! \brief  Support for Asterisk built-in variables in the dialplan
-
-\note  See also
-       - \ref AstVar   Channel variables
-       - \ref AstCauses The HANGUPCAUSE variable
- */
-void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
-{
-       struct ast_str *str = ast_str_create(16);
-       const char *cret;
-
-       cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
-       ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
-       *ret = cret ? workspace : NULL;
-       ast_free(str);
-}
-
-const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
-{
-       const char not_found = '\0';
-       char *tmpvar;
-       const char *ret;
-       const char *s;  /* the result */
-       int offset, length;
-       int i, need_substring;
-       struct varshead *places[2] = { headp, &globals };       /* list of places where we may look */
-       char workspace[20];
-
-       if (c) {
-               ast_channel_lock(c);
-               places[0] = ast_channel_varshead(c);
-       }
-       /*
-        * Make a copy of var because parse_variable_name() modifies the string.
-        * Then if called directly, we might need to run substring() on the result;
-        * remember this for later in 'need_substring', 'offset' and 'length'
-        */
-       tmpvar = ast_strdupa(var);      /* parse_variable_name modifies the string */
-       need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
-
-       /*
-        * Look first into predefined variables, then into variable lists.
-        * Variable 's' points to the result, according to the following rules:
-        * s == &not_found (set at the beginning) means that we did not find a
-        *      matching variable and need to look into more places.
-        * If s != &not_found, s is a valid result string as follows:
-        * s = NULL if the variable does not have a value;
-        *      you typically do this when looking for an unset predefined variable.
-        * s = workspace if the result has been assembled there;
-        *      typically done when the result is built e.g. with an snprintf(),
-        *      so we don't need to do an additional copy.
-        * s != workspace in case we have a string, that needs to be copied
-        *      (the ast_copy_string is done once for all at the end).
-        *      Typically done when the result is already available in some string.
-        */
-       s = &not_found; /* default value */
-       if (c) {        /* This group requires a valid channel */
-               /* Names with common parts are looked up a piece at a time using strncmp. */
-               if (!strncmp(var, "CALL", 4)) {
-                       if (!strncmp(var + 4, "ING", 3)) {
-                               if (!strcmp(var + 7, "PRES")) {                 /* CALLINGPRES */
-                                       ast_str_set(str, maxlen, "%d",
-                                               ast_party_id_presentation(&ast_channel_caller(c)->id));
-                                       s = ast_str_buffer(*str);
-                               } else if (!strcmp(var + 7, "ANI2")) {          /* CALLINGANI2 */
-                                       ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
-                                       s = ast_str_buffer(*str);
-                               } else if (!strcmp(var + 7, "TON")) {           /* CALLINGTON */
-                                       ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
-                                       s = ast_str_buffer(*str);
-                               } else if (!strcmp(var + 7, "TNS")) {           /* CALLINGTNS */
-                                       ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
-                                       s = ast_str_buffer(*str);
-                               }
-                       }
-               } else if (!strcmp(var, "HINT")) {
-                       s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
-               } else if (!strcmp(var, "HINTNAME")) {
-                       s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
-               } else if (!strcmp(var, "EXTEN")) {
-                       s = ast_channel_exten(c);
-               } else if (!strcmp(var, "CONTEXT")) {
-                       s = ast_channel_context(c);
-               } else if (!strcmp(var, "PRIORITY")) {
-                       ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
-                       s = ast_str_buffer(*str);
-               } else if (!strcmp(var, "CHANNEL")) {
-                       s = ast_channel_name(c);
-               } else if (!strcmp(var, "UNIQUEID")) {
-                       s = ast_channel_uniqueid(c);
-               } else if (!strcmp(var, "HANGUPCAUSE")) {
-                       ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
-                       s = ast_str_buffer(*str);
-               }
-       }
-       if (s == &not_found) { /* look for more */
-               if (!strcmp(var, "EPOCH")) {
-                       ast_str_set(str, maxlen, "%d", (int) time(NULL));
-                       s = ast_str_buffer(*str);
-               } else if (!strcmp(var, "SYSTEMNAME")) {
-                       s = ast_config_AST_SYSTEM_NAME;
-               } else if (!strcmp(var, "ASTETCDIR")) {
-                       s = ast_config_AST_CONFIG_DIR;
-               } else if (!strcmp(var, "ASTMODDIR")) {
-                       s = ast_config_AST_MODULE_DIR;
-               } else if (!strcmp(var, "ASTVARLIBDIR")) {
-                       s = ast_config_AST_VAR_DIR;
-               } else if (!strcmp(var, "ASTDBDIR")) {
-                       s = ast_config_AST_DB;
-               } else if (!strcmp(var, "ASTKEYDIR")) {
-                       s = ast_config_AST_KEY_DIR;
-               } else if (!strcmp(var, "ASTDATADIR")) {
-                       s = ast_config_AST_DATA_DIR;
-               } else if (!strcmp(var, "ASTAGIDIR")) {
-                       s = ast_config_AST_AGI_DIR;
-               } else if (!strcmp(var, "ASTSPOOLDIR")) {
-                       s = ast_config_AST_SPOOL_DIR;
-               } else if (!strcmp(var, "ASTRUNDIR")) {
-                       s = ast_config_AST_RUN_DIR;
-               } else if (!strcmp(var, "ASTLOGDIR")) {
-                       s = ast_config_AST_LOG_DIR;
-               } else if (!strcmp(var, "ENTITYID")) {
-                       ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
-                       s = workspace;
-               }
-       }
-       /* if not found, look into chanvars or global vars */
-       for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
-               struct ast_var_t *variables;
-               if (!places[i])
-                       continue;
-               if (places[i] == &globals)
-                       ast_rwlock_rdlock(&globalslock);
-               AST_LIST_TRAVERSE(places[i], variables, entries) {
-                       if (!strcmp(ast_var_name(variables), var)) {
-                               s = ast_var_value(variables);
-                               break;
-                       }
-               }
-               if (places[i] == &globals)
-                       ast_rwlock_unlock(&globalslock);
-       }
-       if (s == &not_found || s == NULL) {
-               ast_debug(5, "Result of '%s' is NULL\n", var);
-               ret = NULL;
-       } else {
-               ast_debug(5, "Result of '%s' is '%s'\n", var, s);
-               if (s != ast_str_buffer(*str)) {
-                       ast_str_set(str, maxlen, "%s", s);
-               }
-               ret = ast_str_buffer(*str);
-               if (need_substring) {
-                       ret = ast_str_substring(*str, offset, length);
-                       ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
-               }
-       }
-
-       if (c) {
-               ast_channel_unlock(c);
-       }
-       return ret;
-}
-
 static void exception_store_free(void *data)
 {
        struct pbx_exception *exception = data;
@@ -3822,7 +2695,7 @@ static const struct ast_datastore_info exception_store_info = {
  * \retval 0 on success.
  * \retval -1 on error.
  */
-static int raise_exception(struct ast_channel *chan, const char *reason, int priority)
+int raise_exception(struct ast_channel *chan, const char *reason, int priority)
 {
        struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
        struct pbx_exception *exception = NULL;
@@ -3848,12 +2721,6 @@ static int raise_exception(struct ast_channel *chan, const char *reason, int pri
        return 0;
 }
 
-int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
-{
-       /* Priority will become 1, next time through the AUTOLOOP */
-       return raise_exception(chan, reason, 0);
-}
-
 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
 {
        struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
@@ -3879,8008 +2746,5185 @@ static struct ast_custom_function exception_function = {
        .read = acf_exception_read,
 };
 
-static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+/*!
+ * \brief The return value depends on the action:
+ *
+ * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
+ *     and return 0 on failure, -1 on match;
+ * E_FINDLABEL maps the label to a priority, and returns
+ *     the priority on success, ... XXX
+ * E_SPAWN, spawn an application,
+ *
+ * \retval 0 on success.
+ * \retval  -1 on failure.
+ *
+ * \note The channel is auto-serviced in this function, because doing an extension
+ * match may block for a long time.  For example, if the lookup has to use a network
+ * dialplan switch, such as DUNDi or IAX2, it may take a while.  However, the channel
+ * auto-service code will queue up any important signalling frames to be processed
+ * after this is done.
+ */
+static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
+  const char *context, const char *exten, int priority,
+  const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
 {
-       struct ast_custom_function *acf;
-       int count_acf = 0;
-       int like = 0;
-
-       switch (cmd) {
-       case CLI_INIT:
-               e->command = "core show functions [like]";
-               e->usage =
-                       "Usage: core show functions [like <text>]\n"
-                       "       List builtin functions, optionally only those matching a given string\n";
-               return NULL;
-       case CLI_GENERATE:
-               return NULL;
-       }
-
-       if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
-               like = 1;
-       } else if (a->argc != 3) {
-               return CLI_SHOWUSAGE;
-       }
+       struct ast_exten *e;
+       struct ast_app *app;
+       char *substitute = NULL;
+       int res;
+       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
+       char passdata[EXT_DATA_SIZE];
+       int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
 
-       ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
+       ast_rdlock_contexts();
+       if (found)
+               *found = 0;
 
-       AST_RWLIST_RDLOCK(&acf_root);
-       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
-               if (!like || strstr(acf->name, a->argv[4])) {
-                       count_acf++;
-                       ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n",
-                               S_OR(acf->name, ""),
-                               S_OR(acf->syntax, ""),
-                               S_OR(acf->synopsis, ""));
+       e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
+       if (e) {
+               if (found)
+                       *found = 1;
+               if (matching_action) {
+                       ast_unlock_contexts();
+                       return -1;      /* success, we found it */
+               } else if (action == E_FINDLABEL) { /* map the label to a priority */
+                       res = e->priority;
+                       ast_unlock_contexts();
+                       return res;     /* the priority we were looking for */
+               } else {        /* spawn */
+                       if (!e->cached_app)
+                               e->cached_app = pbx_findapp(e->app);
+                       app = e->cached_app;
+                       if (ast_strlen_zero(e->data)) {
+                               *passdata = '\0';
+                       } else {
+                               const char *tmp;
+                               if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
+                                       /* no variables to substitute, copy on through */
+                                       ast_copy_string(passdata, e->data, sizeof(passdata));
+                               } else {
+                                       /* save e->data on stack for later processing after lock released */
+                                       substitute = ast_strdupa(e->data);
+                               }
+                       }
+                       ast_unlock_contexts();
+                       if (!app) {
+                               ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
+                               return -1;
+                       }
+                       if (ast_channel_context(c) != context)
+                               ast_channel_context_set(c, context);
+                       if (ast_channel_exten(c) != exten)
+                               ast_channel_exten_set(c, exten);
+                       ast_channel_priority_set(c, priority);
+                       if (substitute) {
+                               pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
+                       }
+                       ast_debug(1, "Launching '%s'\n", app_name(app));
+                       if (VERBOSITY_ATLEAST(3)) {
+                               ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
+                                       exten, context, priority,
+                                       COLORIZE(COLOR_BRCYAN, 0, app_name(app)),
+                                       COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(c)),
+                                       COLORIZE(COLOR_BRMAGENTA, 0, passdata),
+                                       "in new stack");
+                       }
+                       return pbx_exec(c, app, passdata);      /* 0 on success, -1 on failure */
+               }
+       } else if (q.swo) {     /* not found here, but in another switch */
+               if (found)
+                       *found = 1;
+               ast_unlock_contexts();
+               if (matching_action) {
+                       return -1;
+               } else {
+                       if (!q.swo->exec) {
+                               ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
+                               res = -1;
+                       }
+                       return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
+               }
+       } else {        /* not found anywhere, see what happened */
+               ast_unlock_contexts();
+               /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
+               switch (q.status) {
+               case STATUS_NO_CONTEXT:
+                       if (!matching_action && !combined_find_spawn)
+                               ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
+                       break;
+               case STATUS_NO_EXTENSION:
+                       if (!matching_action && !combined_find_spawn)
+                               ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
+                       break;
+               case STATUS_NO_PRIORITY:
+                       if (!matching_action && !combined_find_spawn)
+                               ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
+                       break;
+               case STATUS_NO_LABEL:
+                       if (context && !combined_find_spawn)
+                               ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
+                       break;
+               default:
+                       ast_debug(1, "Shouldn't happen!\n");
                }
-       }
-       AST_RWLIST_UNLOCK(&acf_root);
 
-       ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
+               return (matching_action) ? 0 : -1;
+       }
+}
 
-       return CLI_SUCCESS;
+/*! \brief Find hint for given extension in context */
+static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
+{
+       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
+       return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
 }
 
-static char *complete_functions(const char *word, int pos, int state)
+static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
 {
-       struct ast_custom_function *cur;
-       char *ret = NULL;
-       int which = 0;
-       int wordlen;
-       int cmp;
-
-       if (pos != 3) {
-               return NULL;
-       }
+       struct ast_exten *e;
+       ast_rdlock_contexts();
+       e = ast_hint_extension_nolock(c, context, exten);
+       ast_unlock_contexts();
+       return e;
+}
 
-       wordlen = strlen(word);
-       AST_RWLIST_RDLOCK(&acf_root);
-       AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
-               /*
-                * Do a case-insensitive search for convenience in this
-                * 'complete' function.
-                *
-                * We must search the entire container because the functions are
-                * sorted and normally found case sensitively.
-                */
-               cmp = strncasecmp(word, cur->name, wordlen);
-               if (!cmp) {
-                       /* Found match. */
-                       if (++which <= state) {
-                               /* Not enough matches. */
-                               continue;
-                       }
-                       ret = ast_strdup(cur->name);
-                       break;
-               }
+enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
+{
+       switch (devstate) {
+       case AST_DEVICE_ONHOLD:
+               return AST_EXTENSION_ONHOLD;
+       case AST_DEVICE_BUSY:
+               return AST_EXTENSION_BUSY;
+       case AST_DEVICE_UNKNOWN:
+               return AST_EXTENSION_NOT_INUSE;
+       case AST_DEVICE_UNAVAILABLE:
+       case AST_DEVICE_INVALID:
+               return AST_EXTENSION_UNAVAILABLE;
+       case AST_DEVICE_RINGINUSE:
+               return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
+       case AST_DEVICE_RINGING:
+               return AST_EXTENSION_RINGING;
+       case AST_DEVICE_INUSE:
+               return AST_EXTENSION_INUSE;
+       case AST_DEVICE_NOT_INUSE:
+               return AST_EXTENSION_NOT_INUSE;
+       case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
+               break;
        }
-       AST_RWLIST_UNLOCK(&acf_root);
 
-       return ret;
+       return AST_EXTENSION_NOT_INUSE;
 }
 
-static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+/*!
+ * \internal
+ * \brief Parse out the presence portion of the hint string
+ */
+static char *parse_hint_presence(struct ast_str *hint_args)
 {
-       struct ast_custom_function *acf;
-       /* Maximum number of characters added by terminal coloring is 22 */
-       char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
-       char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
-       char stxtitle[40], *syntax = NULL, *arguments = NULL;
-       int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
+       char *copy = ast_strdupa(ast_str_buffer(hint_args));
+       char *tmp = "";
 
-       switch (cmd) {
-       case CLI_INIT:
-               e->command = "core show function";
-               e->usage =
-                       "Usage: core show function <function>\n"
-                       "       Describe a particular dialplan function.\n";
+       if ((tmp = strrchr(copy, ','))) {
+               *tmp = '\0';
+               tmp++;
+       } else {
                return NULL;
-       case CLI_GENERATE:
-               return complete_functions(a->word, a->pos, a->n);
        }
+       ast_str_set(&hint_args, 0, "%s", tmp);
+       return ast_str_buffer(hint_args);
+}
 
-       if (a->argc != 4) {
-               return CLI_SHOWUSAGE;
-       }
+/*!
+ * \internal
+ * \brief Parse out the device portion of the hint string
+ */
+static char *parse_hint_device(struct ast_str *hint_args)
+{
+       char *copy = ast_strdupa(ast_str_buffer(hint_args));
+       char *tmp;
 
-       if (!(acf = ast_custom_function_find(a->argv[3]))) {
-               ast_cli(a->fd, "No function by that name registered.\n");
-               return CLI_FAILURE;
+       if ((tmp = strrchr(copy, ','))) {
+               *tmp = '\0';
        }
 
-       syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-       if (!(syntax = ast_malloc(syntax_size))) {
-               ast_cli(a->fd, "Memory allocation failure!\n");
-               return CLI_FAILURE;
-       }
+       ast_str_set(&hint_args, 0, "%s", copy);
+       return ast_str_buffer(hint_args);
+}
 
-       snprintf(info, sizeof(info), "\n  -= Info about function '%s' =- \n\n", acf->name);
-       term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
-       term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
-       term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
-       term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
-       term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
-       term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
-       term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
-#ifdef AST_XML_DOCS
-       if (acf->docsrc == AST_XML_DOC) {
-               arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
-               synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
-               description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
-               seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
-       } else
-#endif
-       {
-               synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-               synopsis = ast_malloc(synopsis_size);
+static void device_state_info_dt(void *obj)
+{
+       struct ast_device_state_info *info = obj;
 
-               description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-               description = ast_malloc(description_size);
+       ao2_cleanup(info->causing_channel);
+}
 
-               arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-               arguments = ast_malloc(arguments_size);
+static struct ao2_container *alloc_device_state_info(void)
+{
+       return ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
+}
 
-               seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
-               seealso = ast_malloc(seealso_size);
+static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
+{
+       char *cur;
+       char *rest;
+       struct ast_devstate_aggregate agg;
 
-               /* check allocated memory. */
-               if (!synopsis || !description || !arguments || !seealso) {
-                       ast_free(synopsis);
-                       ast_free(description);
-                       ast_free(arguments);
-                       ast_free(seealso);
-                       ast_free(syntax);
-                       return CLI_FAILURE;
-               }
+       /* One or more devices separated with a & character */
+       rest = parse_hint_device(hint_app);
 
-               term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
-               term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
-               term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
-               term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
-       }
+       ast_devstate_aggregate_init(&agg);
+       while ((cur = strsep(&rest, "&"))) {
+               enum ast_device_state state = ast_device_state(cur);
 
-       ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
-                       infotitle, syntitle, synopsis, destitle, description,
-                       stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
+               ast_devstate_aggregate_add(&agg, state);
+               if (device_state_info) {
+                       struct ast_device_state_info *obj;
 
-       ast_free(arguments);
-       ast_free(synopsis);
-       ast_free(description);
-       ast_free(seealso);
-       ast_free(syntax);
+                       obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
+                       /* if failed we cannot add this device */
+                       if (obj) {
+                               obj->device_state = state;
+                               strcpy(obj->device_name, cur);
+                               ao2_link(device_state_info, obj);
+                               ao2_ref(obj, -1);
+                       }
+               }
+       }
 
-       return CLI_SUCCESS;
+       return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
 }
 
-static struct ast_custom_function *ast_custom_function_find_nolock(const char *name)
+/*! \brief Check state of extension by using hints */
+static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
 {
-       struct ast_custom_function *cur;
-       int cmp;
+       struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
 
-       AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
-               cmp = strcmp(name, cur->name);
-               if (cmp > 0) {
-                       continue;
-               }
-               if (!cmp) {
-                       /* Found it. */
-                       break;
-               }
-               /* Not in container. */
-               cur = NULL;
-               break;
+       if (!e || !hint_app) {
+               return -1;
        }
 
-       return cur;
+       ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
+       return ast_extension_state3(hint_app, device_state_info);
 }
 
-struct ast_custom_function *ast_custom_function_find(const char *name)
+/*! \brief Return extension_state as string */
+const char *ast_extension_state2str(int extension_state)
 {
-       struct ast_custom_function *acf;
-
-       AST_RWLIST_RDLOCK(&acf_root);
-       acf = ast_custom_function_find_nolock(name);
-       AST_RWLIST_UNLOCK(&acf_root);
+       int i;
 
-       return acf;
+       for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
+               if (extension_states[i].extension_state == extension_state)
+                       return extension_states[i].text;
+       }
+       return "Unknown";
 }
 
-int ast_custom_function_unregister(struct ast_custom_function *acf)
+/*!
+ * \internal
+ * \brief Check extension state for an extension by using hint
+ */
+static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
+       struct ao2_container *device_state_info)
 {
-       struct ast_custom_function *cur;
+       struct ast_exten *e;
 
-       if (!acf) {
-               return -1;
+       if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
+               return -1;                   /* No hint, return -1 */
        }
 
-       AST_RWLIST_WRLOCK(&acf_root);
-       if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
-#ifdef AST_XML_DOCS
-               if (cur->docsrc == AST_XML_DOC) {
-                       ast_string_field_free_memory(acf);
+       if (e->exten[0] == '_') {
+               /* Create this hint on-the-fly */
+               ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
+                       e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
+                       e->registrar);
+               if (!(e = ast_hint_extension(c, context, exten))) {
+                       /* Improbable, but not impossible */
+                       return -1;
                }
-#endif
-               ast_verb(2, "Unregistered custom function %s\n", cur->name);
        }
-       AST_RWLIST_UNLOCK(&acf_root);
 
-       return cur ? 0 : -1;
-}
-
-/*!
- * \brief Returns true if given custom function escalates privileges on read.
- *
- * \param acf Custom function to query.
- * \return True (non-zero) if reads escalate privileges.
- * \return False (zero) if reads just read.
- */
-static int read_escalates(const struct ast_custom_function *acf) {
-       return acf->read_escalates;
+       return ast_extension_state2(e, device_state_info);  /* Check all devices in the hint */
 }
 
-/*!
- * \brief Returns true if given custom function escalates privileges on write.
- *
- * \param acf Custom function to query.
- * \return True (non-zero) if writes escalate privileges.
- * \return False (zero) if writes just write.
- */
-static int write_escalates(const struct ast_custom_function *acf) {
-       return acf->write_escalates;
+/*! \brief Check extension state for an extension by using hint */
+int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
+{
+       return internal_extension_state_extended(c, context, exten, NULL);
 }
 
-/*! \internal
- *  \brief Retrieve the XML documentation of a specified ast_custom_function,
- *         and populate ast_custom_function string fields.
- *  \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
- *             but with a function 'name'.
- *  \retval -1 On error.
- *  \retval 0 On succes.
- */
-static int acf_retrieve_docs(struct ast_custom_function *acf)
+/*! \brief Check extended extension state for an extension by using hint */
+int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
+       struct ao2_container **device_state_info)
 {
-#ifdef AST_XML_DOCS
-       char *tmpxml;
+       struct ao2_container *container = NULL;
+       int ret;
 
-       /* Let's try to find it in the Documentation XML */
-       if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
-               return 0;
+       if (device_state_info) {
+               container = alloc_device_state_info();
        }
 
-       if (ast_string_field_init(acf, 128)) {
-               return -1;
+       ret = internal_extension_state_extended(c, context, exten, container);
+       if (ret < 0 && container) {
+               ao2_ref(container, -1);
+               container = NULL;
        }
 
-       /* load synopsis */
-       tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
-       ast_string_field_set(acf, synopsis, tmpxml);
-       ast_free(tmpxml);
-
-       /* load description */
-       tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
-       ast_string_field_set(acf, desc, tmpxml);
-       ast_free(tmpxml);
-
-       /* load syntax */
-       tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
-       ast_string_field_set(acf, syntax, tmpxml);
-       ast_free(tmpxml);
-
-       /* load arguments */
-       tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
-       ast_string_field_set(acf, arguments, tmpxml);
-       ast_free(tmpxml);
-
-       /* load seealso */
-       tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
-       ast_string_field_set(acf, seealso, tmpxml);
-       ast_free(tmpxml);
-
-       acf->docsrc = AST_XML_DOC;
-#endif
+       if (device_state_info) {
+               get_device_state_causing_channels(container);
+               *device_state_info = container;
+       }
 
-       return 0;
+       return ret;
 }
 
-int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
+static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
 {
-       struct ast_custom_function *cur;
+       struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
+       char *presence_provider;
+       const char *app;
 
-       if (!acf) {
+       if (!e || !hint_app) {
                return -1;
        }
 
-       acf->mod = mod;
-#ifdef AST_XML_DOCS
-       acf->docsrc = AST_STATIC_DOC;
-#endif
-
-       if (acf_retrieve_docs(acf)) {
+       app = ast_get_extension_app(e);
+       if (ast_strlen_zero(app)) {
                return -1;
        }
 
-       AST_RWLIST_WRLOCK(&acf_root);
-
-       cur = ast_custom_function_find_nolock(acf->name);
-       if (cur) {
-               ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
-               AST_RWLIST_UNLOCK(&acf_root);
-               return -1;
-       }
+       ast_str_set(&hint_app, 0, "%s", app);
+       presence_provider = parse_hint_presence(hint_app);
 
-       /* Store in alphabetical order */
-       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
-               if (strcmp(acf->name, cur->name) < 0) {
-                       AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
-                       break;
-               }
-       }
-       AST_RWLIST_TRAVERSE_SAFE_END;
-       if (!cur) {
-               AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
+       if (ast_strlen_zero(presence_provider)) {
+               /* No presence string in the hint */
+               return 0;
        }
 
-       AST_RWLIST_UNLOCK(&acf_root);
-
-       ast_verb(2, "Registered custom function '" COLORIZE_FMT "'\n", COLORIZE(COLOR_BRCYAN, 0, acf->name));
-
-       return 0;
+       return ast_presence_state(presence_provider, subtype, message);
 }
 
-int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
+int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
 {
-       int res;
+       struct ast_exten *e;
 
-       res = __ast_custom_function_register(acf, mod);
-       if (res != 0) {
-               return -1;
+       if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
+               return -1;                   /* No hint, return -1 */
        }
 
-       switch (escalation) {
-       case AST_CFE_NONE:
-               break;
-       case AST_CFE_READ:
-               acf->read_escalates = 1;
-               break;
-       case AST_CFE_WRITE:
-               acf->write_escalates = 1;
-               break;
-       case AST_CFE_BOTH:
-               acf->read_escalates = 1;
-               acf->write_escalates = 1;
-               break;
+       if (e->exten[0] == '_') {
+               /* Create this hint on-the-fly */
+               ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
+                       e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
+                       e->registrar);
+               if (!(e = ast_hint_extension(c, context, exten))) {
+                       /* Improbable, but not impossible */
+                       return -1;
+               }
        }
 
-       return 0;
+       return extension_presence_state_helper(e, subtype, message);
 }
 
-/*! \brief return a pointer to the arguments of the function,
- * and terminates the function name with '\\0'
- */
-static char *func_args(char *function)
+static int execute_state_callback(ast_state_cb_type cb,
+       const char *context,
+       const char *exten,
+       void *data,
+       enum ast_state_cb_update_reason reason,
+       struct ast_hint *hint,
+       struct ao2_container *device_state_info)
 {
-       char *args = strchr(function, '(');
+       int res = 0;
+       struct ast_state_cb_info info = { 0, };
 
-       if (!args) {
-               ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses.  Assuming null argument.\n", function);
-       } else {
-               char *p;
-               *args++ = '\0';
-               if ((p = strrchr(args, ')'))) {
-                       *p = '\0';
-               } else {
-                       ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
-               }
-       }
-       return args;
-}
-
-void pbx_live_dangerously(int new_live_dangerously)
-{
-       if (new_live_dangerously && !live_dangerously) {
-               ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
-                       "See https://wiki.asterisk.org/wiki/x/1gKfAQ for more details.\n");
-       }
-
-       if (!new_live_dangerously && live_dangerously) {
-               ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
-       }
-       live_dangerously = new_live_dangerously;
-}
-
-int ast_thread_inhibit_escalations(void)
-{
-       int *thread_inhibit_escalations;
-
-       thread_inhibit_escalations = ast_threadstorage_get(
-               &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
+       info.reason = reason;
 
-       if (thread_inhibit_escalations == NULL) {
-               ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
-               return -1;
+       /* Copy over current hint data */
+       if (hint) {
+               ao2_lock(hint);
+               info.exten_state = hint->laststate;
+               info.device_state_info = device_state_info;
+               info.presence_state = hint->last_presence_state;
+               if (!(ast_strlen_zero(hint->last_presence_subtype))) {
+                       info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
+               } else {
+                       info.presence_subtype = "";
+               }
+               if (!(ast_strlen_zero(hint->last_presence_message))) {
+                       info.presence_message = ast_strdupa(hint->last_presence_message);
+               } else {
+                       info.presence_message = "";
+               }
+               ao2_unlock(hint);
+       } else {
+               info.exten_state = AST_EXTENSION_REMOVED;
        }
 
-       *thread_inhibit_escalations = 1;
-       return 0;
-}
-
-/*!
- * \brief Indicates whether the current thread inhibits the execution of
- * dangerous functions.
- *
- * \return True (non-zero) if dangerous function execution is inhibited.
- * \return False (zero) if dangerous function execution is allowed.
- */
-static int thread_inhibits_escalations(void)
-{
-       int *thread_inhibit_escalations;
-
-       thread_inhibit_escalations = ast_threadstorage_get(
-               &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
-
-       if (thread_inhibit_escalations == NULL) {
-               ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
-               /* On error, assume that we are inhibiting */
-               return 1;
-       }
+       /* NOTE: The casts will not be needed for v10 and later */
+       res = cb((char *) context, (char *) exten, &info, data);
 
-       return *thread_inhibit_escalations;
+       return res;
 }
 
 /*!
- * \brief Determines whether execution of a custom function's read function
- * is allowed.
+ * /internal
+ * /brief Identify a channel for every device which is supposedly responsible for the device state.
  *
- * \param acfptr Custom function to check
- * \return True (non-zero) if reading is allowed.
- * \return False (zero) if reading is not allowed.
+ * Especially when the device is ringing, the oldest ringing channel is chosen.
+ * For all other cases the first encountered channel in the specific state is chosen.
  */
-static int is_read_allowed(struct ast_custom_function *acfptr)
+static void get_device_state_causing_channels(struct ao2_container *c)
 {
-       if (!acfptr) {
-               return 1;
-       }
+       struct ao2_iterator iter;
+       struct ast_device_state_info *info;
+       struct ast_channel *chan;
 
-       if (!read_escalates(acfptr)) {
-               return 1;
+       if (!c || !ao2_container_count(c)) {
+               return;
        }
+       iter = ao2_iterator_init(c, 0);
+       for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
+               enum ast_channel_state search_state = 0; /* prevent false uninit warning */
+               char match[AST_CHANNEL_NAME];
+               struct ast_channel_iterator *chan_iter;
+               struct timeval chantime = {0, }; /* prevent false uninit warning */
 
-       if (!thread_inhibits_escalations()) {
-               return 1;
-       }
+               switch (info->device_state) {
+               case AST_DEVICE_RINGING:
+               case AST_DEVICE_RINGINUSE:
+                       /* find ringing channel */
+                       search_state = AST_STATE_RINGING;
+                       break;
+               case AST_DEVICE_BUSY:
+                       /* find busy channel */
+                       search_state = AST_STATE_BUSY;
+                       break;
+               case AST_DEVICE_ONHOLD:
+               case AST_DEVICE_INUSE:
+                       /* find up channel */
+                       search_state = AST_STATE_UP;
+                       break;
+               case AST_DEVICE_UNKNOWN:
+               case AST_DEVICE_NOT_INUSE:
+               case AST_DEVICE_INVALID:
+               case AST_DEVICE_UNAVAILABLE:
+               case AST_DEVICE_TOTAL /* not a state */:
+                       /* no channels are of interest */
+                       continue;
+               }
 
-       if (live_dangerously) {
-               /* Global setting overrides the thread's preference */
-               ast_debug(2, "Reading %s from a dangerous context\n",
-                       acfptr->name);
-               return 1;
+               /* iterate over all channels of the device */
+               snprintf(match, sizeof(match), "%s-", info->device_name);
+               chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
+               for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
+                       ast_channel_lock(chan);
+                       /* this channel's state doesn't match */
+                       if (search_state != ast_channel_state(chan)) {
+                               ast_channel_unlock(chan);
+                               continue;
+                       }
+                       /* any non-ringing channel will fit */
+                       if (search_state != AST_STATE_RINGING) {
+                               ast_channel_unlock(chan);
+                               info->causing_channel = chan; /* is kept ref'd! */
+                               break;
+                       }
+                       /* but we need the oldest ringing channel of the device to match with undirected pickup */
+                       if (!info->causing_channel) {
+                               chantime = ast_channel_creationtime(chan);
+                               ast_channel_ref(chan); /* must ref it! */
+                               info->causing_channel = chan;
+                       } else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
+                               chantime = ast_channel_creationtime(chan);
+                               ast_channel_unref(info->causing_channel);
+                               ast_channel_ref(chan); /* must ref it! */
+                               info->causing_channel = chan;
+                       }
+                       ast_channel_unlock(chan);
+               }
+               ast_channel_iterator_destroy(chan_iter);
        }
-
-       /* We have no reason to allow this function to execute */
-       return 0;
+       ao2_iterator_destroy(&iter);
 }
 
-/*!
- * \brief Determines whether execution of a custom function's write function
- * is allowed.
- *
- * \param acfptr Custom function to check
- * \return True (non-zero) if writing is allowed.
- * \return False (zero) if writing is not allowed.
- */
-static int is_write_allowed(struct ast_custom_function *acfptr)
+static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
 {
-       if (!acfptr) {
-               return 1;
-       }
-
-       if (!write_escalates(acfptr)) {
-               return 1;
-       }
+       struct ast_device_state_message *dev_state;
+       struct ast_hint *hint;
+       struct ast_str *hint_app;
+       struct ast_hintdevice *device;
+       struct ast_hintdevice *cmpdevice;
+       struct ao2_iterator *dev_iter;
+       struct ao2_iterator cb_iter;
+       char context_name[AST_MAX_CONTEXT];
+       char exten_name[AST_MAX_EXTENSION];
 
-       if (!thread_inhibits_escalations()) {
-               return 1;
+       if (ast_device_state_message_type() != stasis_message_type(msg)) {
+               return;
        }
 
-       if (live_dangerously) {
-               /* Global setting overrides the thread's preference */
-               ast_debug(2, "Writing %s from a dangerous context\n",
-                       acfptr->name);
-               return 1;
+       dev_state = stasis_message_data(msg);
+       if (dev_state->eid) {
+               /* ignore non-aggregate states */
+               return;
        }
 
-       /* We have no reason to allow this function to execute */
-       return 0;
-}
-
-int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
-{
-       char *copy = ast_strdupa(function);
-       char *args = func_args(copy);
-       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
-       int res;
-       struct ast_module_user *u = NULL;
-
-       if (acfptr == NULL) {
-               ast_log(LOG_ERROR, "Function %s not registered\n", copy);
-       } else if (!acfptr->read && !acfptr->read2) {
-               ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
-       } else if (!is_read_allowed(acfptr)) {
-               ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
-       } else if (acfptr->read) {
-               if (acfptr->mod) {
-                       u = __ast_module_user_add(acfptr->mod, chan);
-               }
-               res = acfptr->read(chan, copy, args, workspace, len);
-               if (acfptr->mod && u) {
-                       __ast_module_user_remove(acfptr->mod, u);
-               }
-               return res;
-       } else {
-               struct ast_str *str = ast_str_create(16);
-               if (acfptr->mod) {
-                       u = __ast_module_user_add(acfptr->mod, chan);
-               }
-               res = acfptr->read2(chan, copy, args, &str, 0);
-               if (acfptr->mod && u) {
-                       __ast_module_user_remove(acfptr->mod, u);
-               }
-               ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
-               ast_free(str);
-               return res;
+       if (ao2_container_count(hintdevices) == 0) {
+               /* There are no hints monitoring devices. */
+               return;
        }
-       return -1;
-}
 
-int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
-{
-       char *copy = ast_strdupa(function);
-       char *args = func_args(copy);
-       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
-       int res;
-       struct ast_module_user *u = NULL;
-
-       if (acfptr == NULL) {
-               ast_log(LOG_ERROR, "Function %s not registered\n", copy);
-       } else if (!acfptr->read && !acfptr->read2) {
-               ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
-       } else if (!is_read_allowed(acfptr)) {
-               ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
-       } else {
-               if (acfptr->mod) {
-                       u = __ast_module_user_add(acfptr->mod, chan);
-               }
-               ast_str_reset(*str);
-               if (acfptr->read2) {
-                       /* ast_str enabled */
-                       res = acfptr->read2(chan, copy, args, str, maxlen);
-               } else {
-                       /* Legacy function pointer, allocate buffer for result */
-                       int maxsize = ast_str_size(*str);
-                       if (maxlen > -1) {
-                               if (maxlen == 0) {
-                                       if (acfptr->read_max) {
-                                               maxsize = acfptr->read_max;
-                                       } else {
-                                               maxsize = VAR_BUF_SIZE;
-                                       }
-                               } else {
-                                       maxsize = maxlen;
-                               }
-                               ast_str_make_space(str, maxsize);
-                       }
-                       res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
-               }
-               if (acfptr->mod && u) {
-                       __ast_module_user_remove(acfptr->mod, u);
-               }
-               return res;
+       hint_app = ast_str_create(1024);
+       if (!hint_app) {
+               return;
        }
-       return -1;
-}
 
-int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
-{
-       char *copy = ast_strdupa(function);
-       char *args = func_args(copy);
-       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
+       cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(dev_state->device));
+       strcpy(cmpdevice->hintdevice, dev_state->device);
 
-       if (acfptr == NULL) {
-               ast_log(LOG_ERROR, "Function %s not registered\n", copy);
-       } else if (!acfptr->write) {
-               ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
-       } else if (!is_write_allowed(acfptr)) {
-               ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
-       } else {
-               int res;
-               struct ast_module_user *u = NULL;
-               if (acfptr->mod)
-                       u = __ast_module_user_add(acfptr->mod, chan);
-               res = acfptr->write(chan, copy, args, value);
-               if (acfptr->mod && u)
-                       __ast_module_user_remove(acfptr->mod, u);
-               return res;
+       ast_mutex_lock(&context_merge_lock);/* Hold off ast_merge_contexts_and_delete */
+       dev_iter = ao2_t_callback(hintdevices,
+               OBJ_SEARCH_OBJECT | OBJ_MULTIPLE,
+               hintdevice_cmp_multiple,
+               cmpdevice,
+               "find devices in container");
+       if (!dev_iter) {
+               ast_mutex_unlock(&context_merge_lock);
+               ast_free(hint_app);
+               return;
        }
 
-       return -1;
-}
+       for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
+               struct ast_state_cb *state_cb;
+               int state;
+               int same_state;
+               struct ao2_container *device_state_info;
+               int first_extended_cb_call = 1;
 
-void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
-{
-       /* Substitutes variables into buf, based on string templ */
-       char *cp4 = NULL;
-       const char *whereweare;
-       int orig_size = 0;
-       int offset, offset2, isfunction;
-       const char *nextvar, *nextexp, *nextthing;
-       const char *vars, *vare;
-       char *finalvars;
-       int pos, brackets, needsub, len;
-       struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
-
-       ast_str_reset(*buf);
-       whereweare = templ;
-       while (!ast_strlen_zero(whereweare)) {
-               /* reset our buffer */
-               ast_str_reset(substr3);
-
-               /* Assume we're copying the whole remaining string */
-               pos = strlen(whereweare);
-               nextvar = NULL;
-               nextexp = NULL;
-               nextthing = strchr(whereweare, '$');
-               if (nextthing) {
-                       switch (nextthing[1]) {
-                       case '{':
-                               nextvar = nextthing;
-                               pos = nextvar - whereweare;
-                               break;
-                       case '[':
-                               nextexp = nextthing;
-                               pos = nextexp - whereweare;
-                               break;
-                       default:
-                               pos = 1;
-                       }
+               if (!device->hint) {
+                       /* Should never happen. */
+                       continue;
                }
+               hint = device->hint;
 
-               if (pos) {
-                       /* Copy that many bytes */
-                       ast_str_append_substr(buf, maxlen, whereweare, pos);
-
-                       templ += pos;
-                       whereweare += pos;
-               }
-
-               if (nextvar) {
-                       /* We have a variable.  Find the start and end, and determine
-                          if we are going to have to recursively call ourselves on the
-                          contents */
-                       vars = vare = nextvar + 2;
-                       brackets = 1;
-                       needsub = 0;
-
-                       /* Find the end of it */
-                       while (brackets && *vare) {
-                               if ((vare[0] == '$') && (vare[1] == '{')) {
-                                       needsub++;
-                               } else if (vare[0] == '{') {
-                                       brackets++;
-                               } else if (vare[0] == '}') {
-                                       brackets--;
-                               } else if ((vare[0] == '$') && (vare[1] == '['))
-                                       needsub++;
-                               vare++;
-                       }
-                       if (brackets)
-                               ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
-                       len = vare - vars - 1;
-
-                       /* Skip totally over variable string */
-                       whereweare += (len + 3);
+               ao2_lock(hint);
+               if (!hint->exten) {
+                       /* The extension has already been destroyed */
+                       ao2_unlock(hint);
+                       continue;
+               }
 
-                       /* Store variable name (and truncate) */
-                       ast_str_set_substr(&substr1, 0, vars, len);
-                       ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
+               /*
+                * Save off strings in case the hint extension gets destroyed
+                * while we are notifying the watchers.
+                */
+               ast_copy_string(context_name,
+                       ast_get_context_name(ast_get_extension_context(hint->exten)),
+                       sizeof(context_name));
+               ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
+                       sizeof(exten_name));
+               ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
+               ao2_unlock(hint);
 
-                       /* Substitute if necessary */
-                       if (needsub) {
-                               size_t my_used;
+               /*
+                * Get device state for this hint.
+                *
+                * NOTE: We cannot hold any locks while determining the hint
+                * device state or notifying the watchers without causing a
+                * deadlock.  (conlock, hints, and hint)
+                */
+               /* Make a container so state3 can fill it if we wish.
+                * If that failed we simply do not provide the extended state info.
+                */
+               device_state_info = alloc_device_state_info();
+               state = ast_extension_state3(hint_app, device_state_info);
+               if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) {
+                       ao2_cleanup(device_state_info);
+                       continue;
+               }
 
-                               if (!substr2) {
-                                       substr2 = ast_str_create(16);
-                               }
-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
-                               finalvars = ast_str_buffer(substr2);
-                       } else {
-                               finalvars = ast_str_buffer(substr1);
-                       }
+               /* Device state changed since last check - notify the watchers. */
+               hint->laststate = state;        /* record we saw the change */
 
-                       parse_variable_name(finalvars, &offset, &offset2, &isfunction);
-                       if (isfunction) {
-                               /* Evaluate function */
-                               if (c || !headp) {
-                                       cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
-                               } else {
-                                       struct varshead old;
-                                       struct ast_channel *bogus = ast_dummy_channel_alloc();
-                                       if (bogus) {
-                                               memcpy(&old, ast_channel_varshead(bogus), sizeof(old));
-                                               memcpy(ast_channel_varshead(bogus), headp, sizeof(*ast_channel_varshead(bogus)));
-                                               cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
-                                               /* Don't deallocate the varshead that was passed in */
-                                               memcpy(ast_channel_varshead(bogus), &old, sizeof(*ast_channel_varshead(bogus)));
-                                               ast_channel_unref(bogus);
-                                       } else {
-                                               ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
-                                       }
-                               }
-                               ast_debug(2, "Function %s result is '%s'\n", finalvars, cp4 ? cp4 : "(null)");
-                       } else {
-                               /* Retrieve variable value */
-                               ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
-                               cp4 = ast_str_buffer(substr3);
-                       }
-                       if (cp4) {
-                               ast_str_substring(substr3, offset, offset2);
-                               ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
-                       }
-               } else if (nextexp) {
-                       /* We have an expression.  Find the start and end, and determine
-                          if we are going to have to recursively call ourselves on the
-                          contents */
-                       vars = vare = nextexp + 2;
-                       brackets = 1;
-                       needsub = 0;
-
-                       /* Find the end of it */
-                       while (brackets && *vare) {
-                               if ((vare[0] == '$') && (vare[1] == '[')) {
-                                       needsub++;
-                                       brackets++;
-                                       vare++;
-                               } else if (vare[0] == '[') {
-                                       brackets++;
-                               } else if (vare[0] == ']') {
-                                       brackets--;
-                               } else if ((vare[0] == '$') && (vare[1] == '{')) {
-                                       needsub++;
-                                       vare++;
-                               }
-                               vare++;
-                       }
-                       if (brackets)
-                               ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
-                       len = vare - vars - 1;
-
-                       /* Skip totally over expression */
-                       whereweare += (len + 3);
-
-                       /* Store variable name (and truncate) */
-                       ast_str_set_substr(&substr1, 0, vars, len);
-
-                       /* Substitute if necessary */
-                       if (needsub) {
-                               size_t my_used;
+               /* For general callbacks */
+               cb_iter = ao2_iterator_init(statecbs, 0);
+               for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+                       execute_state_callback(state_cb->change_cb,
+                               context_name,
+                               exten_name,
+                               state_cb->data,
+                               AST_HINT_UPDATE_DEVICE,
+                               hint,
+                               NULL);
+               }
+               ao2_iterator_destroy(&cb_iter);
 
-                               if (!substr2) {
-                                       substr2 = ast_str_create(16);
-                               }
-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &my_used);
-                               finalvars = ast_str_buffer(substr2);
-                       } else {
-                               finalvars = ast_str_buffer(substr1);
+               /* For extension callbacks */
+               /* extended callbacks are called when the state changed or when AST_STATE_RINGING is
+                * included. Normal callbacks are only called when the state changed.
+                */
+               cb_iter = ao2_iterator_init(hint->callbacks, 0);
+               for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+                       if (state_cb->extended && first_extended_cb_call) {
+                               /* Fill detailed device_state_info now that we know it is used by extd. callback */
+                               first_extended_cb_call = 0;
+                               get_device_state_causing_channels(device_state_info);
                        }
-
-                       if (ast_str_expr(&substr3, 0, c, finalvars)) {
-                               ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
+                       if (state_cb->extended || !same_state) {
+                               execute_state_callback(state_cb->change_cb,
+                                       context_name,
+                                       exten_name,
+                                       state_cb->data,
+                                       AST_HINT_UPDATE_DEVICE,
+                                       hint,
+                                       state_cb->extended ? device_state_info : NULL);
                        }
-                       ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
                }
+               ao2_iterator_destroy(&cb_iter);
+
+               ao2_cleanup(device_state_info);
        }
-       *used = ast_str_strlen(*buf) - orig_size;
-       ast_free(substr1);
-       ast_free(substr2);
-       ast_free(substr3);
-}
+       ast_mutex_unlock(&context_merge_lock);
 
-void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
-{
-       size_t used;
-       ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
+       ao2_iterator_destroy(dev_iter);
+       ast_free(hint_app);
+       return;
 }
 
-void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
+/*!
+ * \internal
+ * \brief Destroy the given state callback object.
+ *
+ * \param doomed State callback to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_state_cb(void *doomed)
 {
-       size_t used;
-       ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
+       struct ast_state_cb *state_cb = doomed;
+
+       if (state_cb->destroy_cb) {
+               state_cb->destroy_cb(state_cb->id, state_cb->data);
+       }
 }
 
-void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
+/*!
+ * \internal
+ * \brief Add watcher for extension states with destructor
+ */
+static int extension_state_add_destroy(const char *context, const char *exten,
+       ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
 {
-       /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
-       char *cp4 = NULL;
-       const char *whereweare, *orig_cp2 = cp2;
-       int length, offset, offset2, isfunction;
-       char *workspace = NULL;
-       char *ltmp = NULL, *var = NULL;
-       char *nextvar, *nextexp, *nextthing;
-       char *vars, *vare;
-       int pos, brackets, needsub, len;
+       struct ast_hint *hint;
+       struct ast_state_cb *state_cb;
+       struct ast_exten *e;
+       int id;
 
-       *cp2 = 0; /* just in case nothing ends up there */
-       whereweare = cp1;
-       while (!ast_strlen_zero(whereweare) && count) {
-               /* Assume we're copying the whole remaining string */
-               pos = strlen(whereweare);
-               nextvar = NULL;
-               nextexp = NULL;
-               nextthing = strchr(whereweare, '$');
-               if (nextthing) {
-                       switch (nextthing[1]) {
-                       case '{':
-                               nextvar = nextthing;
-                               pos = nextvar - whereweare;
-                               break;
-                       case '[':
-                               nextexp = nextthing;
-                               pos = nextexp - whereweare;
-                               break;
-                       default:
-                               pos = 1;
-                       }
+       /* If there's no context and extension:  add callback to statecbs list */
+       if (!context && !exten) {
+               /* Prevent multiple adds from adding the same change_cb at the same time. */
+               ao2_lock(statecbs);
+
+               /* Remove any existing change_cb. */
+               ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
+
+               /* Now insert the change_cb */
+               if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
+                       ao2_unlock(statecbs);
+                       return -1;
+               }
+               state_cb->id = 0;
+               state_cb->change_cb = change_cb;
+               state_cb->destroy_cb = destroy_cb;
+               state_cb->data = data;
+               state_cb->extended = extended;
+               ao2_link(statecbs, state_cb);
+
+               ao2_ref(state_cb, -1);
+               ao2_unlock(statecbs);
+               return 0;
+       }
+
+       if (!context || !exten)
+               return -1;
+
+       /* This callback type is for only one hint, so get the hint */
+       e = ast_hint_extension(NULL, context, exten);
+       if (!e) {
+               return -1;
+       }
+
+       /* If this is a pattern, dynamically create a new extension for this
+        * particular match.  Note that this will only happen once for each
+        * individual extension, because the pattern will no longer match first.
+        */
+       if (e->exten[0] == '_') {
+               ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
+                       e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
+                       e->registrar);
+               e = ast_hint_extension(NULL, context, exten);
+               if (!e || e->exten[0] == '_') {
+                       return -1;
                }
+       }
 
-               if (pos) {
-                       /* Can't copy more than 'count' bytes */
-                       if (pos > count)
-                               pos = count;
-
-                       /* Copy that many bytes */
-                       memcpy(cp2, whereweare, pos);
-
-                       count -= pos;
-                       cp2 += pos;
-                       whereweare += pos;
-                       *cp2 = 0;
-               }
-
-               if (nextvar) {
-                       /* We have a variable.  Find the start and end, and determine
-                          if we are going to have to recursively call ourselves on the
-                          contents */
-                       vars = vare = nextvar + 2;
-                       brackets = 1;
-                       needsub = 0;
-
-                       /* Find the end of it */
-                       while (brackets && *vare) {
-                               if ((vare[0] == '$') && (vare[1] == '{')) {
-                                       needsub++;
-                               } else if (vare[0] == '{') {
-                                       brackets++;
-                               } else if (vare[0] == '}') {
-                                       brackets--;
-                               } else if ((vare[0] == '$') && (vare[1] == '['))
-                                       needsub++;
-                               vare++;
-                       }
-                       if (brackets)
-                               ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
-                       len = vare - vars - 1;
+       /* Find the hint in the hints container */
+       ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
+       hint = ao2_find(hints, e, 0);
+       if (!hint) {
+               ao2_unlock(hints);
+               return -1;
+       }
 
-                       /* Skip totally over variable string */
-                       whereweare += (len + 3);
+       /* Now insert the callback in the callback list  */
+       if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
+               ao2_ref(hint, -1);
+               ao2_unlock(hints);
+               return -1;
+       }
+       do {
+               id = stateid++;         /* Unique ID for this callback */
+               /* Do not allow id to ever be -1 or 0. */
+       } while (id == -1 || id == 0);
+       state_cb->id = id;
+       state_cb->change_cb = change_cb;        /* Pointer to callback routine */
+       state_cb->destroy_cb = destroy_cb;
+       state_cb->data = data;          /* Data for the callback */
+       state_cb->extended = extended;
+       ao2_link(hint->callbacks, state_cb);
 
-                       if (!var)
-                               var = ast_alloca(VAR_BUF_SIZE);
+       ao2_ref(state_cb, -1);
+       ao2_ref(hint, -1);
+       ao2_unlock(hints);
 
-                       /* Store variable name (and truncate) */
-                       ast_copy_string(var, vars, len + 1);
+       return id;
+}
 
-                       /* Substitute if necessary */
-                       if (needsub) {
-                               size_t my_used;
+/*! \brief Add watcher for extension states with destructor */
+int ast_extension_state_add_destroy(const char *context, const char *exten,
+       ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
+{
+       return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
+}
 
-                               if (!ltmp) {
-                                       ltmp = ast_alloca(VAR_BUF_SIZE);
-                               }
-                               pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
-                               vars = ltmp;
-                       } else {
-                               vars = var;
-                       }
+/*! \brief Add watcher for extension states */
+int ast_extension_state_add(const char *context, const char *exten,
+       ast_state_cb_type change_cb, void *data)
+{
+       return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
+}
 
-                       if (!workspace)
-                               workspace = ast_alloca(VAR_BUF_SIZE);
-
-                       workspace[0] = '\0';
-
-                       parse_variable_name(vars, &offset, &offset2, &isfunction);
-                       if (isfunction) {
-                               /* Evaluate function */
-                               if (c || !headp)
-                                       cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
-                               else {
-                                       struct varshead old;
-                                       struct ast_channel *c = ast_dummy_channel_alloc();
-                                       if (c) {
-                                               memcpy(&old, ast_channel_varshead(c), sizeof(old));
-                                               memcpy(ast_channel_varshead(c), headp, sizeof(*ast_channel_varshead(c)));
-                                               cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
-                                               /* Don't deallocate the varshead that was passed in */
-                                               memcpy(ast_channel_varshead(c), &old, sizeof(*ast_channel_varshead(c)));
-                                               c = ast_channel_unref(c);
-                                       } else {
-                                               ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
-                                       }
-                               }
-                               ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
-                       } else {
-                               /* Retrieve variable value */
-                               pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
-                       }
-                       if (cp4) {
-                               cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
-
-                               length = strlen(cp4);
-                               if (length > count)
-                                       length = count;
-                               memcpy(cp2, cp4, length);
-                               count -= length;
-                               cp2 += length;
-                               *cp2 = 0;
-                       }
-               } else if (nextexp) {
-                       /* We have an expression.  Find the start and end, and determine
-                          if we are going to have to recursively call ourselves on the
-                          contents */
-                       vars = vare = nextexp + 2;
-                       brackets = 1;
-                       needsub = 0;
-
-                       /* Find the end of it */
-                       while (brackets && *vare) {
-                               if ((vare[0] == '$') && (vare[1] == '[')) {
-                                       needsub++;
-                                       brackets++;
-                                       vare++;
-                               } else if (vare[0] == '[') {
-                                       brackets++;
-                               } else if (vare[0] == ']') {
-                                       brackets--;
-                               } else if ((vare[0] == '$') && (vare[1] == '{')) {
-                                       needsub++;
-                                       vare++;
-                               }
-                               vare++;
-                       }
-                       if (brackets)
-                               ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
-                       len = vare - vars - 1;
+/*! \brief Add watcher for extended extension states with destructor */
+int ast_extension_state_add_destroy_extended(const char *context, const char *exten,
+       ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
+{
+       return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
+}
 
-                       /* Skip totally over expression */
-                       whereweare += (len + 3);
+/*! \brief Add watcher for extended extension states */
+int ast_extension_state_add_extended(const char *context, const char *exten,
+       ast_state_cb_type change_cb, void *data)
+{
+       return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
+}
 
-                       if (!var)
-                               var = ast_alloca(VAR_BUF_SIZE);
+/*! \brief Find Hint by callback id */
+static int find_hint_by_cb_id(void *obj, void *arg, int flags)
+{
+       struct ast_state_cb *state_cb;
+       const struct ast_hint *hint = obj;
+       int *id = arg;
 
-                       /* Store variable name (and truncate) */
-                       ast_copy_string(var, vars, len + 1);
+       if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
+               ao2_ref(state_cb, -1);
+               return CMP_MATCH | CMP_STOP;
+       }
 
-                       /* Substitute if necessary */
-                       if (needsub) {
-                               size_t my_used;
+       return 0;
+}
 
-                               if (!ltmp) {
-                                       ltmp = ast_alloca(VAR_BUF_SIZE);
-                               }
-                               pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &my_used);
-                               vars = ltmp;
-                       } else {
-                               vars = var;
-                       }
+/*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
+int ast_extension_state_del(int id, ast_state_cb_type change_cb)
+{
+       struct ast_state_cb *p_cur;
+       int ret = -1;
 
-                       length = ast_expr(vars, cp2, count, c);
+       if (!id) {      /* id == 0 is a callback without extension */
+               if (!change_cb) {
+                       return ret;
+               }
+               p_cur = ao2_find(statecbs, change_cb, OBJ_UNLINK);
+               if (p_cur) {
+                       ret = 0;
+                       ao2_ref(p_cur, -1);
+               }
+       } else { /* callback with extension, find the callback based on ID */
+               struct ast_hint *hint;
 
-                       if (length) {
-                               ast_debug(1, "Expression result is '%s'\n", cp2);
-                               count -= length;
-                               cp2 += length;
-                               *cp2 = 0;
+               ao2_lock(hints);/* Locked to hold off ast_merge_contexts_and_delete */
+               hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
+               if (hint) {
+                       p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
+                       if (p_cur) {
+                               ret = 0;
+                               ao2_ref(p_cur, -1);
                        }
+                       ao2_ref(hint, -1);
                }
+               ao2_unlock(hints);
        }
-       *used = cp2 - orig_cp2;
-}
 
-void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
-{
-       size_t used;
-       pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, &used);
+       return ret;
 }
 
-void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
+static int hint_id_cmp(void *obj, void *arg, int flags)
 {
-       size_t used;
-       pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
+       const struct ast_state_cb *cb = obj;
+       int *id = arg;
+
+       return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 /*!
- * \brief The return value depends on the action:
- *
- * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
- *     and return 0 on failure, -1 on match;
- * E_FINDLABEL maps the label to a priority, and returns
- *     the priority on success, ... XXX
- * E_SPAWN, spawn an application,
+ * \internal
+ * \brief Destroy the given hint object.
  *
- * \retval 0 on success.
- * \retval  -1 on failure.
+ * \param obj Hint to destroy.
  *
- * \note The channel is auto-serviced in this function, because doing an extension
- * match may block for a long time.  For example, if the lookup has to use a network
- * dialplan switch, such as DUNDi or IAX2, it may take a while.  However, the channel
- * auto-service code will queue up any important signalling frames to be processed
- * after this is done.
+ * \return Nothing
  */
-static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
-  const char *context, const char *exten, int priority,
-  const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
+static void destroy_hint(void *obj)
 {
-       struct ast_exten *e;
-       struct ast_app *app;
-       char *substitute = NULL;
-       int res;
-       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-       char passdata[EXT_DATA_SIZE];
-       int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
+       struct ast_hint *hint = obj;
+       int i;
 
-       ast_rdlock_contexts();
-       if (found)
-               *found = 0;
+       if (hint->callbacks) {
+               struct ast_state_cb *state_cb;
+               const char *context_name;
+               const char *exten_name;
 
-       e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
-       if (e) {
-               if (found)
-                       *found = 1;
-               if (matching_action) {
-                       ast_unlock_contexts();
-                       return -1;      /* success, we found it */
-               } else if (action == E_FINDLABEL) { /* map the label to a priority */
-                       res = e->priority;
-                       ast_unlock_contexts();
-                       return res;     /* the priority we were looking for */
-               } else {        /* spawn */
-                       if (!e->cached_app)
-                               e->cached_app = pbx_findapp(e->app);
-                       app = e->cached_app;
-                       if (ast_strlen_zero(e->data)) {
-                               *passdata = '\0';
-                       } else {
-                               const char *tmp;
-                               if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
-                                       /* no variables to substitute, copy on through */
-                                       ast_copy_string(passdata, e->data, sizeof(passdata));
-                               } else {
-                                       /* save e->data on stack for later processing after lock released */
-                                       substitute = ast_strdupa(e->data);
-                               }
-                       }
-                       ast_unlock_contexts();
-                       if (!app) {
-                               ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
-                               return -1;
-                       }
-                       if (ast_channel_context(c) != context)
-                               ast_channel_context_set(c, context);
-                       if (ast_channel_exten(c) != exten)
-                               ast_channel_exten_set(c, exten);
-                       ast_channel_priority_set(c, priority);
-                       if (substitute) {
-                               pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
-                       }
-                       ast_debug(1, "Launching '%s'\n", app->name);
-                       if (VERBOSITY_ATLEAST(3)) {
-                               ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
-                                       exten, context, priority,
-                                       COLORIZE(COLOR_BRCYAN, 0, app->name),
-                                       COLORIZE(COLOR_BRMAGENTA, 0, ast_channel_name(c)),
-                                       COLORIZE(COLOR_BRMAGENTA, 0, passdata),
-                                       "in new stack");
-                       }
-                       return pbx_exec(c, app, passdata);      /* 0 on success, -1 on failure */
-               }
-       } else if (q.swo) {     /* not found here, but in another switch */
-               if (found)
-                       *found = 1;
-               ast_unlock_contexts();
-               if (matching_action) {
-                       return -1;
+               if (hint->exten) {
+                       context_name = ast_get_context_name(ast_get_extension_context(hint->exten));
+                       exten_name = ast_get_extension_name(hint->exten);
+                       hint->exten = NULL;
                } else {
-                       if (!q.swo->exec) {
-                               ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
-                               res = -1;
-                       }
-                       return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
+                       /* The extension has already been destroyed */
+                       context_name = hint->context_name;
+                       exten_name = hint->exten_name;
                }
-       } else {        /* not found anywhere, see what happened */
-               ast_unlock_contexts();
-               /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
-               switch (q.status) {
-               case STATUS_NO_CONTEXT:
-                       if (!matching_action && !combined_find_spawn)
-                               ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
-                       break;
-               case STATUS_NO_EXTENSION:
-                       if (!matching_action && !combined_find_spawn)
-                               ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
-                       break;
-               case STATUS_NO_PRIORITY:
-                       if (!matching_action && !combined_find_spawn)
-                               ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
-                       break;
-               case STATUS_NO_LABEL:
-                       if (context && !combined_find_spawn)
-                               ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
-                       break;
-               default:
-                       ast_debug(1, "Shouldn't happen!\n");
+               hint->laststate = AST_EXTENSION_DEACTIVATED;
+               while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
+                       /* Notify with -1 and remove all callbacks */
+                       execute_state_callback(state_cb->change_cb,
+                               context_name,
+                               exten_name,
+                               state_cb->data,
+                               AST_HINT_UPDATE_DEVICE,
+                               hint,
+                               NULL);
+                       ao2_ref(state_cb, -1);
                }
-
-               return (matching_action) ? 0 : -1;
+               ao2_ref(hint->callbacks, -1);
        }
-}
-
-/*! \brief Find hint for given extension in context */
-static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
-{
-       struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
-       return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
-}
-
-static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
-{
-       struct ast_exten *e;
-       ast_rdlock_contexts();
-       e = ast_hint_extension_nolock(c, context, exten);
-       ast_unlock_contexts();
-       return e;
-}
 
-enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
-{
-       switch (devstate) {
-       case AST_DEVICE_ONHOLD:
-               return AST_EXTENSION_ONHOLD;
-       case AST_DEVICE_BUSY:
-               return AST_EXTENSION_BUSY;
-       case AST_DEVICE_UNKNOWN:
-               return AST_EXTENSION_NOT_INUSE;
-       case AST_DEVICE_UNAVAILABLE:
-       case AST_DEVICE_INVALID:
-               return AST_EXTENSION_UNAVAILABLE;
-       case AST_DEVICE_RINGINUSE:
-               return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
-       case AST_DEVICE_RINGING:
-               return AST_EXTENSION_RINGING;
-       case AST_DEVICE_INUSE:
-               return AST_EXTENSION_INUSE;
-       case AST_DEVICE_NOT_INUSE:
-               return AST_EXTENSION_NOT_INUSE;
-       case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
-               break;
+       for (i = 0; i < AST_VECTOR_SIZE(&hint->devices); i++) {
+               char *device = AST_VECTOR_GET(&hint->devices, i);
+               ast_free(device);
        }
-
-       return AST_EXTENSION_NOT_INUSE;
+       AST_VECTOR_FREE(&hint->devices);
+       ast_free(hint->last_presence_subtype);
+       ast_free(hint->last_presence_message);
 }
 
-/*!
- * \internal
- * \brief Parse out the presence portion of the hint string
- */
-static char *parse_hint_presence(struct ast_str *hint_args)
+/*! \brief Remove hint from extension */
+static int ast_remove_hint(struct ast_exten *e)
 {
-       char *copy = ast_strdupa(ast_str_buffer(hint_args));
-       char *tmp = "";
+       /* Cleanup the Notifys if hint is removed */
+       struct ast_hint *hint;
 
-       if ((tmp = strrchr(copy, ','))) {
-               *tmp = '\0';
-               tmp++;
-       } else {
-               return NULL;
+       if (!e) {
+               return -1;
        }
-       ast_str_set(&hint_args, 0, "%s", tmp);
-       return ast_str_buffer(hint_args);
-}
-
-/*!
- * \internal
- * \brief Parse out the device portion of the hint string
- */
-static char *parse_hint_device(struct ast_str *hint_args)
-{
-       char *copy = ast_strdupa(ast_str_buffer(hint_args));
-       char *tmp;
 
-       if ((tmp = strrchr(copy, ','))) {
-               *tmp = '\0';
+       hint = ao2_find(hints, e, OBJ_UNLINK);
+       if (!hint) {
+               return -1;
        }
 
-       ast_str_set(&hint_args, 0, "%s", copy);
-       return ast_str_buffer(hint_args);
-}
+       remove_hintdevice(hint);
 
-static void device_state_info_dt(void *obj)
-{
-       struct ast_device_state_info *info = obj;
+       /*
+        * The extension is being destroyed so we must save some
+        * information to notify that the extension is deactivated.
+        */
+       ao2_lock(hint);
+       ast_copy_string(hint->context_name,
+               ast_get_context_name(ast_get_extension_context(hint->exten)),
+               sizeof(hint->context_name));
+       ast_copy_string(hint->exten_name, ast_get_extension_name(hint->exten),
+               sizeof(hint->exten_name));
+       hint->exten = NULL;
+       ao2_unlock(hint);
 
-       ao2_cleanup(info->causing_channel);
-}
+       ao2_ref(hint, -1);
 
-static struct ao2_container *alloc_device_state_info(void)
-{
-       return ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
+       return 0;
 }
 
-static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
+/*! \brief Add hint to hint list, check initial extension state */
+static int ast_add_hint(struct ast_exten *e)
 {
-       char *cur;
-       char *rest;
-       struct ast_devstate_aggregate agg;
-
-       /* One or more devices separated with a & character */
-       rest = parse_hint_device(hint_app);
-
-       ast_devstate_aggregate_init(&agg);
-       while ((cur = strsep(&rest, "&"))) {
-               enum ast_device_state state = ast_device_state(cur);
+       struct ast_hint *hint_new;
+       struct ast_hint *hint_found;
+       char *message = NULL;
+       char *subtype = NULL;
+       int presence_state;
 
-               ast_devstate_aggregate_add(&agg, state);
-               if (device_state_info) {
-                       struct ast_device_state_info *obj;
+       if (!e) {
+               return -1;
+       }
 
-                       obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
-                       /* if failed we cannot add this device */
-                       if (obj) {
-                               obj->device_state = state;
-                               strcpy(obj->device_name, cur);
-                               ao2_link(device_state_info, obj);
-                               ao2_ref(obj, -1);
-                       }
-               }
+       /*
+        * We must create the hint we wish to add before determining if
+        * it is already in the hints container to avoid possible
+        * deadlock when getting the current extension state.
+        */
+       hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
+       if (!hint_new) {
+               return -1;
        }
+       AST_VECTOR_INIT(&hint_new->devices, 8);
 
-       return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
-}
-
-/*! \brief Check state of extension by using hints */
-static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
-{
-       struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
-
-       if (!e || !hint_app) {
+       /* Initialize new hint. */
+       hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
+       if (!hint_new->callbacks) {
+               ao2_ref(hint_new, -1);
                return -1;
        }
+       hint_new->exten = e;
+       if (strstr(e->app, "${") && e->exten[0] == '_') {
+               /* The hint is dynamic and hasn't been evaluted yet */
+               hint_new->laststate = AST_DEVICE_INVALID;
+               hint_new->last_presence_state = AST_PRESENCE_INVALID;
+       } else {
+               hint_new->laststate = ast_extension_state2(e, NULL);
+               if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
+                       hint_new->last_presence_state = presence_state;
+                       hint_new->last_presence_subtype = subtype;
+                       hint_new->last_presence_message = message;
+                       message = subtype = NULL;
+               }
+       }
 
-       ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
-       return ast_extension_state3(hint_app, device_state_info);
-}
-
-/*! \brief Return extension_state as string */
-const char *ast_extension_state2str(int extension_state)
-{
-       int i;
+       /* Prevent multiple add hints from adding the same hint at the same time. */
+       ao2_lock(hints);
 
-       for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
-               if (extension_states[i].extension_state == extension_state)
-                       return extension_states[i].text;
+       /* Search if hint exists, do nothing */
+       hint_found = ao2_find(hints, e, 0);
+       if (hint_found) {
+               ao2_ref(hint_found, -1);
+               ao2_unlock(hints);
+               ao2_ref(hint_new, -1);
+               ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
+                       ast_get_extension_name(e), ast_get_extension_app(e));
+               return -1;
        }
-       return "Unknown";
-}
-
-/*!
- * \internal
- * \brief Check extension state for an extension by using hint
- */
-static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
-       struct ao2_container *device_state_info)
-{
-       struct ast_exten *e;
 
-       if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
-               return -1;                   /* No hint, return -1 */
+       /* Add new hint to the hints container */
+       ast_debug(2, "HINTS: Adding hint %s: %s\n",
+               ast_get_extension_name(e), ast_get_extension_app(e));
+       ao2_link(hints, hint_new);
+       if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
+               ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
+                       ast_get_extension_name(e),
+                       ast_get_context_name(ast_get_extension_context(e)));
        }
 
-       if (e->exten[0] == '_') {
-               /* Create this hint on-the-fly */
-               ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
-                       e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
-                       e->registrar);
-               if (!(e = ast_hint_extension(c, context, exten))) {
-                       /* Improbable, but not impossible */
-                       return -1;
+       /* if not dynamic */
+       if (!(strstr(e->app, "${") && e->exten[0] == '_')) {
+               struct ast_state_cb *state_cb;
+               struct ao2_iterator cb_iter;
+
+               /* For general callbacks */
+               cb_iter = ao2_iterator_init(statecbs, 0);
+               for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+                       execute_state_callback(state_cb->change_cb,
+                                       ast_get_context_name(ast_get_extension_context(e)),
+                                       ast_get_extension_name(e),
+                                       state_cb->data,
+                                       AST_HINT_UPDATE_DEVICE,
+                                       hint_new,
+                                       NULL);
                }
+               ao2_iterator_destroy(&cb_iter);
        }
+       ao2_unlock(hints);
+       ao2_ref(hint_new, -1);
 
-       return ast_extension_state2(e, device_state_info);  /* Check all devices in the hint */
-}
-
-/*! \brief Check extension state for an extension by using hint */
-int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
-{
-       return internal_extension_state_extended(c, context, exten, NULL);
+       return 0;
 }
 
-/*! \brief Check extended extension state for an extension by using hint */
-int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
-       struct ao2_container **device_state_info)
+/*! \brief Change hint for an extension */
+static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
 {
-       struct ao2_container *container = NULL;
-       int ret;
-
-       if (device_state_info) {
-               container = alloc_device_state_info();
-       }
+       struct ast_str *hint_app;
+       struct ast_hint *hint;
+       int previous_device_state;
+       char *previous_message = NULL;
+       char *message = NULL;
+       char *previous_subtype = NULL;
+       char *subtype = NULL;
+       int previous_presence_state;
+       int presence_state;
+       int presence_state_changed = 0;
 
-       ret = internal_extension_state_extended(c, context, exten, container);
-       if (ret < 0 && container) {
-               ao2_ref(container, -1);
-               container = NULL;
+       if (!oe || !ne) {
+               return -1;
        }
 
-       if (device_state_info) {
-               get_device_state_causing_channels(container);
-               *device_state_info = container;
+       hint_app = ast_str_create(1024);
+       if (!hint_app) {
+               return -1;
        }
 
-       return ret;
-}
-
-static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
-{
-       struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
-       char *presence_provider;
-       const char *app;
+       ast_mutex_lock(&context_merge_lock); /* Hold off ast_merge_contexts_and_delete and state changes */
 
-       if (!e || !hint_app) {
-               return -1;
-       }
+       ao2_lock(hints);/* Locked to hold off others while we move the hint around. */
 
-       app = ast_get_extension_app(e);
-       if (ast_strlen_zero(app)) {
+       /*
+        * Unlink the hint from the hints container as the extension
+        * name (which is the hash value) could change.
+        */
+       hint = ao2_find(hints, oe, OBJ_UNLINK);
+       if (!hint) {
+               ao2_unlock(hints);
+               ast_mutex_unlock(&context_merge_lock);
+               ast_free(hint_app);
                return -1;
        }
 
-       ast_str_set(&hint_app, 0, "%s", app);
-       presence_provider = parse_hint_presence(hint_app);
+       remove_hintdevice(hint);
 
-       if (ast_strlen_zero(presence_provider)) {
-               /* No presence string in the hint */
-               return 0;
-       }
+       /* Update the hint and put it back in the hints container. */
+       ao2_lock(hint);
+       hint->exten = ne;
 
-       return ast_presence_state(presence_provider, subtype, message);
-}
+       /* Store the previous states so we know whether we need to notify state callbacks */
+       previous_device_state = hint->laststate;
+       previous_presence_state = hint->last_presence_state;
+       previous_message = hint->last_presence_message;
+       previous_subtype = hint->last_presence_subtype;
 
-int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
-{
-       struct ast_exten *e;
+       /* Update the saved device and presence state with the new extension */
+       hint->laststate = ast_extension_state2(ne, NULL);
+       hint->last_presence_state = AST_PRESENCE_INVALID;
+       hint->last_presence_subtype = NULL;
+       hint->last_presence_message = NULL;
 
-       if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
-               return -1;                   /* No hint, return -1 */
+       presence_state = extension_presence_state_helper(ne, &subtype, &message);
+       if (presence_state > 0) {
+               hint->last_presence_state = presence_state;
+               hint->last_presence_subtype = subtype;
+               hint->last_presence_message = message;
        }
 
-       if (e->exten[0] == '_') {
-               /* Create this hint on-the-fly */
-               ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
-                       e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
-                       e->registrar);
-               if (!(e = ast_hint_extension(c, context, exten))) {
-                       /* Improbable, but not impossible */
-                       return -1;
-               }
+       ao2_unlock(hint);
+
+       ao2_link(hints, hint);
+       if (add_hintdevice(hint, ast_get_extension_app(ne))) {
+               ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
+                       ast_get_extension_name(ne),
+                       ast_get_context_name(ast_get_extension_context(ne)));
        }
 
-       return extension_presence_state_helper(e, subtype, message);
-}
+       ao2_unlock(hints);
 
-static int execute_state_callback(ast_state_cb_type cb,
-       const char *context,
-       const char *exten,
-       void *data,
-       enum ast_state_cb_update_reason reason,
-       struct ast_hint *hint,
-       struct ao2_container *device_state_info)
-{
-       int res = 0;
-       struct ast_state_cb_info info = { 0, };
+       /* Locking for state callbacks is respected here and only the context_merge_lock lock is
+        * held during the state callback invocation. This will stop the normal state callback
+        * thread from being able to handle incoming state changes if they occur.
+        */
 
-       info.reason = reason;
+       /* Determine if presence state has changed due to the change of the hint extension */
+       if ((hint->last_presence_state != previous_presence_state) ||
+               strcmp(S_OR(hint->last_presence_subtype, ""), S_OR(previous_subtype, "")) ||
+               strcmp(S_OR(hint->last_presence_message, ""), S_OR(previous_message, ""))) {
+               presence_state_changed = 1;
+       }
 
-       /* Copy over current hint data */
-       if (hint) {
-               ao2_lock(hint);
-               info.exten_state = hint->laststate;
-               info.device_state_info = device_state_info;
-               info.presence_state = hint->last_presence_state;
-               if (!(ast_strlen_zero(hint->last_presence_subtype))) {
-                       info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
-               } else {
-                       info.presence_subtype = "";
+       /* Notify any existing state callbacks if the device or presence state has changed */
+       if ((hint->laststate != previous_device_state) || presence_state_changed) {
+               struct ao2_iterator cb_iter;
+               struct ast_state_cb *state_cb;
+               struct ao2_container *device_state_info;
+               int first_extended_cb_call = 1;
+
+               /* For general callbacks */
+               cb_iter = ao2_iterator_init(statecbs, 0);
+               for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+                       /* Unlike the normal state callbacks since something has explicitly provided us this extension
+                        * it will remain valid and unchanged for the lifetime of this function invocation.
+                        */
+                       if (hint->laststate != previous_device_state) {
+                               execute_state_callback(state_cb->change_cb,
+