[server] / trunk / clients / asterisk / chan_woomera / chan_woomera.c Repository:
ViewVC logotype

View of /trunk/clients/asterisk/chan_woomera/chan_woomera.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 690 - (download) (annotate)
Thu Apr 22 11:05:25 2010 UTC (3 years, 1 month ago) by amartin
File size: 212442 byte(s)
Fix in clone_woomera_profile
    1 /*
    2  * Asterisk -- A telephony toolkit for Linux.
    3  *
    4  * Woomera Channel Driver
    5  *
    6  * Copyright (C) 05-09
    7  *             Nenad Corbic
    8  *             David Yat Sin
    9  *             Antony Martin (Dialogic Corp)
   10  *             John Tarlton  (Dialogic Corp)
   11  *             Anthony Minessale II
   12  *
   13  * Nenad Corbic         <ncorbic@sangoma.com>
   14  * David Yat Sin        <davidy@sangoma.com>
   15  * Antony Martin        <antony.martin@dialogic.com>
   16  * John Tarlton         <john.tarlton@dialogic.com>
   17  * Anthony Minessale II <anthmct@yahoo.com>
   18  *
   19  * This program is free software, distributed under the terms of
   20  * the GNU General Public License
   21  * =============================================
   22  *
   23  * v1.59 Antony Martin <antony.martin@dialogic.com>
   24  * Apr 22 2010
   25  *     Fix in clone_woomera_profile.
   26  *
   27  * v1.58 John Tarlton <john.tarlton@dialogic.com>
   28  * Mar 19 2010
   29  *     New app WoomeraStop currently allows WoomeraBackground
   30  *
   31  * v1.57 John Tarlton <john.tarlton@dialogic.com>
   32  * Nov 4 2009
   33  *     Ensure rx gain processing is done on voice frames only.
   34  *
   35  * v1.56 Antony Martin <antony.martin@dialogic.com>
   36  * Sep 30 2009
   37  *     Added Woomera play and record functionality.
   38  *     Native bridging support.
   39  *
   40  * v1.55 Antony Martin <antony.martin@dialogic.com>
   41  * Jul 09 2009
   42  *     Changes for Asterisk 1.6.1 compatibility.
   43  *
   44  * v1.54 John Tarlton <john.tarlton@dialogic.com>
   45  * Jun 12 2009
   46  *     Set dnid channel var on incoming call.
   47  *
   48  * v1.53 John Tarlton <john.tarlton@dialogic.com>
   49  * Jun 11 2009
   50  *     Parse profile name from dial string, falling back to 'default'
   51  *
   52  * v1.52 John Tarlton <john.tarlton@dialogic.com>
   53  * May 28 2009
   54  *     Check for dsp when processing the DTMF header of a MEDIA message.
   55  *
   56  * v1.51 Antony Martin <antony.martin@dialogic.com>
   57  * Apr 30 2009
   58  *     Added RTP Audio
   59  *
   60  * v1.50 Nenad Corbic <ncorbic@sangoma.com>
   61  * Apr 24 2009
   62  *  Bug fix on write socket. Check that write woomera socket failed.
   63  *  This update prevents socket warning messages on call congestion.
   64  *
   65  * v1.49 Nenad Corbic <ncorbic@sangoma.com>
   66  * Apr 08 2009
   67  *  Bug fix on transfer. The owner was not
   68  *  properly updated causing unpredictable behaviour.
   69  *
   70  * v1.48 Nenad Corbic <ncorbic@sangoma.com>
   71  * Apr 05 2009
   72  *  Updated locking on pbx_start
   73  *
   74  * v1.47 Nenad Corbic <ncorbic@sangoma.com>
   75  * Apr 03 2009
   76  *      Added BLOCKER sanity check.
   77  *
   78  * v1.46 Nenad Corbic <ncorbic@sangoma.com>
   79  * Mar 29 2009
   80  *  Added hup_pending stat to call_status
   81  *  Let tech_hangup destroy softhungup channel
   82  *
   83  * v1.45 Nenad Corbic <ncorbic@sangoma.com>
   84  * Mar 27 2009
   85  *  Major updates on channel locking.
   86  *  This update fixes potential crashing issues
   87  *  under heavy load. Stress tested in 500+ call
   88  *      environment.
   89  *
   90  * v1.44 Nenad Corbic <ncorbic@sangoma.com>
   91  * Mar 55 2009
   92  *  Updated woomera channel locking using
   93  *      DEADLOCK_AVOIDANCE. Fixed RDNIS transmission issue.
   94  *
   95  * v1.43 David Yat Sin <dyatsin@sangoma.com>
   96  * Mar 01 2009
   97  *  Fix to support Callweaver svn trunk
   98  *
   99  * v1.42 David Yat Sin <dyatsin@sangoma.com>
  100  * Feb 25 2009
  101  *  Fix to support Callweaver svn trunk
  102  *
  103  * v1.41 Nenad Corbic <ncorbic@sangoma.com>
  104  * Jan 29 2008
  105  *  Bug introduced in 1.40 if WOOMERA uil1p parameter
  106  *  was not there transcoding was misconfigued.
  107  *
  108  * v1.40 Nenad Corbic <ncorbic@sangoma.com>
  109  * Jan 26 2008
  110  *  Call Bearer Capability Feature
  111  *  Updated for Callweaver
  112  *
  113  * v1.39 David Yat Sin <dyatsin@sangoma.com>
  114  * Dec 19 2008
  115  *  Support for Asterisk 1.6
  116  *
  117  * v1.38 David Yat Sin <dyatsin@sangoma.com>
  118  * Dec 05 2008
  119  *  Support for fax_detect using Asterisk software DSP
  120  *
  121  * v1.37 Nenad Corbic <ncorbic@sangoma.com>
  122  * Nov 26 2008
  123  *  Bug Fix: tech_read try again now checks for hangup
  124  *
  125  * v1.36 David Yat Sin <dyatsin@sangoma.com>
  126  * Oct 14 2008
  127  *  Bug Fix: Call hangup on call park
  128  *
  129  * v1.35 Nenad Corbic <ncorbic@sangoma.com>
  130  * Jul 23 2008
  131  *  Bug Fix: Check for cid_name.
  132  *
  133  * v1.34 Nenad Corbic <ncorbic@sangoma.com>
  134  * Jul 23 2008
  135  *  Added udp tagging and rx/tx sync options for
  136  *  voice streams debugging. Not for production.
  137  *
  138  * v1.33 Nenad Corbic <ncorbic@sangoma.com>
  139  * Jul 18 2008
  140  *  Added UDP Sequencing to check for dropped frames
  141  *  Should only be used for debugging.
  142  *
  143  * v1.32 David Yat Sin <davidy@sangoma.com>
  144  * Jun 3 2008
  145  *  Updated for callweaver v1.2.0
  146  *
  147  * v1.31 Nenad Corbic <ncorbic@sangoma.com>
  148  * v1.30 Nenad Corbic <ncorbic@sangoma.com>
  149  * Jun 2 2008
  150  *  Added AST_CTONROL_RING event on outgoing call.
  151  *  Updated for CallWeaver 1.2 SVN
  152  *
  153  * v1.29 David Yat Sin <davidy@sangoma.com>
  154  * Apr 30 2008
  155  *  Added AST_CONTROL_SRCUPDATE in tech_indicate
  156  *
  157  * v1.29 David Yat Sin <davidy@sangoma.com>
  158  * April 29 2008
  159  *  Support for HW DTMF
  160  *
  161  * v1.28 David Yat Sin <davidy@sangoma.com>
  162  * Apr 29 2008
  163  *  Fix for compilation issues with Callweaver v1.99
  164  *
  165  * v1.27 David Yat Sin <davidy@sangoma.com>
  166  * Feb 13 2008
  167  *  Fix for ast_channel type not defined on
  168  *  outgoing calls, causing PHP agi scripts
  169  *  to fail
  170  *
  171  * v1.26 Nenad Corbic <ncorbic@sangoma.com>
  172  * Feb 13 2008
  173  *  Compilation Update for callweaver 1.2-rc5
  174  *
  175  * v1.25 Nenad Corbic <ncorbic@sangoma.com>
  176  * Feb 06 2008
  177  *  Bug fix in woomera message declaration
  178  *      Possible memory overflow
  179  *
  180  * v1.24 Nenad Corbic <ncorbic@sangoma.com>
  181  * Jan 23 2008
  182  *  Removed LISTEN on every woomera channel. Listen
  183  *      only on master. Fixed jitterbuffer support on AST1.4
  184  *
  185  * v1.23 Nenad Corbic <ncorbic@sangoma.com>
  186  * Jan 22 2008
  187  *  Implemented Music on Hold.
  188  *
  189  * v1.22 David Yat Sin <davidy@sangoma.com>
  190  * Jan 11 2008
  191  *  rxgain and txgain configuration parameters
  192  *  are ignored if coding is not specified in
  193  *  woomera.conf
  194  *
  195  * v1.21 David Yat Sin <davidy@sangoma.com>
  196  * Dec 27 2007
  197  *  Support for language
  198  *
  199  * v1.20 David Yat Sin <davidy@sangoma.com>
  200  * Dec 20 2007
  201  *   Support for call confirmation
  202  *   Support for default context
  203  *
  204  * v1.19 Nenad Corbic <ncorbic@sangoma.com>
  205  * Nov 30 2007
  206  *   Updated for latest CallWeaver
  207  *   Updated smgversion update on master socket
  208  *       restart.
  209  *
  210  * v1.18 Nenad Corbic <ncorbic@sangoma.com>
  211  *   Updated Channel-Name on outbound call
  212  *       Check queued events on ABORT
  213  *       Major Unit Testing done
  214  *       Ability to change chan name from Makefile
  215  *
  216  * v1.17 Nenad Corbic <ncorbic@sangoma.com>
  217  *   Updates for Asterisk 1.4
  218  *   Updated the release causes
  219  *   Updated for tech_indication
  220  *
  221  * v1.16 Nenad Corbic <ncorbic@sangoma.com>
  222  *   Added support for Asterisk 1.4
  223  *   Updated support for Callweaver
  224  *
  225  * v1.15 Nenad Corbic <ncorbic@sangoma.com>
  226  *   Added PRI_CAUSE and Q931-Cause-Code
  227  *   in woomera protocol.
  228  *
  229  * v1.14 Nenad Corbic <ncorbic@sangoma.com>
  230  *   Updated for session support
  231  *
  232  * v1.13 Nenad Corbic <ncorbic@sangoma.com>
  233  *   Added CallWeaver Support
  234  *   |->(thanks to Andre Schwaller)
  235  *   Updated codec negotiation for
  236  *   mutliple profiles.
  237  *
  238  * v1.12 Nenad Corbic <ncorbic@sangoma.com>
  239  *   Updated DTMF locking
  240  *
  241  * v1.11 Nenad Corbic <ncorbic@sangoma.com>
  242  *       Updated multiple profiles
  243  *       Updated Dialect for OPAL Woomera
  244  *       Added call logging/debugging
  245  *
  246  * v1.10 Nenad Corbic <ncorbic@sangoma.com>
  247  *       Bug fix in incoming hangup
  248  *
  249  * v1.9 Nenad Corbic <ncorbic@sangoma.com>
  250  *  Fixed remote asterisk/woomera
  251  *      setup.
  252  *
  253  * v1.8 Nenad Corbic <ncorbic@sangoma.com>
  254  *  Added Woomera OPAL dialect.
  255  *      Code cleanup.
  256  *  Added cli call_status
  257  *
  258  * v1.7 Nenad Corbic <ncorbic@sangoma.com>
  259  *  Added smgdebug to enable smg debugging
  260  *  Added rdnis
  261  *
  262  * v1.6 Nenad Corbic <ncorbic@sangoma.com>
  263  *      Added incoming trunk group context
  264  *      The trunk number will be added to the
  265  *      profile context name.
  266  *      Added presentation feature.
  267  *
  268  * v1.5 Nenad Corbic <ncorbic@sangoma.com>
  269  *      Use only ALAW and MLAW not SLIN.
  270  *      This reduces the load quite a bit.
  271  *      Autodetect Format from HELLO Message.
  272  *      RxTx Gain supported in woomera.conf as well
  273  *      from CLI.
  274  */
  275 
  276 /*!
  277  * \file        chan_woomera.c
  278  * \brief       Woomera Channel driver for Asterisk
  279  */
  280 
  281 #if defined(CALLWEAVER) && defined(HAVE_CONFIG_H)
  282 #include "confdefs.h"
  283 #endif
  284 
  285 #include <stdio.h>
  286 #include <string.h>
  287 #include <stdlib.h>
  288 #include <sys/types.h>
  289 #include <sys/socket.h>
  290 #include <netinet/in.h>
  291 #include <arpa/inet.h>
  292 #include <netdb.h>
  293 #include <stdio.h>
  294 #include <unistd.h>
  295 #include <fcntl.h>
  296 #include <signal.h>
  297 #include <math.h>
  298 #include <netinet/tcp.h>
  299 
  300 
  301 #ifndef CALLWEAVER
  302 
  303 
  304 #include "asterisk.h"
  305 #include "asterisk/sched.h"
  306 #include "asterisk/astobj.h"
  307 #include "asterisk/lock.h"
  308 #if defined(AST16)
  309 #include "asterisk/linkedlists.h"
  310 #include "asterisk/channel.h"
  311 #endif
  312 #if !defined (AST14) && !defined (AST16)
  313 #include "asterisk/options.h"
  314 #endif
  315 #include "asterisk/manager.h"
  316 #include "asterisk/pbx.h"
  317 #include "asterisk/cli.h"
  318 #include "asterisk/logger.h"
  319 #include "asterisk/frame.h"
  320 #include "asterisk/config.h"
  321 #include "asterisk/module.h"
  322 #include "asterisk/lock.h"
  323 #include "asterisk/translate.h"
  324 #include "asterisk/causes.h"
  325 #include "asterisk/dsp.h"
  326 #include "asterisk/musiconhold.h"
  327 #include "asterisk/transcap.h"
  328 #include "asterisk/sched.h"
  329 #include "asterisk/io.h"
  330 #include "asterisk/rtp.h"
  331 
  332 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.55 $")
  333 
  334 #else
  335 
  336 #include "callweaver.h"
  337 #include "callweaver/sched.h"
  338 #ifdef CALLWEAVER_CWOBJ
  339 #include "callweaver/cwobj.h"
  340 #else
  341 #include "callweaver/astobj.h"
  342 #endif
  343 #include "callweaver/lock.h"
  344 #include "callweaver/manager.h"
  345 #include "callweaver/options.h"
  346 #include "callweaver/channel.h"
  347 #include "callweaver/pbx.h"
  348 #include "callweaver/cli.h"
  349 #include "callweaver/logger.h"
  350 #include "callweaver/frame.h"
  351 #include "callweaver/config.h"
  352 #include "callweaver/module.h"
  353 #include "callweaver/lock.h"
  354 #include "callweaver/translate.h"
  355 #include "callweaver/causes.h"
  356 #include "callweaver/dsp.h"
  357 #include "callweaver/transcap.h"
  358 #include "callweaver.h"
  359 #include "confdefs.h"
  360 
  361 
  362 #ifdef CALLWEAVER_CWOBJ
  363 #define ASTOBJ_COMPONENTS                   CWOBJ_COMPONENTS
  364 #define ASTOBJ_CONTAINER_INIT               CWOBJ_CONTAINER_INIT
  365 #define ASTOBJ_CONTAINER_COMPONENTS         CWOBJ_CONTAINER_COMPONENTS
  366 #define ASTOBJ_CONTAINER_DESTROY            CWOBJ_CONTAINER_DESTROY
  367 #define ASTOBJ_CONTAINER_DESTROYALL         CWOBJ_CONTAINER_DESTROYALL
  368 #define ASTOBJ_UNLOCK                       CWOBJ_UNLOCK
  369 #define ASTOBJ_RDLOCK                       CWOBJ_RDLOCK
  370 #define ASTOBJ_CONTAINER_UNLINK             CWOBJ_CONTAINER_UNLINK
  371 #define ASTOBJ_CONTAINER_TRAVERSE           CWOBJ_CONTAINER_TRAVERSE
  372 #define ASTOBJ_CONTAINER_WRLOCK             CWOBJ_CONTAINER_WRLOCK
  373 #define ASTOBJ_CONTAINER_UNLOCK             CWOBJ_CONTAINER_UNLOCK
  374 #define ASTOBJ_CONTAINER_FIND               CWOBJ_CONTAINER_FIND
  375 #define ASTOBJ_CONTAINER_LINK               CWOBJ_CONTAINER_LINK
  376 #endif
  377 
  378 
  379 #if defined (CW_CONTROL_RINGING)
  380 #define CALLWEAVER_19 1
  381 #endif
  382 
  383 CALLWEAVER_FILE_VERSION(__FILE__, "$Revision: 1.55 $")
  384 
  385 #if defined(DSP_FEATURE_FAX_CNG_DETECT)
  386 #undef DSP_FEATURE_FAX_DETECT
  387 #define DSP_FEATURE_FAX_DETECT              DSP_FEATURE_FAX_CNG_DETECT
  388 #endif
  389 
  390 #if !defined(macrocontext)
  391 #undef macrocontext
  392 #define macrocontext                        proc_context
  393 #endif
  394 
  395 #if !defined(ast_tv)
  396 #undef ast_tv
  397 #define ast_tv                              opbx_tv
  398 #endif
  399 
  400 /* CALLWEAVER v1.9 and later */
  401 #if defined (CALLWEAVER_19)
  402 #define ast_transfercapability2str          cw_transfercapability2str
  403 #define ast_config                          cw_config
  404 #define AST_CONTROL_RINGING                 CW_CONTROL_RINGING
  405 #define AST_CONTROL_BUSY                    CW_CONTROL_BUSY
  406 #define AST_CONTROL_CONGESTION              CW_CONTROL_CONGESTION
  407 #define AST_CONTROL_PROCEEDING              CW_CONTROL_PROCEEDING
  408 #define AST_CONTROL_PROGRESS                CW_CONTROL_PROGRESS
  409 #define AST_CONTROL_HOLD                    CW_CONTROL_HOLD
  410 #define AST_CONTROL_UNHOLD                  CW_CONTROL_UNHOLD
  411 #define AST_CONTROL_VIDUPDATE               CW_CONTROL_VIDUPDATE
  412 
  413 #define AST_TRANS_CAP_SPEECH                CW_TRANS_CAP_SPEECH
  414 #define AST_TRANS_CAP_3_1K_AUDIO            CW_TRANS_CAP_3_1K_AUDIO
  415 #define AST_TRANS_CAP_DIGITAL               CW_TRANS_CAP_DIGITAL
  416 #define AST_TRANS_CAP_RESTRICTED_DIGITAL    CW_TRANS_CAP_RESTRICTED_DIGITAL
  417 #define AST_TRANS_CAP_DIGITAL_W_TONES       CW_TRANS_CAP_DIGITAL_W_TONES
  418 #define AST_TRANS_CAP_VIDEO                 CW_TRANS_CAP_VIDEO
  419 
  420 #define AST_FORMAT_ADPCM                    CW_FORMAT_DVI_ADPCM
  421 
  422 #ifndef LOG_NOTICE
  423 #define LOG_NOTICE                          CW_LOG_NOTICE
  424 #endif
  425 
  426 #ifndef LOG_DEBUG
  427 #define LOG_DEBUG                           CW_LOG_DEBUG
  428 #endif
  429 
  430 #ifndef LOG_ERROR
  431 #define LOG_ERROR                           CW_LOG_ERROR
  432 #endif
  433 
  434 #ifndef LOG_WARNING
  435 #define LOG_WARNING                         CW_LOG_WARNING
  436 #endif
  437 
  438 #define AST_FORMAT_SLINEAR                  CW_FORMAT_SLINEAR
  439 #define AST_FORMAT_ULAW                     CW_FORMAT_ULAW
  440 #define AST_FORMAT_ALAW                     CW_FORMAT_ALAW
  441 #define ast_mutex_t                         cw_mutex_t
  442 #define ast_frame                           cw_frame
  443 #define ast_verbose                         cw_verbose
  444 #define AST_FRIENDLY_OFFSET                 CW_FRIENDLY_OFFSET
  445 #define AST_MUTEX_DEFINE_STATIC             CW_MUTEX_DEFINE_STATIC
  446 #define AST_CONTROL_PROGRESS                CW_CONTROL_PROGRESS
  447 #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL    CW_CAUSE_REQUESTED_CHAN_UNAVAIL
  448 #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION CW_CAUSE_NORMAL_CIRCUIT_CONGESTION
  449 #define AST_CAUSE_USER_BUSY                 CW_CAUSE_USER_BUSY
  450 #define AST_CAUSE_NO_ANSWER                 CW_CAUSE_NO_ANSWER
  451 #define AST_CAUSE_NORMAL_CLEARING           CW_CAUSE_NORMAL_CLEARING
  452 #define AST_SOFTHANGUP_EXPLICIT             CW_SOFTHANGUP_EXPLICIT
  453 #define AST_SOFTHANGUP_DEV                  CW_SOFTHANGUP_DEV
  454 #define AST_CAUSE_NORMAL_CLEARING           CW_CAUSE_NORMAL_CLEARING
  455 #define AST_FRAME_DTMF                      CW_FRAME_DTMF
  456 #define AST_FRAME_CONTROL                   CW_FRAME_CONTROL
  457 #define AST_CONTROL_ANSWER                  CW_CONTROL_ANSWER
  458 #define AST_STATE_UP                        CW_STATE_UP
  459 #define AST_STATE_RINGING                   CW_STATE_RINGING
  460 #define AST_STATE_DOWN                      CW_STATE_DOWN
  461 #define AST_FLAGS_ALL                       CW_FLAGS_ALL
  462 #define AST_FRAME_VOICE                     CW_FRAME_VOICE
  463 #define ASTERISK_GPL_KEY                    0
  464 #define ast_channel_tech                    cw_channel_tech
  465 #define ast_test_flag                       cw_test_flag
  466 #define ast_queue_frame                     cw_queue_frame
  467 #define ast_frdup                           cw_frdup
  468 #define ast_channel                         cw_channel
  469 #define ast_exists_extension                cw_exists_extension
  470 #define ast_hostent                         cw_hostent
  471 #define ast_clear_flag                      cw_clear_flag
  472 #define ast_log                             cw_log
  473 #define ast_set_flag                        cw_set_flag
  474 #define ast_copy_string                     cw_copy_string
  475 #define ast_set_flag                        cw_set_flag
  476 #define ast_set2_flag                       cw_set2_flag
  477 #define ast_setstate                        cw_setstate
  478 #define ast_test_flag                       cw_test_flag
  479 #define ast_softhangup                      cw_softhangup
  480 #define ast_softhangup_nolock               cw_softhangup_nolock
  481 #define ast_true                            cw_true
  482 #define ast_false                           cw_false
  483 #define ast_strlen_zero                     cw_strlen_zero
  484 #define ast_exists_extension                cw_exists_extension
  485 #define ast_frame                           cw_frame
  486 #define ast_jb_conf                         cw_jb_conf
  487 #define ast_carefulwrite                    cw_carefulwrite
  488 #define ast_channel_unregister              cw_channel_unregister
  489 #define ast_cli                             cw_cli
  490 #define ast_cli_register                    cw_cli_register
  491 #define ast_cli_unregister                  cw_cli_unregister
  492 #define ast_jb_read_conf                    cw_jb_read_conf
  493 #define ast_mutex_destroy                   cw_mutex_destroy
  494 #define ast_mutex_init                      cw_mutex_init
  495 #define ast_mutex_lock                      cw_mutex_lock
  496 #define ast_mutex_unlock                    cw_mutex_unlock
  497 #define ast_mutex_t                         cw_mutex_t
  498 #define ast_queue_control                   cw_queue_control
  499 #define ast_queue_frame                     cw_queue_frame
  500 #define ast_queue_hangup                    cw_queue_hangup
  501 #define ast_set_callerid                    cw_set_callerid
  502 #define ast_variable                        cw_variable
  503 #define ast_pthread_create                  cw_pthread_create
  504 #define ast_cli_entry                       cw_cli_entry
  505 #define ast_channel_register                cw_channel_register
  506 #define ast_config_load                     cw_config_load
  507 #define ast_config_destroy                  cw_config_destroy
  508 #define ast_category_browse                 cw_category_browse
  509 #define ast_variable_browse                 cw_variable_browse
  510 #define ast_gethostbyname                   cw_gethostbyname
  511 #define ast_channel_alloc                   cw_channel_alloc
  512 #define ast_dsp_new                         cw_dsp_new
  513 #define ast_dsp                             cw_dsp
  514 #define ast_dsp_set_features                cw_dsp_set_features
  515 #define ast_dsp_digitmode                   cw_dsp_digitmode
  516 #define ast_dsp_set_call_progress_zone      cw_dsp_set_call_progress_zone
  517 #define ast_dsp_set_busy_count              cw_dsp_set_busy_count
  518 #define ast_dsp_set_busy_pattern            cw_dsp_set_busy_pattern
  519 #define ast_dsp_process                     cw_dsp_process
  520 #define ast_strdupa                         cw_strdupa
  521 #define ast_mutex_trylock                   cw_mutex_trylock
  522 #define ast_cause2str                       cw_cause2str
  523 #define ast_pbx_start                       cw_pbx_start
  524 #define ast_hangup                          cw_hangup
  525 
  526 #if !defined(ast_async_goto)
  527 #undefast_async_goto
  528 #define ast_async_goto                      cw_async_goto_n
  529 #endif
  530 #else /* CALLWEAVER prior to v1.9 */
  531 
  532 #define ast_transfercapability2str          opbx_transfercapability2str
  533 #define ast_config                          opbx_config
  534 #define AST_CONTROL_RINGING                 OPBX_CONTROL_RINGING
  535 #define AST_CONTROL_BUSY                    OPBX_CONTROL_BUSY
  536 #define AST_CONTROL_CONGESTION              OPBX_CONTROL_CONGESTION
  537 #define AST_CONTROL_PROCEEDING              OPBX_CONTROL_PROCEEDING
  538 #define AST_CONTROL_PROGRESS                OPBX_CONTROL_PROGRESS
  539 #define AST_CONTROL_HOLD                    OPBX_CONTROL_HOLD
  540 #define AST_CONTROL_UNHOLD                  OPBX_CONTROL_UNHOLD
  541 #define AST_CONTROL_VIDUPDATE               OPBX_CONTROL_VIDUPDATE
  542 
  543 #define AST_FORMAT_SLINEAR                  OPBX_FORMAT_SLINEAR
  544 #define AST_FORMAT_ULAW                     OPBX_FORMAT_ULAW
  545 #define AST_FORMAT_ALAW                     OPBX_FORMAT_ALAW
  546 
  547 #define AST_TRANS_CAP_SPEECH                OPBX_TRANS_CAP_SPEECH
  548 #define AST_TRANS_CAP_3_1K_AUDIO            OPBX_TRANS_CAP_3_1K_AUDIO
  549 #define AST_TRANS_CAP_DIGITAL               OPBX_TRANS_CAP_DIGITAL
  550 #define AST_TRANS_CAP_RESTRICTED_DIGITAL    OPBX_TRANS_CAP_RESTRICTED_DIGITAL
  551 #define AST_TRANS_CAP_DIGITAL_W_TONES       OPBX_TRANS_CAP_DIGITAL_W_TONES
  552 #define AST_TRANS_CAP_VIDEO                 OPBX_TRANS_CAP_VIDEO
  553 
  554 #ifndef LOG_NOTICE
  555 #define LOG_NOTICE                          OPBX_LOG_NOTICE
  556 #endif
  557 
  558 #ifndef LOG_DEBUG
  559 #define LOG_DEBUG                           OPBX_LOG_DEBUG
  560 #endif
  561 
  562 #ifndef LOG_ERROR
  563 #define LOG_ERROR                           OPBX_LOG_ERROR
  564 #endif
  565 
  566 #ifndef LOG_WARNING
  567 #define LOG_WARNING                         OPBX_LOG_WARNING
  568 #endif
  569 
  570 
  571 #define AST_FORMAT_SLINEAR                  OPBX_FORMAT_SLINEAR
  572 #define AST_FORMAT_ULAW                     OPBX_FORMAT_ULAW
  573 #define AST_FORMAT_ALAW                     OPBX_FORMAT_ALAW
  574 #define AST_FORMAT_ADPCM                    OPBX_FORMAT_DVI_ADPCM
  575 
  576 #define ast_mutex_t                         opbx_mutex_t
  577 #define ast_frame                           opbx_frame
  578 #define ast_verbose                         opbx_verbose
  579 #define AST_FRIENDLY_OFFSET                 OPBX_FRIENDLY_OFFSET
  580 #define AST_MUTEX_DEFINE_STATIC             OPBX_MUTEX_DEFINE_STATIC
  581 #define AST_CONTROL_PROGRESS                OPBX_CONTROL_PROGRESS
  582 #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL    OPBX_CAUSE_REQUESTED_CHAN_UNAVAIL
  583 #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION OPBX_CAUSE_NORMAL_CIRCUIT_CONGESTION
  584 #define AST_CAUSE_USER_BUSY                 OPBX_CAUSE_USER_BUSY
  585 #define AST_CAUSE_NO_ANSWER                 OPBX_CAUSE_NO_ANSWER
  586 #define AST_CAUSE_NORMAL_CLEARING           OPBX_CAUSE_NORMAL_CLEARING
  587 #define AST_SOFTHANGUP_EXPLICIT             OPBX_SOFTHANGUP_EXPLICIT
  588 #define AST_SOFTHANGUP_DEV                  OPBX_SOFTHANGUP_DEV
  589 #define AST_CAUSE_NORMAL_CLEARING           OPBX_CAUSE_NORMAL_CLEARING
  590 #define AST_FRAME_DTMF                      OPBX_FRAME_DTMF
  591 #define AST_FRAME_CONTROL                   OPBX_FRAME_CONTROL
  592 #define AST_CONTROL_ANSWER                  OPBX_CONTROL_ANSWER
  593 #define AST_STATE_UP                        OPBX_STATE_UP
  594 #define AST_STATE_RINGING                   OPBX_STATE_RINGING
  595 #define AST_STATE_DOWN                      OPBX_STATE_DOWN
  596 #define AST_FLAGS_ALL                       OPBX_FLAGS_ALL
  597 #define AST_FRAME_VOICE                     OPBX_FRAME_VOICE
  598 #define AST_FRAME_NULL                      OPBX_FRAME_NULL
  599 #define ASTERISK_GPL_KEY                    0
  600 #define ast_channel_tech                    opbx_channel_tech
  601 #define ast_test_flag                       opbx_test_flag
  602 #define ast_queue_frame                     opbx_queue_frame
  603 #define ast_frdup                           opbx_frdup
  604 #define ast_channel                         opbx_channel
  605 #define ast_exists_extension                opbx_exists_extension
  606 #define ast_hostent                         opbx_hostent
  607 #define ast_clear_flag                      opbx_clear_flag
  608 #define ast_log                             opbx_log
  609 #define ast_set_flag                        opbx_set_flag
  610 #define ast_copy_string                     opbx_copy_string
  611 #define ast_set_flag                        opbx_set_flag
  612 #define ast_set2_flag                       opbx_set2_flag
  613 #define ast_setstate                        opbx_setstate
  614 #define ast_test_flag                       opbx_test_flag
  615 #define ast_softhangup                      opbx_softhangup
  616 #define ast_softhangup_nolock               opbx_softhangup_nolock
  617 #define ast_true                            opbx_true
  618 #define ast_false                           opbx_false
  619 #define ast_strlen_zero                     opbx_strlen_zero
  620 #define ast_exists_extension                opbx_exists_extension
  621 #define ast_frame                           opbx_frame
  622 #define ast_jb_conf                         opbx_jb_conf
  623 #define ast_carefulwrite                    opbx_carefulwrite
  624 #define ast_channel_unregister              opbx_channel_unregister
  625 #define ast_cli                             opbx_cli
  626 #define ast_cli_register                    opbx_cli_register
  627 #define ast_cli_unregister                  opbx_cli_unregister
  628 #define ast_jb_read_conf                    opbx_jb_read_conf
  629 #define ast_mutex_destroy                   opbx_mutex_destroy
  630 #define ast_mutex_init                      opbx_mutex_init
  631 #define ast_mutex_lock                      opbx_mutex_lock
  632 #define ast_mutex_unlock                    opbx_mutex_unlock
  633 #define ast_mutex_t                         opbx_mutex_t
  634 #define ast_queue_control                   opbx_queue_control
  635 #define ast_queue_frame                     opbx_queue_frame
  636 #define ast_queue_hangup                    opbx_queue_hangup
  637 #define ast_set_callerid                    opbx_set_callerid
  638 #define ast_variable                        opbx_variable
  639 #define ast_pthread_create                  opbx_pthread_create
  640 #define ast_cli_entry                       opbx_cli_entry
  641 #define ast_channel_register                opbx_channel_register
  642 #define ast_config_load                     opbx_config_load
  643 #define ast_config_destroy                  opbx_config_destroy
  644 #define ast_category_browse                 opbx_category_browse
  645 #define ast_variable_browse                 opbx_variable_browse
  646 #define ast_gethostbyname                   opbx_gethostbyname
  647 #define ast_channel_alloc                   opbx_channel_alloc
  648 #define ast_dsp_new                         opbx_dsp_new
  649 #define ast_dsp                             opbx_dsp
  650 #define ast_dsp_set_features                opbx_dsp_set_features
  651 #define ast_dsp_digitmode                   opbx_dsp_digitmode
  652 #define ast_dsp_set_call_progress_zone      opbx_dsp_set_call_progress_zone
  653 #define ast_dsp_set_busy_count              opbx_dsp_set_busy_count
  654 #define ast_dsp_set_busy_pattern            opbx_dsp_set_busy_pattern
  655 #define ast_dsp_process                     opbx_dsp_process
  656 #define ast_strdupa                         opbx_strdupa
  657 #define ast_mutex_trylock                   opbx_mutex_trylock
  658 #define ast_cause2str                       opbx_cause2str
  659 #define ast_pbx_start                       opbx_pbx_start
  660 #define ast_hangup                          opbx_hangup
  661 
  662 #if !defined(ast_async_goto)
  663 #undef ast_async_goto
  664 #define ast_async_goto                      opbx_async_goto
  665 #endif
  666 
  667 #endif /* CALLWEAVER_19 */
  668 #endif
  669 
  670 #include "g711.h"
  671 #include <errno.h>
  672 
  673 //#define USE_TECH_INDICATE
  674 #ifdef  USE_TECH_INDICATE
  675 #define MEDIA_ANSWER "MEDIA"
  676 #else
  677 #define MEDIA_ANSWER "ACCEPT"
  678 #endif
  679 
  680 #define USE_ANSWER 1
  681 
  682 #ifndef ast_free
  683 #define ast_free(x) free(x)
  684 #define ast_malloc(x) malloc(x)
  685 #endif
  686 
  687 
  688 extern int option_verbose;
  689 
  690 #define WOOMERA_VERSION "v1.59"
  691 #ifndef WOOMERA_CHAN_NAME
  692 #define WOOMERA_CHAN_NAME "WOOMERA"
  693 #endif
  694 
  695 #if 1
  696 #undef WOOMERA_PRINTF_DEBUG
  697 #else
  698 #warning "WOOMERA_PRINTF_DEBUG defined"
  699 #define WOOMERA_PRINTF_DEBUG
  700 #endif
  701 #ifdef WOOMERA_PRINTF_DEBUG
  702 #define woomera_printf(a,b,c,msg...) __woomera_printf(__FUNCTION__,__LINE__,a,b,c,##msg)
  703 #else
  704 #define woomera_printf(a,b,c,msg...) __woomera_printf(a,b,c,##msg)
  705 #endif
  706 
  707 static int tech_count = 0;
  708 
  709 static const char desc[] = "Woomera Channel Driver";
  710 //static const char type[] = "WOOMERA";
  711 static const char tdesc[] = "Woomera Channel Driver";
  712 static char configfile[] = "woomera.conf";
  713 
  714 static char svrversion_init = 0;
  715 static char svrversion[100] = "N/A";
  716 
  717 static char mohinterpret[MAX_MUSICCLASS] = "default";
  718 static char mohsuggest[MAX_MUSICCLASS] = "";
  719 
  720 
  721 static char *woomeraplaybackdesc = "Play audio and / or video on the Woomera Server\n";
  722 static char *woomeraplaybackapp = "WoomeraPlayback";
  723 static char *woomeraplaybacksynopsis = "Execute a play on chan_woomera";
  724 
  725 static char *woomerabackgrounddesc = "Play audio and / or video in the background on the Woomera Server\n";
  726 static char *woomerabackgroundapp = "WoomeraBackground";
  727 static char *woomerabackgroundsynopsis = "Execute a background play on chan_woomera";
  728 
  729 static char *woomerarecorddesc = "Record audio and / or video on the Woomera Server\n";
  730 static char *woomerarecordapp = "WoomeraRecord";
  731 static char *woomerarecordsynopsis = "Execute a Record on chan_woomera";
  732 
  733 static char *woomerastopdesc = "Stop the current background play on the Woomera Server\n";
  734 static char *woomerastopapp = "WoomeraStop";
  735 static char *woomerastopsynopsis = "Stop the current WoomeraBackground ";
  736 
  737 static char *woomeraringbackdesc = "Play audio and / or video ringback until the caall is answered\n";
  738 static char *woomeraringbackapp = "WoomeraRingback";
  739 static char *woomeraringbacksynopsis = "Execute a play ringback on chan_woomera";
  740 
  741 
  742 #if !defined (AST14) && !defined (AST16)
  743 struct ast_frame ast_null_frame;
  744 #endif
  745 
  746 #if defined (AST14) || defined (AST16)
  747  #if !defined (AST_JB)
  748   #define AST_JB 1
  749  #endif
  750 #endif
  751 
  752 #if !defined(DSP_FEATURE_DTMF_DETECT) && defined(DSP_FEATURE_DIGIT_DETECT)
  753  #define DSP_FEATURE_DTMF_DETECT DSP_FEATURE_DIGIT_DETECT
  754  #define ast_dsp_digitmode ast_dsp_set_digitmode
  755  #define woo_ast_data_ptr data.ptr
  756 #else
  757  #define woo_ast_data_ptr data
  758 #endif
  759 
  760 #if defined (AST_JB)
  761 #include "asterisk/abstract_jb.h"
  762 /* Global jitterbuffer configuration - by default, jb is disabled */
  763 static struct ast_jb_conf default_jbconf =
  764 {
  765         .flags = 0,
  766         .max_size = -1,
  767         .resync_threshold = -1,
  768         .impl = ""
  769 };
  770 static struct ast_jb_conf global_jbconf;
  771 #endif /* AST_JB */
  772 
  773 
  774 #define WOOMERA_SLINEAR 0
  775 #define WOOMERA_ULAW  1
  776 #define WOOMERA_ALAW  2
  777 
  778 #define WOOMERA_MAX_MEDIA_PORTS 899
  779 
  780 #define WOOMERA_STRLEN 256
  781 #define WOOMERA_ARRAY_LEN 50
  782 #define WOOMERA_MIN_PORT  10000
  783 #define WOOMERA_MAX_PORT WOOMERA_MIN_PORT+WOOMERA_MAX_MEDIA_PORTS
  784 #define WOOMERA_BODYLEN 2048
  785 #define WOOMERA_LINE_SEPARATOR "\r\n"
  786 #define WOOMERA_RECORD_SEPARATOR "\r\n\r\n"
  787 #define WOOMERA_DEBUG_PREFIX "[WOOMERA] "
  788 #define WOOMERA_DEBUG_LINE "--------------------------------------------------------------------------------"
  789 #define WOOMERA_HARD_TIMEOUT -2000
  790 #define WOOMERA_QLEN 10
  791 #define WOOMERA_MAX_TRUNKGROUPS 64
  792 
  793 static int woomera_base_media_port = WOOMERA_MIN_PORT;
  794 static int woomera_max_media_port  = WOOMERA_MAX_PORT;
  795 
  796 /* this macro is not in all versions of asterisk */
  797 #ifdef OLDERAST
  798 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
  799         ({ \
  800                 typeof((container)->head) found = NULL; \
  801                 typeof((container)->head) prev = NULL; \
  802                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
  803                         if (iterator== obj) { \
  804                                 found = iterator; \
  805                                 found->next[0] = NULL; \
  806                                 ASTOBJ_CONTAINER_WRLOCK(container); \
  807                                 if (prev) \
  808                                         prev->next[0] = next; \
  809                                 else \
  810                                         (container)->head = next; \
  811                                 ASTOBJ_CONTAINER_UNLOCK(container); \
  812                         } \
  813                         prev = iterator; \
  814                 } while (0)); \
  815                 found; \
  816         })
  817 #endif
  818 
  819 
  820 #define FRAME_LEN 480
  821 
  822 #if 0
  823 static int WFORMAT = AST_FORMAT_ALAW; //AST_FORMAT_SLINEAR;
  824 #else
  825 static int WFORMAT = AST_FORMAT_SLINEAR;
  826 #endif
  827 
  828 typedef enum {
  829   WFLAG_EXISTS = (1 << 0),
  830   WFLAG_EVENT = (1 << 1),
  831   WFLAG_CONTENT = (1 << 2),
  832 } WFLAGS;
  833 
  834 
  835 typedef enum {
  836   WCFLAG_NOWAIT = (1 << 0)
  837 } WCFLAGS;
  838 
  839 
  840 typedef enum {
  841   PFLAG_INBOUND = (1 << 0),
  842   PFLAG_OUTBOUND = (1 << 1),
  843   PFLAG_DYNAMIC = (1 << 2),
  844   PFLAG_DISABLED = (1 << 3)
  845 } PFLAGS;
  846 
  847 typedef enum {
  848   TFLAG_MEDIA = (1 << 0),
  849   TFLAG_INBOUND = (1 << 1),
  850   TFLAG_OUTBOUND = (1 << 2),
  851   TFLAG_INCOMING = (1 << 3),
  852   TFLAG_PARSE_INCOMING = (1 << 4),
  853   TFLAG_ACTIVATE = (1 << 5),
  854   TFLAG_DTMF = (1 << 6),
  855   TFLAG_DESTROY = (1 << 7),
  856   TFLAG_ABORT = (1 << 8),
  857   TFLAG_PBX = (1 << 9),
  858   TFLAG_ANSWER = (1 << 10),
  859   TFLAG_INTHREAD = (1 << 11),
  860   TFLAG_TECHHANGUP = (1 << 12),
  861   TFLAG_DESTROYED = (1 << 13),
  862   TFLAG_UP = (1 << 14),
  863   TFLAG_ACCEPT = (1 << 15),
  864   TFLAG_ACCEPTED = (1 << 16),
  865   TFLAG_ANSWER_RECEIVED = (1 << 17),
  866   TFLAG_CONFIRM_ANSWER = (1 << 18),
  867   TFLAG_CONFIRM_ANSWER_ENABLED = (1 << 19),
  868   TFLAG_AST_HANGUP = (1 << 20),
  869   TFLAG_PLAY = (1 << 21),
  870   TFLAG_PLAY_COMPLETED = (1 << 22),
  871   TFLAG_RECORD = (1 << 23),
  872   TFLAG_RECORD_COMPLETED = (1 << 24),
  873   TFLAG_STOP = (1 << 25),
  874   TFLAG_STOP_COMPLETED = (1 << 26),
  875   TFLAG_BRIDGE = (1 << 27),
  876   TFLAG_CONNECTED = (1 << 28)
  877 } TFLAGS;
  878 
  879 static int usecnt = 0;
  880 
  881 struct woomera_message {
  882   char callid[WOOMERA_STRLEN];
  883   int mval;
  884   char command[WOOMERA_STRLEN];
  885   char command_args[WOOMERA_STRLEN];
  886   char names[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN];
  887   char values[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN];
  888   char body[WOOMERA_BODYLEN];
  889   char cause[WOOMERA_STRLEN];
  890   unsigned int flags;
  891   int last;
  892   unsigned int queue_id;
  893   struct woomera_message *next;
  894 };
  895 
  896 
  897 static struct {
  898   int next_woomera_port;
  899   int debug;
  900   int panic;
  901   int more_threads;
  902   ast_mutex_t woomera_port_lock;
  903 } globals;
  904 
  905 static struct {
  906   int woomeraplayback;
  907   int woomerabackground;
  908   int woomerarecord;
  909   int woomeraringback;
  910 } capabilities;
  911 
  912 struct woomera_event_queue {
  913   struct woomera_message *head;
  914   ast_mutex_t lock;
  915 };
  916 
  917 struct woomera_profile {
  918   ASTOBJ_COMPONENTS(struct woomera_profile);
  919   ast_mutex_t iolock;
  920   ast_mutex_t call_count_lock;
  921   char woomera_host[WOOMERA_STRLEN];
  922   int max_calls;
  923   int call_count;
  924   int woomera_port;
  925   char audio_ip[WOOMERA_STRLEN];
  926   char context[WOOMERA_STRLEN];
  927   pthread_t thread;
  928   unsigned int flags;
  929   int thread_running;
  930   int dtmf_enable;
  931   int send_dtmf_enable;
  932   int faxdetect;
  933   int woomera_socket;
  934   struct woomera_event_queue event_queue;
  935   int jb_enable;
  936   int rtp_enable;
  937   int vrtp_enable;
  938   int bridge_enable;
  939   int progress_enable;
  940   int coding;
  941   int videocoding;
  942   float rxgain_val;
  943   float txgain_val;
  944   unsigned char rxgain[256];
  945   unsigned char txgain[256];
  946   int call_out;
  947   int call_in;
  948   int call_ok;
  949   int call_end;
  950   int call_abort;
  951   int call_ast_hungup;
  952   char default_context[WOOMERA_STRLEN];
  953   char* tg_context [WOOMERA_MAX_TRUNKGROUPS+1];
  954   char language[WOOMERA_STRLEN];
  955   char* tg_language [WOOMERA_MAX_TRUNKGROUPS+1];
  956   int udp_seq;
  957   int rx_sync_check_opt;
  958   int tx_sync_check_opt;
  959   int tx_sync_gen_opt;
  960 };
  961 
  962 
  963 struct private_object {
  964   ASTOBJ_COMPONENTS(struct private_object);
  965   ast_mutex_t iolock;
  966   struct ast_channel *owner;
  967   struct sockaddr_in udpread;
  968   struct sockaddr_in udpwrite;
  969   int command_channel;
  970   int udp_socket;
  971   unsigned int flags;
  972   struct ast_frame frame;
  973   short fdata[FRAME_LEN + AST_FRIENDLY_OFFSET];
  974   struct woomera_message call_info;
  975   struct woomera_profile *profile;
  976   char dest[WOOMERA_STRLEN];
  977   char proto[WOOMERA_STRLEN];
  978   int port;
  979   int vport;
  980   struct timeval started;
  981   int timeout;
  982   char dtmfbuf[WOOMERA_STRLEN];
  983   char cid_name[WOOMERA_STRLEN];
  984   char cid_num[WOOMERA_STRLEN];
  985   char mohinterpret[MAX_MUSICCLASS];
  986   char mohsuggest[MAX_MUSICCLASS];
  987   char *cid_rdnis;
  988   int  cid_pres;
  989   char ds[WOOMERA_STRLEN];
  990   struct ast_dsp *dsp;
  991   int ast_dsp;
  992   int dsp_features;
  993   int faxdetect;
  994   int faxhandled;
  995   int rtp_enable;
  996   int vrtp_enable;
  997   int send_dtmf_enable;
  998   int bridge_enable;
  999   int call_count;
 1000   char callid[WOOMERA_STRLEN];
 1001   pthread_t thread;
 1002   unsigned int callno;
 1003   int refcnt;
 1004   struct woomera_event_queue event_queue;
 1005   int coding;
 1006   int videocoding;
 1007   int pri_cause;
 1008   int rx_udp_seq;
 1009   int tx_udp_seq;
 1010   char audio_uri[WOOMERA_STRLEN];
 1011   char video_uri[WOOMERA_STRLEN];
 1012   char stop_digits[12+1];
 1013   char repeat[WOOMERA_STRLEN];         /* Integer string (1..n) or "infinite" */
 1014   int beep;
 1015 
 1016 #ifdef AST_JB
 1017   struct ast_jb_conf jbconf;
 1018 #endif /* AST_JB */
 1019 
 1020   int sync_r;
 1021   int sync_w;
 1022   unsigned char sync_data_w;
 1023   unsigned char sync_data_r;
 1024   int capability;
 1025   struct ast_rtp *rtp;                 /* Audio RTP Session */
 1026   struct ast_rtp *vrtp;                /* Video RTP session */
 1027   struct sockaddr_in audio_bridge_ip;  /* Bridge destination for our Audio RTP */
 1028   struct sockaddr_in video_bridge_ip;  /* Bridge destination for our Video RTP */
 1029 
 1030 };
 1031 
 1032 
 1033 #define WOOMERA_MAX_CALLS 720     /* 24 * E1 */
 1034 
 1035 static struct private_object *tech_pvt_idx[WOOMERA_MAX_CALLS];
 1036 static ast_mutex_t tech_pvt_idx_lock[WOOMERA_MAX_CALLS];
 1037 
 1038 typedef struct private_object private_object;
 1039 typedef struct woomera_message woomera_message;
 1040 typedef struct woomera_profile woomera_profile;
 1041 typedef struct woomera_event_queue woomera_event_queue;
 1042 
 1043 #ifndef DEADLOCK_AVOIDANCE
 1044 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
 1045 #define DEADLOCK_AVOIDANCE(lock) \
 1046         do { \
 1047                 ast_mutex_unlock(lock); \
 1048                 usleep(1); \
 1049                 ast_mutex_lock(lock); \
 1050         } while (0)
 1051 #endif
 1052 
 1053 
 1054 static int my_ast_channel_trylock(struct ast_channel *chan)
 1055 {
 1056 #if defined (AST14) || defined (AST16)
 1057   return ast_channel_trylock(chan);
 1058 #else
 1059   return ast_mutex_trylock(&chan->lock);
 1060 #endif
 1061 }
 1062 
 1063 #if !defined (CALLWEAVER)
 1064 #if 0
 1065 static int my_ast_channel_lock(struct ast_channel *chan)
 1066 {
 1067 #if defined (AST14) || defined (AST16)
 1068   return ast_channel_lock(chan);
 1069 #else
 1070   return ast_mutex_lock(&chan->lock);
 1071 #endif
 1072 }
 1073 #endif
 1074 #endif
 1075 
 1076 static int my_ast_channel_unlock(struct ast_channel *chan)
 1077 {
 1078 #if defined (AST14) || defined (AST16)
 1079   return ast_channel_unlock(chan);
 1080 #else
 1081   return ast_mutex_unlock(&chan->lock);
 1082 #endif
 1083 }
 1084 
 1085 /*!
 1086  * Lock both the private object and the owning channel.
 1087  */
 1088 static int my_tech_pvt_and_owner_lock(private_object *tech_pvt)
 1089 {
 1090   ast_mutex_lock(&tech_pvt->iolock);
 1091   while (tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) {
 1092     if (globals.debug > 2) {
 1093       ast_log(LOG_NOTICE, "my_tech_pvt_and_owner_lock() - deadlock avoidance\n");
 1094     }
 1095     DEADLOCK_AVOIDANCE(&tech_pvt->iolock);
 1096   }
 1097   return 0;
 1098 }
 1099 
 1100 /*!
 1101  * Unlock both the private object and the owning channel.
 1102  */
 1103 static int my_tech_pvt_and_owner_unlock(private_object *tech_pvt)
 1104 {
 1105   if (tech_pvt->owner) {
 1106     my_ast_channel_unlock(tech_pvt->owner);
 1107   }
 1108   ast_mutex_unlock(&tech_pvt->iolock);
 1109   return 0;
 1110 }
 1111 
 1112 
 1113 static void my_ast_softhangup(struct ast_channel *chan, private_object *tech_pvt, int cause)
 1114 {
 1115 #if 1
 1116   ast_queue_hangup(chan);
 1117   //ast_softhangup(chan,  AST_SOFTHANGUP_EXPLICIT);
 1118 #else
 1119   struct ast_frame f = { AST_FRAME_NULL };
 1120 
 1121   if (chan) {
 1122     chan->_softhangup |= cause;
 1123     ast_queue_frame(chan, &f);
 1124   }
 1125 
 1126   ast_set_flag(tech_pvt, TFLAG_ABORT);
 1127 #endif
 1128 
 1129 #if 0
 1130   if (tech_pvt->dsp) {
 1131     tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
 1132     ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
 1133     tech_pvt->ast_dsp = 0;
 1134   }
 1135 #endif
 1136 
 1137 }
 1138 
 1139 /* For RTP audio */
 1140 static struct sched_context *sched;     /*!< The scheduling context */
 1141 static struct io_context *io;           /*!< The IO context */
 1142 
 1143 
 1144 static struct private_object_container {
 1145     ASTOBJ_CONTAINER_COMPONENTS(private_object);
 1146 } private_object_list;
 1147 
 1148 static struct woomera_profile_container {
 1149     ASTOBJ_CONTAINER_COMPONENTS(woomera_profile);
 1150 } woomera_profile_list;
 1151 
 1152 static woomera_profile default_profile;
 1153 
 1154 /* some locks you will use for use count and for exclusive access to the main linked-list of private objects */
 1155 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 1156 AST_MUTEX_DEFINE_STATIC(lock);
 1157 
 1158 /* local prototypes */
 1159 static void woomera_close_socket(int *socket);
 1160 static void global_set_flag(int flags);
 1161 #ifdef WOOMERA_PRINTF_DEBUG
 1162 static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...);
 1163 #else
 1164 static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...);
 1165 #endif
 1166 static char *woomera_message_header(woomera_message *wmsg, char *key);
 1167 static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
 1168 static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
 1169 static int woomera_message_parse(int fd, woomera_message *wmsg, int timeout, woomera_profile *profile, woomera_event_queue *event_queue);
 1170 static int woomera_message_parse_wait(private_object *tech_pvt,woomera_message *wmsg);
 1171 static int waitfor_socket(int fd, int timeout);
 1172 static int woomera_profile_thread_running(woomera_profile *profile, int set, int new);
 1173 static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket);
 1174 static void *woomera_thread_run(void *obj);
 1175 static void launch_woomera_thread(woomera_profile *profile);
 1176 static void destroy_woomera_profile(woomera_profile *profile);
 1177 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile, woomera_profile *default_profile);
 1178 static woomera_profile *create_woomera_profile(woomera_profile *default_profile);
 1179 static int config_woomera(void);
 1180 static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client);
 1181 static struct ast_rtp * create_rtp(char *ip);
 1182 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags);
 1183 static int init_woomera(void);
 1184 
 1185 #if defined (AST16)
 1186 static char *ast16_woomera_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 1187 #endif
 1188 
 1189 static int woomera_cli(int fd, int argc, char *argv[]);
 1190 static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner);
 1191 static struct ast_channel *woomera_new(const char *type, int format, void *data, int *cause, woomera_profile *profile);
 1192 static int launch_tech_thread(private_object *tech_pvt);
 1193 static int tech_create_read_socket(private_object *tech_pvt);
 1194 static int tech_activate(private_object *tech_pvt);
 1195 static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags);
 1196 static void *tech_monitor_thread(void *obj);
 1197 static void tech_monitor_in_one_thread(void);
 1198 static struct ast_channel *  tech_get_owner( private_object *tech_pvt);
 1199 int usecount(void);
 1200 
 1201 #if 0
 1202 static char *key(void);
 1203 static char *description(void);
 1204 #endif
 1205 
 1206 int load_module(void);
 1207 int unload_module(void);
 1208 int reload(void);
 1209 
 1210 /********************CHANNEL METHOD PROTOTYPES**********************************
 1211  * You may or may not need all of these methods,
 1212  * remove any unnecessary functions/protos/mappings as needed.
 1213  */
 1214 static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause);
 1215 static int tech_send_digit(struct ast_channel *self, char digit);
 1216 
 1217 #if defined (AST14) || defined (AST16)
 1218 static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 1219 #endif
 1220 
 1221 static int tech_call(struct ast_channel *self, char *dest, int timeout);
 1222 static int tech_hangup(struct ast_channel *self);
 1223 static int tech_answer(struct ast_channel *self);
 1224 static struct ast_frame *tech_read(struct ast_channel *self);
 1225 static struct ast_frame *tech_exception(struct ast_channel *self);
 1226 static int tech_write(struct ast_channel *self, struct ast_frame *frame);
 1227 
 1228 #ifdef  USE_TECH_INDICATE
 1229 # if defined (AST14) || defined (AST16)
 1230 static int tech_indicate(struct ast_channel *self, int condition, const void *data, size_t datalen);
 1231 # else
 1232 static int tech_indicate(struct ast_channel *self, int condition);
 1233 # endif
 1234 #endif
 1235 
 1236 static int tech_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 1237 static int tech_send_html(struct ast_channel *self, int subclass, const char *data, int datalen);
 1238 static int tech_send_text(struct ast_channel *self, const char *text);
 1239 static int tech_send_image(struct ast_channel *self, struct ast_frame *frame);
 1240 static int tech_setoption(struct ast_channel *self, int option, void *data, int datalen);
 1241 static int tech_queryoption(struct ast_channel *self, int option, void *data, int *datalen);
 1242 //static enum ast_bridge_result tech_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 1243 static int tech_transfer(struct ast_channel *self, const char *newdest);
 1244 static int tech_write_video(struct ast_channel *self, struct ast_frame *frame);
 1245 //static struct ast_channel *tech_bridged_channel(struct ast_channel *self, struct ast_channel *bridge);
 1246 
 1247 static enum ast_rtp_get_result tech_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 1248 static enum ast_rtp_get_result tech_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 1249 //static enum ast_rtp_get_result tech_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
 1250 
 1251 #if defined (AST16)
 1252   static int tech_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
 1253 #else
 1254   static int tech_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
 1255 #endif
 1256 
 1257 static int tech_get_codec(struct ast_channel *chan);
 1258 
 1259 static int woomera_event_incoming (private_object *tech_pvt);
 1260 static int woomera_event_media (private_object *tech_pvt, woomera_message *wmsg);
 1261 static void woomera_check_event (private_object *tech_pvt, int res, woomera_message *wmsg);
 1262 
 1263 /*******************************************************************************
 1264  * Constant structure for mapping local methods to the core interface.
 1265  * This structure only needs to contain the methods the channel requires to operate
 1266  * Not every channel needs all of them defined.
 1267  */
 1268 
 1269 static const struct ast_channel_tech technology = {
 1270   .type = WOOMERA_CHAN_NAME,
 1271   .description = tdesc,
 1272   .capabilities = (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW),
 1273   .requester = tech_requester,
 1274 #if defined (AST14) || defined (AST16)
 1275   .send_digit_begin = tech_send_digit,
 1276   .send_digit_end = tech_digit_end,
 1277 #else
 1278   .send_digit = tech_send_digit,
 1279 #endif
 1280   .call = tech_call,
 1281   .bridge = ast_rtp_bridge,
 1282 //  .early_bridge = ast_rtp_early_bridge,
 1283   .hangup = tech_hangup,
 1284   .answer = tech_answer,
 1285   .transfer = tech_transfer,
 1286   .write_video = tech_write_video,
 1287   .read = tech_read,
 1288   .write = tech_write,
 1289   .exception = tech_exception,
 1290 #ifdef  USE_TECH_INDICATE
 1291   .indicate = tech_indicate,
 1292 #endif
 1293   .fixup = tech_fixup,
 1294   .send_html = tech_send_html,
 1295   .send_text = tech_send_text,
 1296   .send_image = tech_send_image,
 1297   .setoption = tech_setoption,
 1298   .queryoption = tech_queryoption,
 1299   //.bridged_channel = tech_bridged_channel,
 1300   .transfer = tech_transfer,
 1301 };
 1302 
 1303 
 1304 /*!
 1305  * Interface structure with callbacks used to connect to RTP module
 1306  */
 1307 static struct ast_rtp_protocol tech_rtp = {
 1308   .type = "WOOMERA",
 1309   .get_rtp_info = tech_get_rtp_peer,
 1310   .get_vrtp_info = tech_get_vrtp_peer,
 1311 //  .get_trtp_info = tech_get_trtp_peer,
 1312   .set_rtp_peer = tech_set_rtp_peer,
 1313   .get_codec = tech_get_codec,
 1314 };
 1315 
 1316 /******************************************************************************/
 1317 
 1318 static void woomera_close_socket(int *socket)
 1319 {
 1320   if (*socket > -1) {
 1321     close(*socket);
 1322   }
 1323   *socket = -1;
 1324 }
 1325 
 1326 
 1327 static int woomera_message_reply_ok(woomera_message *wmsg)
 1328 {
 1329   if (!(wmsg->mval >= 200 && wmsg->mval <= 299)) {
 1330     return -1;
 1331   }
 1332   return 0;
 1333 }
 1334 
 1335 
 1336 static void global_set_flag(int flags)
 1337 {
 1338   private_object *tech_pvt;
 1339 
 1340   ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do {
 1341     ASTOBJ_RDLOCK(iterator);
 1342     tech_pvt = iterator;
 1343     ast_set_flag(tech_pvt, flags);
 1344     ASTOBJ_UNLOCK(iterator);
 1345     } while(0));
 1346 }
 1347 
 1348 
 1349 static void woomera_send_progress(private_object *tech_pvt)
 1350 {
 1351   struct ast_channel *owner = tech_pvt->owner;
 1352 
 1353   if (tech_pvt->profile->progress_enable && owner) {
 1354     if (globals.debug > 2) {
 1355       ast_log(LOG_NOTICE, "Sending Progress %s\n", tech_pvt->callid);
 1356     }
 1357     ast_queue_control(owner, AST_CONTROL_PROGRESS);
 1358   }
 1359 }
 1360 
 1361 
 1362 static int  woomera_coding_to_ast(char *suil1p)
 1363 {
 1364   if (suil1p) {
 1365     if (!strcasecmp(suil1p, "G_711_ULAW")) {
 1366       return AST_FORMAT_ULAW;
 1367     }
 1368     if (!strcasecmp(suil1p, "G_711_ALAW")) {
 1369       return AST_FORMAT_ALAW;
 1370     }
 1371     if (!strcasecmp(suil1p, "G_721")) {
 1372       return AST_FORMAT_ADPCM;
 1373     }
 1374   }
 1375   return -1;
 1376 }
 1377 
 1378 
 1379 static char* woomera_ast_coding_to_string(int coding)
 1380 {
 1381   switch(coding) {
 1382     case AST_FORMAT_ALAW:
 1383       return "G_711_ALAW";
 1384     case AST_FORMAT_ULAW:
 1385       return "G_711_ULAW";
 1386     case AST_FORMAT_ADPCM:
 1387       return "G_721";
 1388   }
 1389   return "G_711_ALAW";
 1390 }
 1391 
 1392 
 1393 static uint32_t woomera_capability_to_ast(char *sbearer_cap)
 1394 {
 1395   if (sbearer_cap) {
 1396     if (!strcasecmp(sbearer_cap, "SPEECH")) {
 1397       return AST_TRANS_CAP_SPEECH;
 1398     }
 1399     if (!strcasecmp(sbearer_cap, "3_1KHZ_AUDIO")) {
 1400       return AST_TRANS_CAP_3_1K_AUDIO;
 1401     }
 1402     if (!strcasecmp(sbearer_cap, "64K_UNRESTRICTED") ||
 1403         !strcasecmp(sbearer_cap, "ALTERNATE_SPEECH") ||
 1404         !strcasecmp(sbearer_cap, "ALTERNATE_64K") ||
 1405         !strcasecmp(sbearer_cap, "64K_PREFERRED") ||
 1406         !strcasecmp(sbearer_cap, "384K_UNRESTRICTED") ||
 1407         !strcasecmp(sbearer_cap, "2x64K_PREFERRED") ||
 1408         !strcasecmp(sbearer_cap, "1536K_UNRESTRICTED") ||
 1409         !strcasecmp(sbearer_cap, "1920K_UNRESTRICTED")) {
 1410 
 1411       return AST_TRANS_CAP_DIGITAL;
 1412     }
 1413   }
 1414   return AST_TRANS_CAP_SPEECH;
 1415 }
 1416 
 1417 
 1418 static char* woomera_ast_transfercap_to_string(int transfercap)
 1419 {
 1420   switch(transfercap) {
 1421     case AST_TRANS_CAP_SPEECH:
 1422       return "SPEECH";
 1423     case AST_TRANS_CAP_3_1K_AUDIO:
 1424       return "3_1KHZ_AUDIO";
 1425     case AST_TRANS_CAP_DIGITAL:
 1426     case AST_TRANS_CAP_RESTRICTED_DIGITAL:
 1427     case AST_TRANS_CAP_DIGITAL_W_TONES:
 1428     case AST_TRANS_CAP_VIDEO:
 1429       return "64K_UNRESTRICTED";
 1430   }
 1431 
 1432   return "SPEECH";
 1433 }
 1434 
 1435 
 1436 static uint32_t string_to_release(char *code)
 1437 {
 1438   if (code) {
 1439     if (!strcasecmp(code, "CHANUNAVAIL")) {
 1440       return AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
 1441     }
 1442 
 1443     if (!strcasecmp(code, "INVALID")) {
 1444       return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 1445     }
 1446 
 1447     if (!strcasecmp(code, "ERROR")) {
 1448       return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 1449     }
 1450 
 1451     if (!strcasecmp(code, "CONGESTION")) {
 1452       return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 1453     }
 1454 
 1455     if (!strcasecmp(code, "BUSY")) {
 1456       return AST_CAUSE_USER_BUSY;
 1457     }
 1458 
 1459     if (!strcasecmp(code, "NOANSWER")) {
 1460       return AST_CAUSE_NO_ANSWER;
 1461     }
 1462 
 1463     if (!strcasecmp(code, "ANSWER")) {
 1464       return AST_CAUSE_NORMAL_CLEARING;
 1465     }
 1466 
 1467     if (!strcasecmp(code, "CANCEL")) {
 1468       return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 1469     }
 1470 
 1471     if (!strcasecmp(code, "UNKNOWN")) {
 1472       return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 1473     }
 1474   }
 1475   return AST_CAUSE_NORMAL_CLEARING;
 1476 }
 1477 
 1478 
 1479 /*!
 1480  * \brief  Send a message to a Woomera server.
 1481  */
 1482 #ifdef WOOMERA_PRINTF_DEBUG
 1483 static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...)
 1484 #else
 1485 static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...)
 1486 #endif
 1487 {
 1488   char *stuff;
 1489   int res = 0;
 1490 
 1491   if (fd < 0) {
 1492     if (globals.debug > 4) {
 1493       ast_log(LOG_ERROR, "Not gonna write to fd %d\n", fd);
 1494     }
 1495     return -1;
 1496   }
 1497 
 1498   va_list ap;
 1499   va_start(ap, fmt);
 1500 #ifdef SOLARIS
 1501   stuff = (char *)ast_malloc(10240);
 1502   vsnprintf(stuff, 10240, fmt, ap);
 1503 #else
 1504   res = vasprintf(&stuff, fmt, ap);
 1505 #endif
 1506   va_end(ap);
 1507 
 1508   if (res == -1) {
 1509     ast_log(LOG_ERROR, "Out of memory\n");
 1510   } else {
 1511     res = 0;
 1512     if (profile && globals.debug) {
 1513       if (option_verbose > 2) {
 1514         ast_verbose(WOOMERA_DEBUG_PREFIX "Send Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, stuff);
 1515       }
 1516     }
 1517         res = ast_carefulwrite(fd, stuff, strlen(stuff), 100);
 1518 
 1519 #ifdef WOOMERA_PRINTF_DEBUG
 1520     if (res < 0) {
 1521       ast_log(LOG_ERROR,"%s:%d FAILED fd=%i %s\n", file, line, fd, strerror(errno));
 1522     }
 1523 #endif
 1524     ast_free(stuff);
 1525     }
 1526 
 1527   return res;
 1528 }
 1529 
 1530 
 1531 /*!
 1532  * \brief Lookup a message header by name and return its value (null if not found).
 1533  */
 1534 static char *woomera_message_header(woomera_message *wmsg, char *key)
 1535 {
 1536   int x = 0;
 1537   char *value = NULL;
 1538 
 1539 #if 0
 1540   if (!strcasecmp(wmsg->command,"HANGUP")) {
 1541     ast_log(LOG_NOTICE, "Message Header for HANGUP\n");
 1542     for (x = 0 ; x < wmsg->last ; x++) {
 1543       ast_log(LOG_NOTICE, "Name=%s Value=%s\n",
 1544           wmsg->names[x], wmsg->values[x]);
 1545       if (!strcasecmp(wmsg->names[x], key)) {
 1546         value = wmsg->values[x];
 1547         break;
 1548       }
 1549     }
 1550   }
 1551 #endif
 1552 
 1553   for (x = 0 ; x < wmsg->last ; x++) {
 1554     if (!strcasecmp(wmsg->names[x], key)) {
 1555       value = wmsg->values[x];
 1556       break;
 1557     }
 1558   }
 1559 
 1560   return value;
 1561 }
 1562 
 1563 /*!
 1564  * \brief Queue an event. Used store events that arrive while we are waiting
 1565  * for a command to complete.
 1566  */
 1567 static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
 1568 {
 1569   woomera_message *new, *mptr;
 1570 
 1571   if ((new = ast_malloc(sizeof(woomera_message)))) {
 1572     ast_mutex_lock(&event_queue->lock);
 1573     memcpy(new, wmsg, sizeof(woomera_message));
 1574     new->next = NULL;
 1575     if (!event_queue->head) {
 1576       event_queue->head = new;
 1577     } else {
 1578       for (mptr = event_queue->head; mptr && mptr->next ; mptr = mptr->next);
 1579       mptr->next = new;
 1580     }
 1581     ast_mutex_unlock(&event_queue->lock);
 1582     return 1;
 1583   } else {
 1584     ast_log(LOG_ERROR, "Memory Allocation Error!\n");
 1585   }
 1586 
 1587   return 0;
 1588 }
 1589 
 1590 /*!
 1591  * \brief Remove one event from the queue.
 1592  */
 1593 static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
 1594 {
 1595   woomera_message *mptr = NULL;
 1596 
 1597   ast_mutex_lock(&event_queue->lock);
 1598   if (event_queue->head) {
 1599     mptr = event_queue->head;
 1600     event_queue->head = mptr->next;
 1601   }
 1602 
 1603   if (mptr) {
 1604     memcpy(wmsg, mptr, sizeof(woomera_message));
 1605   }
 1606   ast_mutex_unlock(&event_queue->lock);
 1607 
 1608   if (mptr) {
 1609     ast_free(mptr);
 1610     return 1;
 1611   } else {
 1612     memset(wmsg, 0, sizeof(woomera_message));
 1613   }
 1614 
 1615   return 0;
 1616 }
 1617 
 1618 
 1619 #if 0
 1620 #include <execinfo.h>
 1621 static void print_trace(void)
 1622 {
 1623   int i;
 1624   void *stacktrace[100];
 1625   size_t size;
 1626   char **symbols;
 1627 
 1628   size = backtrace(stacktrace, sizeof(stacktrace)/sizeof(stacktrace[1]));
 1629   symbols = backtrace_symbols(stacktrace, size);
 1630 
 1631   for (i = 0; i < size; i++) {
 1632      ast_log(LOG_ERROR, "%lu, %s\n", pthread_self(), symbols[i]);
 1633 
 1634   }
 1635 
 1636   if (symbols)
 1637         free(symbols);
 1638 
 1639 }
 1640 #endif
 1641 
 1642 
 1643 /*!
 1644  * \brief Read from the socket and parse into a message object.
 1645  * This will block until message is received.
 1646  */
 1647 static int woomera_message_parse(int fd,
 1648                                  woomera_message *wmsg,
 1649                                  int timeout,
 1650                                  woomera_profile *profile,
 1651                                  woomera_event_queue *event_queue)
 1652 {
 1653   char *cur, *cr, *next = NULL, *eor = NULL;
 1654   char buf[2048];
 1655   int res = 0, bytes = 0, sanity = 0;
 1656   struct timeval started, ended;
 1657   int elapsed, loops = 0;
 1658   int fail_timeout = 0;
 1659 
 1660   memset(wmsg, 0, sizeof(woomera_message));
 1661 
 1662   if (fd < 0) {
 1663     return -1;
 1664   }
 1665 
 1666   gettimeofday(&started, NULL);
 1667   memset(buf, 0, sizeof(buf));
 1668 
 1669   /* -ve timeout values indicate that timeouts should be treated as a failure.
 1670    */
 1671   if (timeout < 0) {
 1672     timeout = abs(timeout);
 1673     fail_timeout = 1;
 1674   } else if (timeout == 0) {
 1675     timeout = -1;
 1676   }
 1677 
 1678   while (!(eor = strstr(buf, WOOMERA_RECORD_SEPARATOR))) {
 1679 
 1680     if (!profile->thread_running) {
 1681       return -1;
 1682     }
 1683 
 1684     if (globals.panic > 2) {
 1685       return -1;
 1686     }
 1687 
 1688     res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR);
 1689     if (res < 0) {
 1690       return -1;
 1691     }
 1692 
 1693     if ((res = waitfor_socket(fd, (timeout > 0 ? timeout : 100)) > 0)) {
 1694       res = recv(fd, buf, sizeof(buf), MSG_PEEK);
 1695       if (res == 0) {
 1696         sanity++;
 1697       } else if (res < 0) {
 1698         if (option_verbose > 2) {
 1699           ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} error during packet retry #%d\n", profile->name, loops);
 1700         }
 1701         return res;
 1702 
 1703       } else if (loops && globals.debug) {
 1704         //ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} Didnt get complete packet retry #%d\n", profile->name, loops);
 1705         res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR);
 1706         if (res < 0) {
 1707           return res;
 1708         }
 1709         usleep(100);
 1710       }
 1711 
 1712       if (res > 0) {
 1713         sanity = 0;
 1714       }
 1715     }
 1716 
 1717     if (res < 0) {
 1718       return res;
 1719     }
 1720 
 1721     if (sanity > 1000) {
 1722       if (globals.debug > 2) {
 1723         ast_log(LOG_ERROR, "{%s} Failed Sanity Check! [errors] fd=%d\n",
 1724                 profile->name, fd);
 1725       }
 1726       return -100;
 1727     }
 1728 
 1729     gettimeofday(&ended, NULL);
 1730     elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000));
 1731     if (timeout > 0 && (elapsed > timeout)) {
 1732       return fail_timeout ? -1 : 0;
 1733     }
 1734 
 1735     loops++;
 1736   }
 1737 
 1738   *eor = '\0';
 1739   bytes = strlen(buf) + 4;
 1740 
 1741   memset(buf, 0, sizeof(buf));
 1742   res = read(fd, buf, bytes);
 1743   next = buf;
 1744 
 1745   if (globals.debug) {
 1746     if (option_verbose > 2) {
 1747       ast_verbose(WOOMERA_DEBUG_PREFIX "Receive Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, buf);
 1748     }
 1749   }
 1750 
 1751   while ((cur = next)) {
 1752     if ((cr = strstr(cur, WOOMERA_LINE_SEPARATOR))) {
 1753       *cr = '\0';
 1754       next = cr + (sizeof(WOOMERA_LINE_SEPARATOR) - 1);
 1755       if (!strcmp(next, WOOMERA_RECORD_SEPARATOR)) {
 1756         break;
 1757       }
 1758     }
 1759 
 1760     if (ast_strlen_zero(cur)) {
 1761       break;
 1762     }
 1763 
 1764     if (!wmsg->last) {
 1765       ast_set_flag(wmsg, WFLAG_EXISTS);
 1766       if (!strncasecmp(cur, "EVENT", 5)) {
 1767         cur += 6;
 1768         ast_set_flag(wmsg, WFLAG_EVENT);
 1769 
 1770         if (cur && (cr = strchr(cur, ' '))) {
 1771           char *id;
 1772 
 1773           *cr = '\0';
 1774           cr++;
 1775           id = cr;
 1776           if (cr && (cr = strchr(cr, ' '))) {
 1777             *cr = '\0';
 1778             cr++;
 1779             strncpy(wmsg->command_args, cr, WOOMERA_STRLEN);
 1780           }
 1781           if(id) {
 1782             ast_copy_string(wmsg->callid, id, sizeof(wmsg->callid));
 1783           }
 1784         }
 1785       } else {
 1786         if (cur && (cur = strchr(cur, ' '))) {
 1787           *cur = '\0';
 1788           cur++;
 1789           wmsg->mval = atoi(buf);
 1790         } else {
 1791           ast_log(LOG_NOTICE, "Malformed Message!\n");
 1792           break;
 1793         }
 1794       }
 1795       if (cur) {
 1796         strncpy(wmsg->command, cur, WOOMERA_STRLEN);
 1797       } else {
 1798         ast_log(LOG_NOTICE, "Malformed Message!\n");
 1799         break;
 1800       }
 1801     } else {
 1802       char *name, *val;
 1803       name = cur;
 1804       if ((val = strchr(name, ':'))) {
 1805         *val = '\0';
 1806         val++;
 1807         while (*val == ' ') {
 1808           *val = '\0';
 1809           val++;
 1810         }
 1811         strncpy(wmsg->values[wmsg->last-1], val, WOOMERA_STRLEN);
 1812       }
 1813       strncpy(wmsg->names[wmsg->last-1], name, WOOMERA_STRLEN);
 1814       if (name && val && !strcasecmp(name, "content-type")) {
 1815         ast_set_flag(wmsg, WFLAG_CONTENT);
 1816         bytes = atoi(val);
 1817       }
 1818 
 1819       if (name && val && !strcasecmp(name, "content-length")) {
 1820         ast_set_flag(wmsg, WFLAG_CONTENT);
 1821         bytes = atoi(val);
 1822       }
 1823     }
 1824     wmsg->last++;
 1825 
 1826     if (wmsg->last >= WOOMERA_ARRAY_LEN) {
 1827       ast_log(LOG_NOTICE, "Woomera parse error: index overflow!\n");
 1828       break;
 1829     }
 1830   }
 1831 
 1832   wmsg->last--;
 1833 
 1834   if (bytes && ast_test_flag(wmsg, WFLAG_CONTENT)) {
 1835     int terr;
 1836     terr = read(fd, wmsg->body, (bytes > sizeof(wmsg->body)) ? sizeof(wmsg->body) : bytes);
 1837     if (globals.debug) {
 1838       if (option_verbose > 2) {
 1839         ast_verbose("%s\n", wmsg->body);
 1840       }
 1841     }
 1842   }
 1843 
 1844   if (event_queue && ast_test_flag(wmsg, WFLAG_EVENT)) {
 1845     if (globals.debug) {
 1846       if (option_verbose > 2) {
 1847         ast_verbose(WOOMERA_DEBUG_PREFIX "Queue Event: {%s} [%s]\n", profile->name, wmsg->command);
 1848       }
 1849     }
 1850     /* we don't want events we want a reply so we will stash them for later */
 1851     woomera_enqueue_event(event_queue, wmsg);
 1852 
 1853     /* call ourself recursively to find the reply. we'll keep doing this as long we get events.
 1854      * wmsg will be overwritten but it's ok we just queued it.
 1855      */
 1856     return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
 1857 
 1858   } else if (wmsg->mval > 99 && wmsg->mval < 200) {
 1859     /* reply in the 100's are nice but we need to wait for another reply
 1860      * call ourself recursively to find the reply > 199 and forget this reply.
 1861      */
 1862     return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
 1863   } else {
 1864     return ast_test_flag(wmsg, WFLAG_EXISTS);
 1865   }
 1866 }
 1867 
 1868 
 1869 /*!
 1870  * \brief Block until a message arrives, an error occurs or the call is aborte.
 1871  */
 1872 static int woomera_message_parse_wait(private_object *tech_pvt, woomera_message *wmsg)
 1873 {
 1874   int err = 0;
 1875 
 1876   for (;;) {
 1877 
 1878     if (ast_test_flag(tech_pvt, TFLAG_ABORT)){
 1879       return -1;
 1880     }
 1881 
 1882     err = woomera_message_parse(tech_pvt->command_channel,
 1883                                 wmsg,
 1884                                 100,
 1885                                 tech_pvt->profile,
 1886                                 &tech_pvt->event_queue);
 1887 
 1888     if (err == 0) {
 1889       /* This is a timeout */
 1890       continue;
 1891     }
 1892 
 1893     break;
 1894   }
 1895 
 1896   return err;
 1897 }
 1898 
 1899 
 1900 /*!
 1901  * \brief Create a udp socket for raw audio.
 1902  */
 1903 static int tech_create_read_socket(private_object *tech_pvt)
 1904 {
 1905   int retry=0;
 1906   int ports=0;
 1907 
 1908 retry_udp:
 1909 
 1910   ast_mutex_lock(&globals.woomera_port_lock);
 1911   globals.next_woomera_port++;
 1912   if (globals.next_woomera_port >= woomera_max_media_port) {
 1913     globals.next_woomera_port = woomera_base_media_port;
 1914   }
 1915   tech_pvt->port = globals.next_woomera_port;
 1916   ports++;
 1917   ast_mutex_unlock(&globals.woomera_port_lock);
 1918 
 1919   if ((tech_pvt->udp_socket = create_udp_socket(tech_pvt->profile->audio_ip,
 1920                                                 tech_pvt->port,
 1921                                                 &tech_pvt->udpread, 0)) > -1) {
 1922     struct ast_channel *owner = tech_get_owner(tech_pvt);
 1923     if (owner) {
 1924       owner->fds[0] = tech_pvt->udp_socket;
 1925     } else {
 1926       ast_log(LOG_ERROR, "Tech_pvt has no OWNER! %i\n",__LINE__);
 1927     }
 1928 
 1929   } else {
 1930 
 1931     retry++;
 1932     if (retry <= 10 || errno == EADDRINUSE) {
 1933       if (ports < (woomera_max_media_port - woomera_base_media_port)) {
 1934         goto retry_udp;
 1935       }
 1936     }
 1937 
 1938     if (globals.debug) {
 1939       ast_log(LOG_ERROR,
 1940               "Error Creating udp socket  %s/%i (%p) %s %s %s\n",
 1941               tech_pvt->profile->audio_ip,
 1942               tech_pvt->port,
 1943               tech_pvt,
 1944               tech_pvt->callid,
 1945               ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN",
 1946               strerror(errno));
 1947     }
 1948   }
 1949   return tech_pvt->udp_socket;
 1950 }
 1951 
 1952 /*!
 1953  * \brief Start a call
 1954  */
 1955 static int tech_activate(private_object *tech_pvt)
 1956 {
 1957   int retry_activate_call = 0;
 1958   woomera_message wmsg;
 1959   char *callid;
 1960   int err = 0;
 1961 
 1962   memset(&wmsg, 0, sizeof(wmsg));
 1963 
 1964 retry_activate_again:
 1965 
 1966   if (!tech_pvt) {
 1967     ast_log(LOG_ERROR, "Critical Error: Where's my tech_pvt?\n");
 1968     return -1;
 1969   }
 1970 
 1971   if ((connect_woomera(&tech_pvt->command_channel, tech_pvt->profile, 0)) > -1) {
 1972     if (globals.debug > 2) {
 1973       ast_log(LOG_NOTICE,
 1974               "Connected to woomera! chfd=%i port=%i dir=%s callid=%s Count=%i tpvt=%p\n",
 1975               tech_pvt->command_channel,
 1976               tech_pvt->port,
 1977               ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN",
 1978               ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "N/A" : tech_pvt->callid,
 1979               tech_pvt->call_count,
 1980               tech_pvt);
 1981     }
 1982   } else {
 1983 
 1984     if (retry_activate_call <= 3) {
 1985       retry_activate_call++;
 1986       goto retry_activate_again;
 1987     }
 1988 
 1989     if (globals.debug > 1 && option_verbose > 1) {
 1990       ast_log(LOG_ERROR, "Error: %s call connect to TCP/Woomera Server! tpvt=%p: %s\n",
 1991               ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "Out" : "In",
 1992               tech_pvt, strerror(errno));
 1993     }
 1994     goto tech_activate_failed;
 1995   }
 1996 
 1997   retry_activate_call = 0;
 1998 
 1999   if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
 2000 
 2001     if (strlen(tech_pvt->proto) > 1) {
 2002       if (tech_pvt->vrtp_enable) {
 2003         err = woomera_printf(tech_pvt->profile,
 2004                        tech_pvt->command_channel,
 2005                        "CALL %s:%s%s"
 2006                        "RTP-Audio: %s:%d%s"
 2007                        "RTP-Audio-Format: %s%s"
 2008                        "RTP-Video: %s:%d%s"
 2009                        "RTP-Video-Format: %s%s"
 2010                        "Local-Name: %s!%s%s"
 2011                        "Local-Number:%s%s"
 2012                        "Presentation:%d%s"
 2013                        "Screening:%d%s"
 2014                        "Bearer-Cap:%s%s"
 2015                        "uil1p:%s%s"
 2016                        "RDNIS:%s%s",
 2017                        tech_pvt->proto,
 2018                        tech_pvt->dest,
 2019                        WOOMERA_LINE_SEPARATOR,
 2020                        tech_pvt->profile->audio_ip,
 2021                        tech_pvt->port,
 2022                        WOOMERA_LINE_SEPARATOR,
 2023                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 2024                          WOOMERA_LINE_SEPARATOR,
 2025                        tech_pvt->profile->audio_ip, /* use same ip for video */
 2026                        tech_pvt->vport,
 2027                        WOOMERA_LINE_SEPARATOR,
 2028                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0),
 2029                        WOOMERA_LINE_SEPARATOR,
 2030                        tech_pvt->cid_name,
 2031                        tech_pvt->cid_num,
 2032                        WOOMERA_LINE_SEPARATOR,
 2033                        tech_pvt->cid_num,
 2034                        WOOMERA_LINE_SEPARATOR,
 2035                        (tech_pvt->cid_pres >> 5) & 0x7,
 2036                        WOOMERA_LINE_SEPARATOR,
 2037                        tech_pvt->cid_pres & 0xF,
 2038                        WOOMERA_LINE_SEPARATOR,
 2039                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2040                        WOOMERA_LINE_SEPARATOR,
 2041                        woomera_ast_coding_to_string(tech_pvt->coding),
 2042                        WOOMERA_LINE_SEPARATOR,
 2043                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2044                        WOOMERA_RECORD_SEPARATOR
 2045                       );
 2046       }else if (tech_pvt->rtp_enable) {
 2047         err = woomera_printf(tech_pvt->profile,
 2048                        tech_pvt->command_channel,
 2049                        "CALL %s:%s%s"
 2050                        "RTP-Audio: %s:%d%s"
 2051                        "RTP-Audio-Format: %s%s"
 2052                        "Local-Name: %s!%s%s"
 2053                        "Local-Number:%s%s"
 2054                        "Presentation:%d%s"
 2055                        "Screening:%d%s"
 2056                        "Bearer-Cap:%s%s"
 2057                        "uil1p:%s%s"
 2058                        "RDNIS:%s%s",
 2059                        tech_pvt->proto,
 2060                        tech_pvt->dest,
 2061                        WOOMERA_LINE_SEPARATOR,
 2062                        tech_pvt->profile->audio_ip,
 2063                        tech_pvt->port,
 2064                        WOOMERA_LINE_SEPARATOR,
 2065                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 2066                        WOOMERA_LINE_SEPARATOR,
 2067                        tech_pvt->cid_name,
 2068                        tech_pvt->cid_num,
 2069                        WOOMERA_LINE_SEPARATOR,
 2070                        tech_pvt->cid_num,
 2071                        WOOMERA_LINE_SEPARATOR,
 2072                        (tech_pvt->cid_pres >> 5) & 0x7,
 2073                        WOOMERA_LINE_SEPARATOR,
 2074                        tech_pvt->cid_pres & 0xF,
 2075                        WOOMERA_LINE_SEPARATOR,
 2076                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2077                        WOOMERA_LINE_SEPARATOR,
 2078                        woomera_ast_coding_to_string(tech_pvt->coding),
 2079                        WOOMERA_LINE_SEPARATOR,
 2080                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2081                        WOOMERA_RECORD_SEPARATOR
 2082                       );
 2083       } else {
 2084         err = woomera_printf(tech_pvt->profile,
 2085                        tech_pvt->command_channel,
 2086                        "CALL %s:%s%s"
 2087                        "Raw-Audio: %s:%d%s"
 2088                        "Local-Name: %s!%s%s"
 2089                        "Local-Number:%s%s"
 2090                        "Presentation:%d%s"
 2091                        "Screening:%d%s"
 2092                        "Bearer-Cap:%s%s"
 2093                        "uil1p:%s%s"
 2094                        "RDNIS:%s%s",
 2095                        tech_pvt->proto,
 2096                        tech_pvt->dest,
 2097                        WOOMERA_LINE_SEPARATOR,
 2098                        tech_pvt->profile->audio_ip,
 2099                        tech_pvt->port,
 2100                        WOOMERA_LINE_SEPARATOR,
 2101                        tech_pvt->cid_name,
 2102                        tech_pvt->cid_num,
 2103                        WOOMERA_LINE_SEPARATOR,
 2104                        tech_pvt->cid_num,
 2105                        WOOMERA_LINE_SEPARATOR,
 2106                        (tech_pvt->cid_pres >> 5) & 0x7,
 2107                        WOOMERA_LINE_SEPARATOR,
 2108                        tech_pvt->cid_pres & 0xF,
 2109                        WOOMERA_LINE_SEPARATOR,
 2110                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2111                        WOOMERA_LINE_SEPARATOR,
 2112                        woomera_ast_coding_to_string(tech_pvt->coding),
 2113                        WOOMERA_LINE_SEPARATOR,
 2114                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2115                        WOOMERA_RECORD_SEPARATOR
 2116                       );
 2117       }
 2118     }
 2119     else
 2120     {
 2121       if (tech_pvt->vrtp_enable) {
 2122         err = woomera_printf(tech_pvt->profile,
 2123                        tech_pvt->command_channel,
 2124                        "CALL %s%s"
 2125                        "RTP-Audio: %s:%d%s"
 2126                        "RTP-Audio-Format: %s%s"
 2127                        "RTP-Video: %s:%d%s"
 2128                        "RTP-Video-Format: %s%s"
 2129                        "Local-Name: %s!%s%s"
 2130                        "Local-Number:%s%s"
 2131                        "Presentation:%d%s"
 2132                        "Screening:%d%s"
 2133                        "Bearer-Cap:%s%s"
 2134                        "uil1p:%s%s"
 2135                        "RDNIS:%s%s",
 2136                        tech_pvt->dest,
 2137                        WOOMERA_LINE_SEPARATOR,
 2138                        tech_pvt->profile->audio_ip,
 2139                        tech_pvt->port,
 2140                        WOOMERA_LINE_SEPARATOR,
 2141                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 2142                          WOOMERA_LINE_SEPARATOR,
 2143                        tech_pvt->profile->audio_ip,
 2144                        tech_pvt->vport,
 2145                        WOOMERA_LINE_SEPARATOR,
 2146                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0),
 2147                        WOOMERA_LINE_SEPARATOR,
 2148                        tech_pvt->cid_name,
 2149                        tech_pvt->cid_num,
 2150                        WOOMERA_LINE_SEPARATOR,
 2151                        tech_pvt->cid_num,
 2152                        WOOMERA_LINE_SEPARATOR,
 2153                        (tech_pvt->cid_pres >> 5) & 0x7,
 2154                        WOOMERA_LINE_SEPARATOR,
 2155                        tech_pvt->cid_pres & 0xF,
 2156                        WOOMERA_LINE_SEPARATOR,
 2157                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2158                        WOOMERA_LINE_SEPARATOR,
 2159                        woomera_ast_coding_to_string(tech_pvt->coding),
 2160                        WOOMERA_LINE_SEPARATOR,
 2161                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2162                        WOOMERA_RECORD_SEPARATOR
 2163                       );
 2164       } else if (tech_pvt->rtp_enable) {
 2165         err = woomera_printf(tech_pvt->profile,
 2166                        tech_pvt->command_channel,
 2167                        "CALL %s%s"
 2168                        "RTP-Audio: %s:%d%s"
 2169                        "RTP-Audio-Format: %s%s"
 2170                        "Local-Name: %s!%s%s"
 2171                        "Local-Number:%s%s"
 2172                        "Presentation:%d%s"
 2173                        "Screening:%d%s"
 2174                        "Bearer-Cap:%s%s"
 2175                        "uil1p:%s%s"
 2176                        "RDNIS:%s%s",
 2177                        tech_pvt->dest,
 2178                        WOOMERA_LINE_SEPARATOR,
 2179                        tech_pvt->profile->audio_ip,
 2180                        tech_pvt->port,
 2181                        WOOMERA_LINE_SEPARATOR,
 2182                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 2183                        WOOMERA_LINE_SEPARATOR,
 2184                        tech_pvt->cid_name,
 2185                        tech_pvt->cid_num,
 2186                        WOOMERA_LINE_SEPARATOR,
 2187                        tech_pvt->cid_num,
 2188                        WOOMERA_LINE_SEPARATOR,
 2189                        (tech_pvt->cid_pres >> 5) & 0x7,
 2190                        WOOMERA_LINE_SEPARATOR,
 2191                        tech_pvt->cid_pres & 0xF,
 2192                        WOOMERA_LINE_SEPARATOR,
 2193                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2194                        WOOMERA_LINE_SEPARATOR,
 2195                        woomera_ast_coding_to_string(tech_pvt->coding),
 2196                        WOOMERA_LINE_SEPARATOR,
 2197                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2198                        WOOMERA_RECORD_SEPARATOR
 2199                       );
 2200       } else {
 2201         err = woomera_printf(tech_pvt->profile,
 2202                        tech_pvt->command_channel,
 2203                        "CALL %s%s"
 2204                        "Raw-Audio: %s:%d%s"
 2205                        "Local-Name: %s!%s%s"
 2206                        "Local-Number:%s%s"
 2207                        "Presentation:%d%s"
 2208                        "Screening:%d%s"
 2209                        "Bearer-Cap:%s%s"
 2210                        "uil1p:%s%s"
 2211                        "RDNIS:%s%s",
 2212                        tech_pvt->dest,
 2213                        WOOMERA_LINE_SEPARATOR,
 2214                        tech_pvt->profile->audio_ip,
 2215                        tech_pvt->port,
 2216                        WOOMERA_LINE_SEPARATOR,
 2217                        tech_pvt->cid_name,
 2218                        tech_pvt->cid_num,
 2219                        WOOMERA_LINE_SEPARATOR,
 2220                        tech_pvt->cid_num,
 2221                        WOOMERA_LINE_SEPARATOR,
 2222                        (tech_pvt->cid_pres >> 5) & 0x7,
 2223                        WOOMERA_LINE_SEPARATOR,
 2224                        tech_pvt->cid_pres & 0xF,
 2225                        WOOMERA_LINE_SEPARATOR,
 2226                        woomera_ast_transfercap_to_string(tech_pvt->capability),
 2227                        WOOMERA_LINE_SEPARATOR,
 2228                        woomera_ast_coding_to_string(tech_pvt->coding),
 2229                        WOOMERA_LINE_SEPARATOR,
 2230                        tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
 2231                        WOOMERA_RECORD_SEPARATOR
 2232                       );
 2233       }
 2234     }
 2235 
 2236      if (err < 0) {
 2237       if (globals.debug > 2) {
 2238         ast_log(LOG_NOTICE, "Outbound call failed, -write msg Call %s tpvt=%p\n",
 2239                 tech_pvt->callid, tech_pvt);
 2240       }
 2241       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2242       goto tech_activate_failed;
 2243      }
 2244 
 2245      err = woomera_message_parse_wait(tech_pvt, &wmsg);
 2246      if (err < 0) {
 2247       if (globals.debug > 2) {
 2248         ast_log(LOG_NOTICE, "Outbound call failed, -wait parse Call %s tpvt=%p\n",
 2249                 tech_pvt->callid, tech_pvt);
 2250       }
 2251       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2252       goto tech_activate_failed;
 2253        }
 2254 
 2255      if (woomera_message_reply_ok(&wmsg) != 0) {
 2256       if (globals.debug > 2) {
 2257         ast_log(LOG_NOTICE, "Outbound call failed, got bad reply. Call %s tpvt=%p response=%d\n",
 2258                 tech_pvt->callid, tech_pvt, wmsg.mval);
 2259       }
 2260       if (wmsg.mval == 503) {
 2261         ast_queue_control(tech_pvt->owner, AST_CONTROL_CONGESTION);
 2262       }
 2263       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2264      }
 2265 
 2266      callid = woomera_message_header(&wmsg, "Unique-Call-Id");
 2267      if (callid) {
 2268       ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid));
 2269      }
 2270 
 2271   } else {
 2272     ast_set_flag(tech_pvt, TFLAG_PARSE_INCOMING);
 2273     if (globals.debug > 2) {
 2274       ast_log(LOG_NOTICE, "Incoming Call %s tpvt=%p\n",
 2275               tech_pvt->callid, tech_pvt);
 2276     }
 2277 
 2278     err = woomera_printf(tech_pvt->profile,
 2279                          tech_pvt->command_channel,
 2280                          "PROCEED %s%s"
 2281                          "Unique-Call-Id: %s%s",
 2282                          tech_pvt->callid,
 2283                          WOOMERA_LINE_SEPARATOR,
 2284                          tech_pvt->callid,
 2285                          WOOMERA_RECORD_SEPARATOR);
 2286 
 2287      if (err < 0) {
 2288       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2289       goto tech_activate_failed;
 2290      }
 2291 
 2292      err = woomera_message_parse_wait(tech_pvt, &wmsg);
 2293      if (err < 0) {
 2294       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2295       goto tech_activate_failed;
 2296      }
 2297 
 2298      if (woomera_message_reply_ok(&wmsg) != 0) {
 2299       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2300       /* Do not hangup on main because
 2301        * socket connection has been
 2302        * established */
 2303      }
 2304   }
 2305 
 2306   if (globals.debug > 2) {
 2307     ast_log(LOG_NOTICE, "TECH ACTIVATE OK tech_pvt=%p\n", tech_pvt);
 2308   }
 2309   return 0;
 2310 
 2311 tech_activate_failed:
 2312 
 2313   if (globals.debug > 2) {
 2314     ast_log(LOG_NOTICE, "TECH ACTIVATE FAILED tech_pvt=%p\n", tech_pvt);
 2315   }
 2316 
 2317   woomera_close_socket(&tech_pvt->command_channel);
 2318   ast_set_flag(tech_pvt, TFLAG_ABORT);
 2319 
 2320   /* At this point we cannot estabilsh a woomera
 2321    * socket to the server.  The server still doesnt know
 2322    * about the incoming call that is now pending.
 2323    * We must send a message to server to hangup the call */
 2324 
 2325   if (globals.debug > 2) {
 2326     ast_log(LOG_NOTICE, "Error: %s Call %s tpvt=%p Failed!\n",
 2327             ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN",
 2328             tech_pvt->callid, tech_pvt);
 2329   }
 2330 
 2331   return -1;
 2332 }
 2333 
 2334 
 2335 /*!
 2336  * Initialise pvt object, called at the start of a call.
 2337  */
 2338 static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags)
 2339 {
 2340   struct sockaddr_in us;
 2341   struct ast_channel *self = tech_get_owner(tech_pvt);
 2342 
 2343   gettimeofday(&tech_pvt->started, NULL);
 2344 
 2345   if (profile) {
 2346     tech_pvt->profile = profile;
 2347   } else {
 2348     ast_log(LOG_ERROR, "Tech init no profile!\n");
 2349     ast_set_flag(tech_pvt, TFLAG_ABORT);
 2350     return -1;
 2351   }
 2352 
 2353   if (profile && profile->send_dtmf_enable) {
 2354     tech_pvt->send_dtmf_enable = 1;
 2355   } else {
 2356     tech_pvt->send_dtmf_enable = 0;
 2357   }
 2358 
 2359   if (profile && profile->rtp_enable) {
 2360     tech_pvt->rtp_enable = 1;
 2361   } else {
 2362     tech_pvt->rtp_enable = 0;
 2363   }
 2364 
 2365   if (profile && profile->vrtp_enable) {
 2366     tech_pvt->vrtp_enable = 1;
 2367   } else {
 2368     tech_pvt->vrtp_enable = 0;
 2369   }
 2370 
 2371   if (profile && profile->bridge_enable) {
 2372     tech_pvt->bridge_enable = 1;
 2373   } else {
 2374     tech_pvt->bridge_enable = 0;
 2375   }
 2376 
 2377   ast_set_flag(tech_pvt, flags);
 2378 
 2379   if (tech_pvt->rtp_enable) {
 2380     tech_pvt->rtp = create_rtp(tech_pvt->profile->audio_ip);
 2381     if (tech_pvt->rtp) {
 2382       self->fds[0] = ast_rtp_fd(tech_pvt->rtp);
 2383       ast_rtp_get_us(tech_pvt->rtp, &us);
 2384       tech_pvt->port = ntohs(us.sin_port);
 2385       if (globals.debug > 2) {
 2386         ast_log(LOG_DEBUG, "Created rtp audio. port=%d\n", tech_pvt->port);
 2387       }
 2388     } else {
 2389       ast_log(LOG_ERROR, "Failed to create rtp audio\n");
 2390       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2391       return -1;
 2392     }
 2393 
 2394     if (tech_pvt->vrtp_enable) {
 2395       tech_pvt->vrtp = create_rtp(tech_pvt->profile->audio_ip); /* same ip for both */
 2396       if (tech_pvt->vrtp) {
 2397         self->fds[1] = ast_rtp_fd(tech_pvt->vrtp);
 2398         ast_rtp_get_us(tech_pvt->vrtp, &us);
 2399         tech_pvt->vport = ntohs(us.sin_port);
 2400         if (globals.debug > 2) {
 2401           ast_log(LOG_DEBUG, "Created rtp video. port=%d\n", tech_pvt->vport);
 2402         }
 2403       } else {
 2404         ast_log(LOG_ERROR, "Failed to create rtp video\n");
 2405         ast_set_flag(tech_pvt, TFLAG_ABORT);
 2406         return -1;
 2407       }
 2408     }
 2409 
 2410   } else {
 2411     if (tech_pvt->udp_socket < 0) {
 2412       int rc;
 2413       rc = tech_create_read_socket(tech_pvt);
 2414       if (rc < 0) {
 2415         ast_log(LOG_ERROR, "Failed to create UDP Socket (%p)! %s\n",
 2416                 tech_pvt, strerror(errno));
 2417         ast_set_flag(tech_pvt, TFLAG_ABORT);
 2418         return -1;
 2419       }
 2420     }
 2421   }
 2422 
 2423   ast_set_flag(tech_pvt, flags);
 2424 
 2425   tech_pvt->capability = self->transfercapability;
 2426 
 2427   tech_pvt->coding = profile->coding;
 2428   tech_pvt->videocoding = profile->videocoding;
 2429   self->nativeformats = tech_pvt->coding | tech_pvt->videocoding;
 2430   self->writeformat = self->rawwriteformat = self->readformat = tech_pvt->coding | tech_pvt->videocoding;
 2431   tech_pvt->frame.subclass = tech_pvt->coding | tech_pvt->videocoding;
 2432 
 2433   ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER);
 2434   ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED);
 2435   ast_clear_flag(tech_pvt, TFLAG_ANSWER_RECEIVED);
 2436 
 2437   if (profile && profile->faxdetect) {
 2438     tech_pvt->faxdetect = 1;
 2439   }
 2440 
 2441   if (profile->dtmf_enable) {
 2442 
 2443     tech_pvt->dsp_features = 0;
 2444     tech_pvt->dsp = ast_dsp_new();
 2445     if (tech_pvt->dsp) {
 2446 #if 0
 2447       i->dsp_features = features & ~DSP_PROGRESS_TALK;
 2448 
 2449       /* We cannot do progress detection until receives PROGRESS message */
 2450       if (i->outgoing && (i->sig == SIG_PRI)) {
 2451         /* Remember requested DSP features, don't treat
 2452         talking as ANSWER */
 2453         features = 0;
 2454       }
 2455 #endif
 2456       tech_pvt->dsp_features |= DSP_FEATURE_DTMF_DETECT;
 2457       //tech_pvt->dsp_features |= DSP_FEATURE_BUSY_DETECT;
 2458       //tech_pvt->dsp_features |= DSP_FEATURE_CALL_PROGRESS;
 2459       if (tech_pvt->faxdetect) {
 2460         tech_pvt->dsp_features |= DSP_FEATURE_FAX_DETECT;
 2461       }
 2462       ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
 2463       ast_dsp_digitmode(tech_pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
 2464       tech_pvt->ast_dsp = 1;
 2465 #if 0
 2466       if (!ast_strlen_zero(progzone))
 2467         ast_dsp_set_call_progress_zone(tech_pvt->dsp, progzone);
 2468       if (i->busydetect && CANBUSYDETECT(i)) {
 2469         ast_dsp_set_busy_count(tech_pvt->dsp, i->busycount);
 2470         ast_dsp_set_busy_pattern(tech_pvt->dsp, i->busy_tonelength, i->busy_quietlength);
 2471       }
 2472 #endif
 2473     }
 2474   }
 2475 
 2476   if (profile->jb_enable) {
 2477 #if defined AST_JB
 2478     /* Assign default jb conf to the new zt_pvt */
 2479     memcpy(&tech_pvt->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));
 2480     ast_jb_configure(self, &tech_pvt->jbconf);
 2481 
 2482     if (globals.debug > 2 && option_verbose > 10) {
 2483       ast_log(LOG_NOTICE, "%s: Cfg JitterBuffer (F=%i MS=%li Rs=%li Impl=%s)\n",
 2484           self->name,
 2485           tech_pvt->jbconf.flags,
 2486           tech_pvt->jbconf.max_size,
 2487           tech_pvt->jbconf.resync_threshold,
 2488           tech_pvt->jbconf.impl);
 2489     }
 2490 #else
 2491     ast_log(LOG_ERROR, "Asterisk Jitter Buffer Not Compiled!\n");
 2492 #endif
 2493   }
 2494 
 2495   /* Asterisk allows approx 1 nanosecond to try and establish a connetion here.
 2496    * Now asterisk, will not enforce a lock while we work
 2497    * and after even a 1 second delay it will give up on the lock and mess everything up
 2498    * This stems from the fact that asterisk will scan it's list of channels constantly for
 2499    * reasons like tab completion and cli output.
 2500    *
 2501    * Anyway, since we've already spent that nanosecond with the previous line of code
 2502    * tech_create_read_socket(tech_pvt); to setup a read socket
 2503    * which, by the way, asterisk insists we have before going any furthur.
 2504    * So, in short, we are between a rock and a hard place and asterisk wants us to open a socket here
 2505    * but it too impaitent to wait for us to make sure it's ready so in the case of outgoing calls
 2506    * we will defer the rest of the socket establishment process to the monitor thread.
 2507    */
 2508   if (globals.more_threads) {
 2509     int err;
 2510     ast_set_flag(tech_pvt, TFLAG_ACTIVATE);
 2511     /* we're gonna try "wasting" a thread to do a better realtime monitoring */
 2512     err = launch_tech_thread(tech_pvt);
 2513     if (err) {
 2514       ast_log(LOG_ERROR, "Failed to launch tech control thread\n");
 2515       ast_clear_flag(tech_pvt, TFLAG_ACTIVATE);
 2516       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2517       return -1;
 2518     }
 2519 
 2520   } else {
 2521     if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
 2522       ast_set_flag(tech_pvt, TFLAG_ACTIVATE);
 2523     } else {
 2524       tech_activate(tech_pvt);
 2525     }
 2526   }
 2527 
 2528   if (globals.debug > 2) {
 2529     ast_log(LOG_NOTICE, "TECH INIT tech_pvt=%p c=%p (use=%i)\n",
 2530       tech_pvt, tech_pvt->owner,usecount());
 2531   }
 2532 
 2533   return 0;
 2534 }
 2535 
 2536 
 2537 /*!
 2538  * \brief End a call.
 2539  */
 2540 static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner)
 2541 {
 2542   ASTOBJ_CONTAINER_UNLINK(&private_object_list, tech_pvt);
 2543 
 2544   ast_set_flag(tech_pvt, TFLAG_DESTROY);
 2545   ast_set_flag(tech_pvt, TFLAG_ABORT);
 2546 
 2547   if (globals.debug > 2) {
 2548     ast_log(LOG_NOTICE, "Tech Destroy callid=%s tpvt=%p %s/%d\n",
 2549             tech_pvt->callid,
 2550             tech_pvt,
 2551             tech_pvt->profile ? tech_pvt->profile->audio_ip : "NA",
 2552             tech_pvt->port);
 2553   }
 2554 
 2555   if (tech_pvt->profile && tech_pvt->command_channel > -1) {
 2556 
 2557     if (globals.debug > 1 && option_verbose > 1) {
 2558       ast_log(LOG_NOTICE, "Tech Destroy sending HANGUP %s\n", tech_pvt->callid);
 2559     }
 2560     woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 2561                    "HANGUP %s%s"
 2562                    "cause: %s%s"
 2563                    "Q931-Cause-Code: %d%s"
 2564                    "Reason-String: %s%s"
 2565                    "Reason: %d%s"
 2566                    "Unique-Call-Id: %s%s",
 2567                    tech_pvt->callid,
 2568                    WOOMERA_LINE_SEPARATOR,
 2569                    tech_pvt->ds,
 2570                    WOOMERA_LINE_SEPARATOR,
 2571                    tech_pvt->pri_cause,
 2572                    WOOMERA_LINE_SEPARATOR,
 2573                    tech_pvt->ds,
 2574                    WOOMERA_LINE_SEPARATOR,
 2575                    tech_pvt->pri_cause,
 2576                    WOOMERA_LINE_SEPARATOR,
 2577                    tech_pvt->callid,
 2578                    WOOMERA_RECORD_SEPARATOR);
 2579 
 2580     woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 2581                   "BYE%s"
 2582                   "Unique-Call-Id: %s%s",
 2583                    WOOMERA_LINE_SEPARATOR,
 2584                    tech_pvt->callid,
 2585                    WOOMERA_RECORD_SEPARATOR);
 2586 
 2587     woomera_close_socket(&tech_pvt->command_channel);
 2588   }
 2589 
 2590   woomera_close_socket(&tech_pvt->command_channel);
 2591 
 2592   if (tech_pvt->rtp_enable) {
 2593     if (tech_pvt->rtp) {
 2594       if (globals.debug > 2) {
 2595         ast_log(LOG_NOTICE,"Tech Destroy ending audio rtp session\n");
 2596       }
 2597       ast_rtp_destroy(tech_pvt->rtp);
 2598     }
 2599     if (tech_pvt->vrtp) {
 2600       if (globals.debug > 2) {
 2601         ast_log(LOG_NOTICE,"Tech Destroy ending video rtp session\n");
 2602       }
 2603       ast_rtp_destroy(tech_pvt->vrtp);
 2604     }
 2605   } else {
 2606     woomera_close_socket(&tech_pvt->udp_socket);
 2607   }
 2608 
 2609   /* Tech profile is allowed to be null in case the call
 2610    * is blocked from the call_count */
 2611 
 2612 #if 0
 2613   ast_log(LOG_NOTICE, "---- Call END %p %s ----------------------------\n",
 2614           tech_pvt, tech_pvt->callid);
 2615 #endif
 2616 
 2617   if (owner) {
 2618     if (globals.debug > 2) {
 2619       ast_log(LOG_NOTICE, "Tech Destroy doing AST HANGUP!\n");
 2620     }
 2621     owner->tech_pvt = NULL;
 2622     tech_pvt->owner = NULL;
 2623     ast_hangup(owner);
 2624   }
 2625   tech_pvt->owner = NULL;
 2626 
 2627   tech_count--;
 2628   if (tech_pvt->dsp) {
 2629     tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
 2630     ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
 2631     tech_pvt->ast_dsp = 0;
 2632     ast_free(tech_pvt->dsp);
 2633     tech_pvt->dsp = NULL;
 2634   }
 2635 
 2636   if (globals.debug > 2) {
 2637     ast_log(LOG_NOTICE, "DESTROY Exit tech_pvt=%p  (use=%i)\n",
 2638             tech_pvt, usecount());
 2639   }
 2640 
 2641   ast_mutex_destroy(&tech_pvt->iolock);
 2642   ast_mutex_destroy(&tech_pvt->event_queue.lock);
 2643 
 2644   if (tech_pvt->cid_rdnis) {
 2645     ast_free(tech_pvt->cid_rdnis);
 2646     tech_pvt->cid_rdnis = NULL;
 2647   }
 2648 
 2649   ast_free(tech_pvt);
 2650 
 2651   ast_mutex_lock(&usecnt_lock);
 2652   usecnt--;
 2653   ast_mutex_unlock(&usecnt_lock);
 2654 }
 2655 
 2656 #if 0
 2657 
 2658 static int waitfor_socket(int fd, int timeout)
 2659 {
 2660   struct pollfd pfds[1];
 2661   int res;
 2662   int errflags = (POLLERR | POLLHUP | POLLNVAL);
 2663 
 2664   if (fd < 0) {
 2665     return -1;
 2666   }
 2667 
 2668   memset(&pfds[0], 0, sizeof(pfds[0]));
 2669   pfds[0].fd = fd;
 2670   pfds[0].events = POLLIN | errflags;
 2671   res = poll(pfds, 1, timeout);
 2672   if (res > 0) {
 2673     if ((pfds[0].revents & errflags)) {
 2674       res = -1;
 2675     } else if ((pfds[0].revents & POLLIN)) {
 2676       res = 1;
 2677     } else {
 2678       ast_log(LOG_ERROR, "System Error: Poll Event Error no event!\n");
 2679       res = -1;
 2680     }
 2681   }
 2682 
 2683   return res;
 2684 }
 2685 
 2686 #else
 2687 
 2688 /*!
 2689  *\brief  Wait for an event on a socket.
 2690  * \return 1  - event ready
 2691  * \return 0  - timeout
 2692  * \return -1 - error
 2693  */
 2694 static int waitfor_socket(int fd, int timeout)
 2695 {
 2696   struct pollfd pfds[1];
 2697   int res;
 2698 
 2699   if (fd < 0) {
 2700     return -1;
 2701   }
 2702 
 2703   memset(&pfds[0], 0, sizeof(pfds[0]));
 2704   pfds[0].fd = fd;
 2705   pfds[0].events = POLLIN | POLLERR;
 2706   res = poll(pfds, 1, timeout);
 2707   if (res > 0) {
 2708     if ((pfds[0].revents & POLLERR)) {
 2709       res = -1;
 2710     } else if((pfds[0].revents & POLLIN)) {
 2711       res = 1;
 2712     } else {
 2713       res = -1;
 2714     }
 2715   }
 2716 
 2717   return res;
 2718 }
 2719 
 2720 #endif
 2721 
 2722 /*!
 2723  * \brief Per call event monitoring.
 2724  */
 2725 static void *tech_monitor_thread(void *obj)
 2726 {
 2727   private_object *tech_pvt;
 2728   woomera_message wmsg;
 2729   char tcallid[WOOMERA_STRLEN];
 2730   int aborted = 0;
 2731 
 2732   int res = 0;
 2733 
 2734   tech_pvt = obj;
 2735 
 2736   if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) {
 2737     ast_log(LOG_NOTICE, "Tech Monitor: Call stopped before thread up!\n");
 2738     return NULL;
 2739   }
 2740 
 2741   memset(tcallid, 0, sizeof(tcallid));
 2742   memset(&wmsg, 0, sizeof(wmsg));
 2743 
 2744   if (globals.debug > 2) {
 2745     ast_log(LOG_NOTICE, "IN THREAD %s rxgain=%f txgain=%f\n",
 2746             tech_pvt->callid,
 2747             tech_pvt->profile->rxgain_val,
 2748             tech_pvt->profile->txgain_val);
 2749   }
 2750   ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 2751   if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
 2752     tech_pvt->profile->call_out++;
 2753   } else {
 2754     tech_pvt->profile->call_in++;
 2755   }
 2756   tech_pvt->profile->call_count++;
 2757   ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 2758 
 2759   for(;;) {
 2760 
 2761     if (globals.panic) {
 2762       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2763     }
 2764 
 2765     if (!tech_pvt->owner) {
 2766       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2767       if (globals.debug > 2) {
 2768         ast_log(LOG_NOTICE, "Thread lost Owner Chan %s %p\n",
 2769                 tech_pvt->callid,
 2770                 tech_pvt);
 2771       }
 2772     }
 2773 
 2774     /* finish the deferred stuff asterisk won't allow us to do live */
 2775     if (ast_test_flag(tech_pvt, TFLAG_ABORT)) {
 2776       int ast_hangup = 0;
 2777       struct woomera_profile *profile = tech_pvt->profile;;
 2778 
 2779       if (globals.debug > 2) {
 2780         ast_log(LOG_NOTICE, "ABORT GOT HANGUP CmdCh=%i %s %s/%i\n",
 2781                 tech_pvt->command_channel, tech_pvt->callid,
 2782                 tech_pvt->profile ? tech_pvt->profile->audio_ip : "N/A",
 2783                 tech_pvt->port);
 2784       }
 2785 
 2786       aborted |= 1;
 2787 
 2788       /* Check for queued events, looking for HANGUP messages,
 2789          so we can return proper hangup cause */
 2790       for (;;) {
 2791         if ((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg))) {
 2792           woomera_check_event(tech_pvt, res, &wmsg);
 2793         } else {
 2794           break;
 2795         }
 2796       }
 2797 
 2798       ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 2799       tech_pvt->profile->call_count--;
 2800       ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 2801 
 2802       if (tech_pvt->profile && tech_pvt->command_channel > -1) {
 2803 
 2804         if (globals.debug > 2) {
 2805           ast_log(LOG_NOTICE, "ABORT sent HANGUP on %s %p\n",
 2806                   tech_pvt->callid,
 2807                   tech_pvt);
 2808         }
 2809         aborted |= 2;
 2810         woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 2811                        "HANGUP %s%s"
 2812                        "cause: %s%s"
 2813                        "Q931-Cause-Code: %d%s"
 2814                          "Reason-String: %s%s"
 2815                        "Reason: %d%s"
 2816                        "Unique-Call-Id: %s%s",
 2817                        tech_pvt->callid,
 2818                        WOOMERA_LINE_SEPARATOR,
 2819                        tech_pvt->ds,
 2820                        WOOMERA_LINE_SEPARATOR,
 2821                        tech_pvt->pri_cause,
 2822                        WOOMERA_LINE_SEPARATOR,
 2823                          tech_pvt->ds,
 2824                        WOOMERA_LINE_SEPARATOR,
 2825                        tech_pvt->pri_cause,
 2826                        WOOMERA_LINE_SEPARATOR,
 2827                        tech_pvt->callid,
 2828                        WOOMERA_RECORD_SEPARATOR);
 2829 
 2830         woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 2831                        "BYE%s"
 2832                        "Unique-Call-Id: %s%s",
 2833                        WOOMERA_LINE_SEPARATOR,
 2834                        tech_pvt->callid,
 2835                        WOOMERA_RECORD_SEPARATOR);
 2836 
 2837         woomera_close_socket(&tech_pvt->command_channel);
 2838       }
 2839 
 2840       if (tech_pvt->rtp_enable) {
 2841         if (tech_pvt->rtp) {
 2842           if (globals.debug > 2) {
 2843             ast_log(LOG_NOTICE, "Tech Thread - ending audio rtp session\n");
 2844           }
 2845           ast_rtp_destroy(tech_pvt->rtp);
 2846           tech_pvt->rtp = 0;
 2847         }
 2848         if (tech_pvt->vrtp) {
 2849           if (globals.debug > 2) {
 2850             ast_log(LOG_NOTICE, "Tech Thread - ending video rtp session\n");
 2851           }
 2852           ast_rtp_destroy(tech_pvt->vrtp);
 2853           tech_pvt->vrtp = 0;
 2854         }
 2855       } else {
 2856         woomera_close_socket(&tech_pvt->udp_socket);
 2857       }
 2858 
 2859       if (globals.debug > 2) {
 2860         ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel\n");
 2861       }
 2862       ast_mutex_lock(&tech_pvt->iolock);
 2863       while (tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) {
 2864         if (globals.debug > 2) {
 2865           ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel - deadlock avoidance\n");
 2866         }
 2867         DEADLOCK_AVOIDANCE(&tech_pvt->iolock);
 2868       }
 2869 
 2870       if (tech_pvt->owner) {
 2871         struct ast_channel *owner = tech_pvt->owner;
 2872         if (ast_test_flag(tech_pvt, TFLAG_PBX) || owner->pbx) {
 2873           aborted |= 4;
 2874 
 2875           if (globals.debug > 2) {
 2876             ast_log(LOG_NOTICE, "ABORT calling hangup on %s t=%p c=%p UP=%d\n",
 2877                     tech_pvt->callid,
 2878                     tech_pvt,
 2879                     owner,
 2880                     ast_test_flag(tech_pvt, TFLAG_UP));
 2881           }
 2882 
 2883           /* Issue a softhangup */
 2884           if (globals.debug > 2) {
 2885             ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel - soft hangup\n");
 2886           }
 2887 
 2888 #if defined (AST14) || defined (AST16)
 2889           if (ast_test_flag(owner, AST_FLAG_BLOCKING)) {
 2890             int cnt = 0;
 2891             while (!owner->blocker) {
 2892               ast_log(LOG_ERROR, "Woomera: BLOCKER Set but no blocker!\n");
 2893               usleep(50);
 2894               cnt++;
 2895             }
 2896             if (cnt) {
 2897               ast_log(LOG_ERROR, "Woomera: BLOCKER Set Got Blocker %s!\n",
 2898                       owner->blockproc);
 2899             }
 2900           }
 2901 #endif
 2902 
 2903           ast_softhangup_nolock(owner, AST_SOFTHANGUP_DEV);
 2904           ast_clear_flag(tech_pvt, TFLAG_INTHREAD);
 2905           ast_set_flag(tech_pvt, TFLAG_AST_HANGUP);
 2906           tech_pvt->owner = NULL;
 2907 
 2908           /* After this point tech_pvt point should not be touched */
 2909           ast_hangup = 1;
 2910 
 2911         } else {
 2912           if (globals.debug > 2) {
 2913             ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - owner=%p pbx=%i \n",
 2914                     owner, ast_test_flag(tech_pvt, TFLAG_PBX));
 2915           }
 2916         }
 2917         my_ast_channel_unlock(owner);
 2918       }
 2919 
 2920       ast_mutex_unlock(&tech_pvt->iolock);
 2921 
 2922       ast_mutex_lock(&profile->call_count_lock);
 2923       profile->call_end++;
 2924       ast_mutex_unlock(&profile->call_count_lock);
 2925 
 2926       /* Wait for tech_hangup to set this, so there is on
 2927        * race condition with asterisk
 2928        */
 2929       //ast_set_flag(tech_pvt, TFLAG_DESTROY);
 2930 
 2931       if (ast_hangup) {
 2932         ast_mutex_lock(&profile->call_count_lock);
 2933         profile->call_ast_hungup++;
 2934         ast_mutex_unlock(&profile->call_count_lock);
 2935 
 2936         /* Let Asterisk tech_hangup destroy tech_pvt */
 2937         goto tech_thread_exit;
 2938 
 2939       } else {
 2940         ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 2941         tech_pvt->profile->call_abort++;
 2942         ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 2943 
 2944         if (globals.debug > 2) {
 2945           ast_log(LOG_NOTICE, "NOTE: Skipping Wait on destroy timedout! %s tech_pvt=%p\n",
 2946                   tech_pvt->callid, tech_pvt);
 2947         }
 2948         ast_set_flag(tech_pvt, TFLAG_DESTROY);
 2949       }
 2950 
 2951       aborted |= 8;
 2952       tech_destroy(tech_pvt, tech_get_owner(tech_pvt));
 2953       tech_pvt = NULL;
 2954       break;
 2955     }
 2956 
 2957     if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP) || !tech_pvt->owner) {
 2958       ast_set_flag(tech_pvt, TFLAG_DESTROY);
 2959       ast_set_flag(tech_pvt, TFLAG_ABORT);
 2960       if (globals.debug > 2) {
 2961         ast_log(LOG_NOTICE, "Thread got HANGUP or no owner %s  %p tpvt=%p\n",
 2962                 tech_pvt->callid, tech_pvt, tech_pvt->owner);
 2963       }
 2964       goto tech_thread_continue;
 2965     }
 2966 
 2967     if (ast_test_flag(tech_pvt, TFLAG_ACTIVATE)) {
 2968 
 2969       struct ast_channel *owner;
 2970       int err;
 2971 
 2972       if (globals.debug > 2) {
 2973         ast_log(LOG_NOTICE, "ACTIVATE %s tpvt=%p\n",
 2974                 tech_pvt->callid, tech_pvt);
 2975       }
 2976       ast_clear_flag(tech_pvt, TFLAG_ACTIVATE);
 2977       err = tech_activate(tech_pvt);
 2978       if (err < 0 || ast_test_flag(tech_pvt, TFLAG_ABORT)) {
 2979         if (globals.debug > 2) {
 2980           ast_log(LOG_NOTICE, "ACTIVATE ABORT Ch=%d\n",
 2981                   tech_pvt->command_channel);
 2982         }
 2983         ast_set_flag(tech_pvt, TFLAG_ABORT);
 2984         goto tech_thread_continue;
 2985       }
 2986 
 2987       my_tech_pvt_and_owner_lock(tech_pvt);
 2988       owner = tech_pvt->owner;
 2989       if (owner) {
 2990         owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
 2991       }
 2992       my_tech_pvt_and_owner_unlock(tech_pvt);
 2993 
 2994       if (globals.debug > 2) {
 2995         ast_log(LOG_NOTICE, "ACTIVATE DONE %s tpvt=%p\n",
 2996                 tech_pvt->callid, tech_pvt);
 2997       }
 2998     }
 2999 
 3000     if (ast_test_flag(tech_pvt, TFLAG_PARSE_INCOMING)) {
 3001       int err;
 3002 
 3003       ast_clear_flag(tech_pvt, TFLAG_PARSE_INCOMING);
 3004       ast_set_flag(tech_pvt, TFLAG_INCOMING);
 3005 
 3006       my_tech_pvt_and_owner_lock(tech_pvt);
 3007       err = woomera_event_incoming(tech_pvt);
 3008       my_tech_pvt_and_owner_unlock(tech_pvt);
 3009 
 3010       if (err != 0) {
 3011 
 3012         err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3013             "HANGUP %s%s"
 3014             "cause: Invalid call reference%s"
 3015             "Q931-Cause-Code: 81%s"
 3016             "Reason-String: Invalid call reference%s"
 3017             "Reason: 81%s"
 3018             "Unique-Call-Id: %s%s",
 3019             tech_pvt->callid,
 3020             WOOMERA_LINE_SEPARATOR,
 3021             WOOMERA_LINE_SEPARATOR,
 3022             WOOMERA_LINE_SEPARATOR,
 3023             WOOMERA_LINE_SEPARATOR,
 3024             WOOMERA_LINE_SEPARATOR,
 3025             tech_pvt->callid,
 3026             WOOMERA_RECORD_SEPARATOR);
 3027 
 3028         /* Wait for Ack */
 3029         if (err >= 0) {
 3030           woomera_message_parse_wait(tech_pvt, &wmsg);
 3031         }
 3032 
 3033         woomera_close_socket(&tech_pvt->command_channel);
 3034 
 3035         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3036         goto tech_thread_continue;
 3037 
 3038       } else {
 3039         if (tech_pvt->vrtp_enable) {
 3040           err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3041                                "%s %s%s"
 3042                                "RTP-Audio: %s:%d%s"
 3043                                "RTP-Audio-Format: %s%s"
 3044                                "RTP-Video: %s:%d%s"
 3045                                "RTP-Video-Format: %s%s"
 3046                                "Unique-Call-Id: %s%s",
 3047                                MEDIA_ANSWER,
 3048                                tech_pvt->callid,
 3049                                WOOMERA_LINE_SEPARATOR,
 3050                                tech_pvt->profile->audio_ip,
 3051                                tech_pvt->port,
 3052                                WOOMERA_LINE_SEPARATOR,
 3053                                ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 3054                                  WOOMERA_LINE_SEPARATOR,
 3055                                tech_pvt->profile->audio_ip,  /* use same */
 3056                                tech_pvt->vport,
 3057                                WOOMERA_LINE_SEPARATOR,
 3058                                ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0),
 3059                                WOOMERA_LINE_SEPARATOR,
 3060                                tech_pvt->callid,
 3061                                WOOMERA_RECORD_SEPARATOR);
 3062         } else if (tech_pvt->rtp_enable) {
 3063           err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3064                                "%s %s%s"
 3065                                "RTP-Audio: %s:%d%s"
 3066                                "RTP-Audio-Format: %s%s"
 3067                                "Unique-Call-Id: %s%s",
 3068                                MEDIA_ANSWER,
 3069                                tech_pvt->callid,
 3070                                WOOMERA_LINE_SEPARATOR,
 3071                                tech_pvt->profile->audio_ip,
 3072                                tech_pvt->port,
 3073                                WOOMERA_LINE_SEPARATOR,
 3074                                ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 3075                                WOOMERA_LINE_SEPARATOR,
 3076                                tech_pvt->callid,
 3077                                WOOMERA_RECORD_SEPARATOR);
 3078         } else {
 3079           err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3080                                "%s %s%s"
 3081                                "Raw-Audio: %s:%d%s"
 3082                                "Request-Audio: Raw%s"
 3083                                "Unique-Call-Id: %s%s",
 3084                                MEDIA_ANSWER,
 3085                                tech_pvt->callid,
 3086                                WOOMERA_LINE_SEPARATOR,
 3087                                tech_pvt->profile->audio_ip,
 3088                                tech_pvt->port,
 3089                                WOOMERA_LINE_SEPARATOR,
 3090                                WOOMERA_LINE_SEPARATOR,
 3091                                tech_pvt->callid,
 3092                                WOOMERA_RECORD_SEPARATOR);
 3093         }
 3094       }
 3095 
 3096       /* Wait for Ack */
 3097       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3098         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3099         ast_log(LOG_NOTICE, "MEDIA ANSWER ABORT Ch=%d\n",
 3100                 tech_pvt->command_channel);
 3101         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3102         tech_pvt->pri_cause = 111;
 3103         goto tech_thread_continue;
 3104       }
 3105 
 3106       /* Confirm that the Ack is OK otherwise
 3107        * hangup */
 3108       if (woomera_message_reply_ok(&wmsg) != 0) {
 3109         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3110         goto tech_thread_continue;
 3111       }
 3112 
 3113       /* It is possible for ACCEPT to have media info
 3114        * This is how Early Media is started */
 3115       err = woomera_event_media(tech_pvt, &wmsg);
 3116       if (err < 0) {
 3117         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3118         goto tech_thread_continue;
 3119       }
 3120     }
 3121 
 3122     if (ast_test_flag(tech_pvt, TFLAG_ACCEPT) &&
 3123         ast_test_flag(tech_pvt, TFLAG_INCOMING)) {
 3124       int err;
 3125 
 3126       ast_set_flag(tech_pvt, TFLAG_ACCEPTED);
 3127       ast_clear_flag(tech_pvt, TFLAG_ACCEPT);
 3128 
 3129       if (tech_pvt->vrtp_enable) {
 3130         err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3131                        "ACCEPT %s%s"
 3132                        "RTP-Audio: %s:%d%s"
 3133                        "RTP-Audio-Format: %s%s"
 3134                        "RTP-Video: %s:%d%s"
 3135                        "RTP-Video-Format: %s%s"
 3136                        "Unique-Call-Id: %s%s",
 3137                        tech_pvt->callid,
 3138                        WOOMERA_LINE_SEPARATOR,
 3139                        tech_pvt->profile->audio_ip,
 3140                        tech_pvt->port,
 3141                        WOOMERA_LINE_SEPARATOR,
 3142                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 3143                          WOOMERA_LINE_SEPARATOR,
 3144                        tech_pvt->profile->audio_ip,
 3145                        tech_pvt->vport,
 3146                        WOOMERA_LINE_SEPARATOR,
 3147                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0),
 3148                        WOOMERA_LINE_SEPARATOR,
 3149                        tech_pvt->callid,
 3150                        WOOMERA_RECORD_SEPARATOR);
 3151       } else if (tech_pvt->rtp_enable) {
 3152         err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3153                        "ACCEPT %s%s"
 3154                        "RTP-Audio: %s:%d%s"
 3155                        "RTP-Audio-Format: %s%s"
 3156                        "Unique-Call-Id: %s%s",
 3157                        tech_pvt->callid,
 3158                        WOOMERA_LINE_SEPARATOR,
 3159                        tech_pvt->profile->audio_ip,
 3160                        tech_pvt->port,
 3161                        WOOMERA_LINE_SEPARATOR,
 3162                        ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0),
 3163                        WOOMERA_LINE_SEPARATOR,
 3164                        tech_pvt->callid,
 3165                        WOOMERA_RECORD_SEPARATOR);
 3166       } else {
 3167         err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3168                        "ACCEPT %s%s"
 3169                        "Raw-Audio: %s:%d%s"
 3170                        "Request-Audio: Raw%s"
 3171                        "Unique-Call-Id: %s%s",
 3172                        tech_pvt->callid,
 3173                        WOOMERA_LINE_SEPARATOR,
 3174                        tech_pvt->profile->audio_ip,
 3175                        tech_pvt->port,
 3176                        WOOMERA_LINE_SEPARATOR,
 3177                        WOOMERA_LINE_SEPARATOR,
 3178                        tech_pvt->callid,
 3179                        WOOMERA_RECORD_SEPARATOR);
 3180       }
 3181 
 3182       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3183         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3184         ast_log(LOG_NOTICE, "ACCEPT ABORT Ch=%d\n", tech_pvt->command_channel);
 3185         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3186         tech_pvt->pri_cause = 111;
 3187         goto tech_thread_continue;
 3188         continue;
 3189       }
 3190     }
 3191 
 3192     if (ast_test_flag(tech_pvt, TFLAG_ANSWER)) {
 3193       int err;
 3194 
 3195       if (globals.debug > 2) {
 3196         ast_log(LOG_NOTICE, "ANSWER %s tpvt=%p\n", tech_pvt->callid, tech_pvt);
 3197       }
 3198       ast_clear_flag(tech_pvt, TFLAG_ANSWER);
 3199 
 3200       if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
 3201         ast_log(LOG_ERROR,"Error: ANSWER on OUTBOUND Call! (skipped) %s\n",
 3202                 tech_pvt->callid);
 3203       } else {
 3204 #ifdef USE_ANSWER
 3205         err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3206                              "ANSWER %s%s"
 3207                              "Unique-Call-Id: %s%s",
 3208                              tech_pvt->callid,
 3209                              WOOMERA_LINE_SEPARATOR,
 3210                              tech_pvt->callid,
 3211                              WOOMERA_RECORD_SEPARATOR);
 3212 
 3213         if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3214           ast_set_flag(tech_pvt, TFLAG_ABORT);
 3215           ast_log(LOG_NOTICE, "ANSWER ABORT Ch=%d\n", tech_pvt->command_channel);
 3216           ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3217           tech_pvt->pri_cause = 111;
 3218           goto tech_thread_continue;
 3219           continue;
 3220         }
 3221         ast_set_flag(tech_pvt, TFLAG_CONNECTED);
 3222         ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 3223         tech_pvt->profile->call_ok++;
 3224         ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 3225 #endif
 3226       }
 3227     }
 3228 
 3229     if (ast_test_flag(tech_pvt, TFLAG_DTMF)) {
 3230       int err;
 3231       if (globals.debug > 2) {
 3232         ast_log(LOG_NOTICE, "DTMF %s tpvt=%p %s\n",
 3233                 tech_pvt->callid, tech_pvt, tech_pvt->dtmfbuf);
 3234       }
 3235 
 3236       //DIALECT
 3237       ast_mutex_lock(&tech_pvt->iolock);
 3238 #if 0
 3239       woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3240             "DTMF %s %s%s",
 3241             tech_pvt->callid,
 3242             tech_pvt->dtmfbuf,
 3243             WOOMERA_LINE_SEPARATOR);
 3244 #else
 3245       err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
 3246             "DTMF %sUnique-Call-Id:%s%sContent-Length:%d%s%s%s%s",
 3247             WOOMERA_LINE_SEPARATOR,
 3248             tech_pvt->callid,
 3249             WOOMERA_LINE_SEPARATOR,
 3250             strlen(tech_pvt->dtmfbuf),
 3251             WOOMERA_LINE_SEPARATOR,
 3252             WOOMERA_LINE_SEPARATOR,
 3253             tech_pvt->dtmfbuf,
 3254             WOOMERA_RECORD_SEPARATOR);
 3255 #endif
 3256 
 3257       ast_clear_flag(tech_pvt, TFLAG_DTMF);
 3258       memset(tech_pvt->dtmfbuf, 0, sizeof(tech_pvt->dtmfbuf));
 3259       ast_mutex_unlock(&tech_pvt->iolock);
 3260 
 3261       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3262         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3263         ast_log(LOG_NOTICE, "DTMF ABORT Ch=%d\n", tech_pvt->command_channel);
 3264         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3265                 tech_pvt->pri_cause = 111;
 3266         goto tech_thread_continue;
 3267         continue;
 3268       }
 3269     }
 3270 
 3271     if (ast_test_flag(tech_pvt, TFLAG_PLAY)) {
 3272       int err;
 3273       if (globals.debug > 2) {
 3274         ast_log(LOG_NOTICE, "PLAY %s tpvt=%p AudioUri=%s VideoUri=%s\n",
 3275                 tech_pvt->callid, tech_pvt, tech_pvt->audio_uri, tech_pvt->video_uri);
 3276       }
 3277 
 3278       ast_mutex_lock(&tech_pvt->iolock);
 3279       err = woomera_printf(tech_pvt->profile,
 3280                            tech_pvt->command_channel,
 3281                            "PLAY%s"
 3282                            "Unique-Call-Id: %s%s"
 3283                            "Audio-Uri: %s%s"
 3284                            "Video-Uri: %s%s"
 3285                            "Stop-Digits: %s%s"
 3286                            "Language: %s%s"
 3287                            "Repeat: %s%s",
 3288                            WOOMERA_LINE_SEPARATOR,
 3289                            tech_pvt->callid,
 3290                            WOOMERA_LINE_SEPARATOR,
 3291                            tech_pvt->audio_uri,
 3292                            WOOMERA_LINE_SEPARATOR,
 3293                            tech_pvt->video_uri,
 3294                            WOOMERA_LINE_SEPARATOR,
 3295                            tech_pvt->stop_digits,
 3296                            WOOMERA_LINE_SEPARATOR,
 3297                            tech_pvt->owner->language,
 3298                            WOOMERA_LINE_SEPARATOR,
 3299                            tech_pvt->repeat,
 3300                            WOOMERA_RECORD_SEPARATOR
 3301                           );
 3302 
 3303       ast_clear_flag(tech_pvt, TFLAG_PLAY);
 3304       memset(tech_pvt->audio_uri, 0, sizeof(tech_pvt->audio_uri));
 3305       memset(tech_pvt->video_uri, 0, sizeof(tech_pvt->video_uri));
 3306       ast_mutex_unlock(&tech_pvt->iolock);
 3307 
 3308       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3309         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3310         ast_log(LOG_NOTICE, "PLAY ABORT Ch=%d\n", tech_pvt->command_channel);
 3311         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3312                 tech_pvt->pri_cause = 111;
 3313         goto tech_thread_continue;
 3314         continue;
 3315       }
 3316       if ( wmsg.mval > 200 ) {
 3317         pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERAPLAYSTATUS", "error");
 3318         pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERAPLAYDURATION", "0");
 3319         ast_set_flag(tech_pvt, TFLAG_PLAY_COMPLETED);
 3320       }
 3321     }
 3322 
 3323     if (ast_test_flag(tech_pvt, TFLAG_RECORD)) {
 3324       int err;
 3325       if (globals.debug > 2) {
 3326         ast_log(LOG_NOTICE, "RECORD %s tpvt=%p AudioUri=%s VideoUri=%s\n",
 3327                 tech_pvt->callid, tech_pvt, tech_pvt->audio_uri, tech_pvt->video_uri);
 3328       }
 3329 
 3330       ast_mutex_lock(&tech_pvt->iolock);
 3331       err = woomera_printf(tech_pvt->profile,
 3332                            tech_pvt->command_channel,
 3333                            "RECORD%s"
 3334                            "Unique-Call-Id: %s%s"
 3335                            "Audio-Uri: %s%s"
 3336                            "Video-Uri: %s%s"
 3337                            "Stop-Digits: %s%s"
 3338                            "Beep: %s%s"
 3339                            "Language: %s%s",
 3340                            WOOMERA_LINE_SEPARATOR,
 3341                            tech_pvt->callid,
 3342                            WOOMERA_LINE_SEPARATOR,
 3343                            tech_pvt->audio_uri,
 3344                            WOOMERA_LINE_SEPARATOR,
 3345                            tech_pvt->video_uri,
 3346                            WOOMERA_LINE_SEPARATOR,
 3347                            tech_pvt->stop_digits,
 3348                            WOOMERA_LINE_SEPARATOR,
 3349                            (tech_pvt->beep ? "yes" : "no"),
 3350                            WOOMERA_LINE_SEPARATOR,
 3351                            tech_pvt->owner->language,
 3352                            WOOMERA_RECORD_SEPARATOR
 3353                           );
 3354       ast_clear_flag(tech_pvt, TFLAG_RECORD);
 3355       memset(tech_pvt->audio_uri, 0, sizeof(tech_pvt->audio_uri));
 3356       memset(tech_pvt->video_uri, 0, sizeof(tech_pvt->video_uri));
 3357       ast_mutex_unlock(&tech_pvt->iolock);
 3358 
 3359       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3360         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3361         ast_log(LOG_NOTICE, "RECORD ABORT Ch=%d\n",
 3362                 tech_pvt->command_channel);
 3363         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3364                 tech_pvt->pri_cause = 111;
 3365         goto tech_thread_continue;
 3366         continue;
 3367       }
 3368       if ( wmsg.mval > 200 ) {
 3369         pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERARECORDSTATUS", "error");
 3370         pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERARECORDDURATION", "0");
 3371         ast_set_flag(tech_pvt, TFLAG_RECORD_COMPLETED);
 3372       }
 3373     }
 3374 
 3375     if (ast_test_flag(tech_pvt, TFLAG_STOP)) {
 3376       int err;
 3377       if (globals.debug > 2) {
 3378         ast_log(LOG_NOTICE, "STOP %s tpvt=%p\n", tech_pvt->callid, tech_pvt);
 3379       }
 3380 
 3381       ast_mutex_lock(&tech_pvt->iolock);
 3382       err = woomera_printf(tech_pvt->profile,
 3383                            tech_pvt->command_channel,
 3384                            "STOP%s"
 3385                            "Unique-Call-Id: %s%s",
 3386                            WOOMERA_LINE_SEPARATOR,
 3387                            tech_pvt->callid,
 3388                            WOOMERA_RECORD_SEPARATOR
 3389                           );
 3390 
 3391       ast_clear_flag(tech_pvt, TFLAG_STOP);
 3392       ast_mutex_unlock(&tech_pvt->iolock);
 3393 
 3394       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3395         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3396         ast_log(LOG_NOTICE, "STOP ABORT Ch=%d\n", tech_pvt->command_channel);
 3397         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3398                 tech_pvt->pri_cause = 111;
 3399         goto tech_thread_continue;
 3400         continue;
 3401       }
 3402       ast_set_flag(tech_pvt, TFLAG_STOP_COMPLETED);
 3403       if ( wmsg.mval > 200 ) {
 3404         /* prevents us getting stuck in woomera_stop_exec() */
 3405         ast_set_flag(tech_pvt, TFLAG_PLAY_COMPLETED);
 3406       }
 3407     }
 3408 
 3409     if (ast_test_flag(tech_pvt, TFLAG_BRIDGE) && ast_test_flag(tech_pvt, TFLAG_CONNECTED)) {
 3410       int err;
 3411       if (globals.debug > 2) {
 3412         ast_log(LOG_NOTICE, "BRIDGE %s tpvt=%p RTP-Audio=%s:%d RTP-Video=%s:%d\n",
 3413                 tech_pvt->callid, tech_pvt,
 3414                 ast_inet_ntoa(tech_pvt->audio_bridge_ip.sin_addr),
 3415                 ntohs(tech_pvt->audio_bridge_ip.sin_port),
 3416                 ast_inet_ntoa(tech_pvt->video_bridge_ip.sin_addr),
 3417                 ntohs(tech_pvt->video_bridge_ip.sin_port)
 3418                 );
 3419       }
 3420       /* update rtp end-points*/
 3421       ast_mutex_lock(&tech_pvt->iolock);
 3422       err = woomera_printf(tech_pvt->profile,
 3423                        tech_pvt->command_channel,
 3424                        "UPDATE%s"
 3425                        "Unique-Call-Id: %s%s"
 3426                        "RTP-Audio: %s:%d%s"
 3427                        "RTP-Video: %s:%d%s",
 3428                        WOOMERA_LINE_SEPARATOR,
 3429                        tech_pvt->callid,
 3430                        WOOMERA_LINE_SEPARATOR,
 3431                        ast_inet_ntoa(tech_pvt->audio_bridge_ip.sin_addr),
 3432                        ntohs(tech_pvt->audio_bridge_ip.sin_port),
 3433                        WOOMERA_LINE_SEPARATOR,
 3434                        ast_inet_ntoa(tech_pvt->video_bridge_ip.sin_addr),
 3435                        ntohs(tech_pvt->video_bridge_ip.sin_port),
 3436                        WOOMERA_RECORD_SEPARATOR
 3437                        );
 3438       ast_clear_flag(tech_pvt, TFLAG_BRIDGE);
 3439       ast_mutex_unlock(&tech_pvt->iolock);
 3440 
 3441       if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
 3442         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3443         ast_log(LOG_NOTICE, "BRIDGE ABORT Ch=%d\n",
 3444                 tech_pvt->command_channel);
 3445         ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 3446                 tech_pvt->pri_cause = 111;
 3447         goto tech_thread_continue;
 3448         continue;
 3449       }
 3450     }
 3451 
 3452     if (tech_pvt->timeout) {
 3453       struct timeval now;
 3454       int elapsed;
 3455       gettimeofday(&now, NULL);
 3456       elapsed = (((now.tv_sec * 1000) + now.tv_usec / 1000) -
 3457                 ((tech_pvt->started.tv_sec * 1000) + tech_pvt->started.tv_usec / 1000));
 3458       if (elapsed > tech_pvt->timeout) {
 3459         /* call timed out! */
 3460         if (globals.debug > 2) {
 3461           ast_log(LOG_NOTICE, "Call timed out %s tpvt=%p\n",
 3462                   tech_pvt->callid, tech_pvt);
 3463         }
 3464         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3465         ast_copy_string(tech_pvt->ds, "RECOVERY_ON_TIMER_EXPIRE", sizeof(tech_pvt->ds));
 3466         tech_pvt->pri_cause = 102;
 3467       }
 3468     }
 3469 
 3470     if (globals.debug > 2) {
 3471       if (tcallid[0] == 0) {
 3472         strncpy(tcallid, tech_pvt->callid, sizeof(tcallid)-1);
 3473       }
 3474     }
 3475 
 3476     if (tech_pvt->command_channel < 0) {
 3477       if (!globals.more_threads) {
 3478         goto tech_thread_continue;
 3479         continue;
 3480       } else {
 3481         if (globals.debug > 2) {
 3482           ast_log(LOG_NOTICE, "No Command Channel %s tpvt=%p\n",
 3483                   tech_pvt->callid, tech_pvt);
 3484         }
 3485         ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds));
 3486         tech_pvt->pri_cause = 44;
 3487         ast_set_flag(tech_pvt, TFLAG_ABORT);
 3488         goto tech_thread_continue;
 3489         continue;
 3490       }
 3491     }
 3492     /* Check for events */
 3493     if((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg)) ||
 3494        (res = woomera_message_parse(tech_pvt->command_channel,
 3495                                     &wmsg,
 3496                                     100,
 3497                                     tech_pvt->profile,
 3498                                     NULL
 3499                                     ))) {
 3500 
 3501       woomera_check_event (tech_pvt, res, &wmsg);
 3502       if (ast_test_flag(tech_pvt, TFLAG_ABORT)) {
 3503         continue;
 3504       }
 3505 
 3506     }
 3507     if (globals.debug > 4) {
 3508       if (option_verbose > 2) {
 3509         ast_verbose(WOOMERA_DEBUG_PREFIX "CHECK {%s} (%d) %s\n",
 3510                     tech_pvt->profile->name,
 3511                     res,tech_pvt->callid);
 3512       }
 3513     }
 3514 
 3515 tech_thread_continue:
 3516 
 3517     if (!globals.more_threads) {
 3518       ast_log(LOG_NOTICE, "EXITING THREAD on more threads %s\n",
 3519             tcallid);
 3520       break;
 3521     }
 3522 
 3523   }
 3524 
 3525 tech_thread_exit:
 3526 
 3527   if (globals.debug > 2) {
 3528     ast_log(LOG_NOTICE, "OUT THREAD %s 0x%X\n",tcallid,aborted);
 3529   }
 3530 
 3531   return NULL;
 3532 }
 3533 
 3534 
 3535 static int woomera_profile_thread_running(woomera_profile *profile, int set, int new)
 3536 {
 3537   int running = 0;
 3538 
 3539   ast_mutex_lock(&profile->iolock);
 3540   if (set) {
 3541     profile->thread_running = new;
 3542   }
 3543   running = profile->thread_running;
 3544   ast_mutex_unlock(&profile->iolock);
 3545   return running;
 3546 }
 3547 
 3548 
 3549 /*!
 3550  * \brief  Connect to the Woomera server defined by the profile.
 3551  */
 3552 static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket)
 3553 {
 3554   woomera_message wmsg;
 3555 
 3556   memset(&wmsg, 0, sizeof(wmsg));
 3557 
 3558   for (;;) {
 3559 
 3560     while (connect_woomera(woomera_socket, profile, 0) < 0) {
 3561       if(!woomera_profile_thread_running(profile, 0, 0)) {
 3562         break;
 3563       }
 3564       if (globals.panic > 2) {
 3565         break;
 3566       }
 3567 /*      ast_log(LOG_NOTICE,
 3568         "Woomera {%s} Cannot Reconnect! retry in 5 seconds...\n",
 3569         profile->name);
 3570 */
 3571       /* When we establish connection update the version */
 3572       svrversion_init = 0;
 3573       sleep(5);
 3574     }
 3575 
 3576     if (*woomera_socket > -1) {
 3577       if (ast_test_flag(profile, PFLAG_INBOUND)) {
 3578         int err;
 3579         if (globals.debug > 2) {
 3580           ast_log(LOG_NOTICE, "Woomera Master Socket \n");
 3581         }
 3582 
 3583         err = woomera_printf(profile, *woomera_socket, "LISTEN MASTER%s", WOOMERA_RECORD_SEPARATOR);
 3584         if (err < 0) {
 3585           if (*woomera_socket > -1) {
 3586             woomera_close_socket(woomera_socket);
 3587           }
 3588           continue;
 3589         }
 3590 
 3591         if (woomera_message_parse(*woomera_socket,
 3592                                   &wmsg,
 3593                                   WOOMERA_HARD_TIMEOUT,
 3594                                   profile,
 3595                                   &profile->event_queue
 3596                                  ) < 0) {
 3597           ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n",
 3598                   profile->name,__FUNCTION__,__LINE__);
 3599           if (*woomera_socket > -1) {
 3600             woomera_close_socket(woomera_socket);
 3601           }
 3602           continue;
 3603         }
 3604       }
 3605 
 3606     }
 3607     usleep(100);
 3608     break;
 3609   }
 3610   return *woomera_socket;
 3611 }
 3612 
 3613 
 3614 static void tech_monitor_in_one_thread(void)
 3615 {
 3616   private_object *tech_pvt;
 3617 
 3618   ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do {
 3619     ASTOBJ_RDLOCK(iterator);
 3620         tech_pvt = iterator;
 3621     tech_monitor_thread(tech_pvt);
 3622     ASTOBJ_UNLOCK(iterator);
 3623     } while(0));
 3624 }
 3625 
 3626 
 3627 /*!
 3628  * \brief Per profile Woomera socket listener.
 3629  */
 3630 static void *woomera_thread_run(void *obj)
 3631 {
 3632   int woomera_socket = -1, res = 0, res2 = 0;
 3633   woomera_message wmsg;
 3634   woomera_profile *profile;
 3635 
 3636   memset(&wmsg, 0, sizeof(wmsg));
 3637 
 3638   profile = obj;
 3639   ast_log(LOG_NOTICE, "Started Woomera Thread {%s}.\n", profile->name);
 3640 
 3641   profile->thread_running = 1;
 3642 
 3643   while (woomera_profile_thread_running(profile, 0, 0)) {
 3644     /* listen on socket and handle events */
 3645 
 3646     if (globals.panic > 2) {
 3647       break;
 3648     }
 3649 
 3650     if (globals.panic == 2) {
 3651       ast_log(LOG_NOTICE, "Woomera is disabled!\n");
 3652       sleep(5);
 3653       continue;
 3654     }
 3655 
 3656     if (woomera_socket < 0) {
 3657       if (woomera_locate_socket(profile, &woomera_socket)) {
 3658         globals.panic = 0;
 3659       }
 3660       if (!woomera_profile_thread_running(profile, 0, 0)) {
 3661         break;
 3662       }
 3663       profile->woomera_socket = woomera_socket;
 3664       ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s:%d\n",
 3665               profile->name, profile->woomera_host, profile->woomera_port);
 3666     }
 3667 
 3668     if (globals.panic) {
 3669       if (globals.panic != 2) {
 3670         ast_log(LOG_ERROR, "Help I'm in a state of panic!\n");
 3671       }
 3672       if (woomera_socket > -1) {
 3673         woomera_close_socket(&woomera_socket);
 3674         profile->woomera_socket = -1;
 3675       }
 3676       continue;
 3677     }
 3678     if (!globals.more_threads) {
 3679       if (woomera_socket > -1) {
 3680         tech_monitor_in_one_thread();
 3681       }
 3682     }
 3683 
 3684     if ((res = woomera_dequeue_event(&profile->event_queue, &wmsg) ||
 3685         (res2 = woomera_message_parse(woomera_socket,
 3686                                       &wmsg,
 3687         /* if we are not stingy with threads we can block forever */
 3688                                       globals.more_threads ? 0 : 500,
 3689                                       profile,
 3690                                       NULL
 3691                                       )))) {
 3692 
 3693       if (res2 < 0) {
 3694         ast_log(LOG_ERROR, "{%s} Lost my connection to Woomera Server %s:%d\n", profile->name, profile->woomera_host, profile->woomera_port);
 3695         if (woomera_socket > -1) {
 3696           woomera_close_socket(&woomera_socket);
 3697           profile->woomera_socket = -1;
 3698         }
 3699         global_set_flag(TFLAG_ABORT);
 3700         if (globals.panic > 2) {
 3701           break;
 3702         }
 3703 
 3704         continue;
 3705 
 3706         if (woomera_socket > -1) {
 3707           if (ast_test_flag(profile, PFLAG_INBOUND)) {
 3708             if (globals.debug > 2) {
 3709               ast_log(LOG_NOTICE, "%s:%d Incoming Call \n",__FUNCTION__,__LINE__);
 3710             }
 3711 
 3712 #if 0
 3713 /* We only want a single listener */
 3714             woomera_printf(profile, woomera_socket, "LISTEN%s", WOOMERA_RECORD_SEPARATOR);
 3715             if (woomera_message_parse(woomera_socket,
 3716                                       &wmsg,
 3717                                       WOOMERA_HARD_TIMEOUT,
 3718                                       profile,
 3719                                       &profile->event_queue
 3720                                       ) < 0) {
 3721               ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n", profile->name, __FUNCTION__, __LINE__);
 3722               woomera_close_socket(&woomera_socket);
 3723               profile->woomera_socket = -1;
 3724             }
 3725 #endif
 3726           }
 3727           if (woomera_socket > -1) {
 3728             ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port);
 3729           }
 3730         }
 3731         continue;
 3732       }
 3733 
 3734       if (!strcasecmp(wmsg.command, "INCOMING")) {
 3735 
 3736         int err = 1;
 3737         int cause = 0;
 3738         struct ast_channel *inchan;
 3739         char *name = "Woomera";
 3740 
 3741         if (!(name = woomera_message_header(&wmsg, "Channel-Name"))) {
 3742           name = woomera_message_header(&wmsg,"Remote-Address");
 3743         }
 3744 
 3745         if (!name) {
 3746           name = wmsg.callid;
 3747         }
 3748 
 3749         if (!name) {
 3750           name = "smg";
 3751         }
 3752 
 3753         if (globals.debug > 2) {
 3754           ast_log(LOG_NOTICE, "New Inbound Call %s\n", wmsg.callid);
 3755         }
 3756 
 3757         if ((inchan = woomera_new(WOOMERA_CHAN_NAME, profile->coding, name, &cause, profile))) {
 3758           private_object *tech_pvt;
 3759           char *callid;
 3760           tech_pvt = inchan->tech_pvt;
 3761 
 3762           /* Save the call id */
 3763           tech_pvt->call_info = wmsg;
 3764           memcpy(tech_pvt->callid, wmsg.callid, sizeof(tech_pvt->callid));
 3765 
 3766           callid = woomera_message_header(&wmsg, "Unique-Call-Id");
 3767           if (callid) {
 3768             ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid));
 3769           }
 3770 
 3771           err = tech_init(tech_pvt, profile, TFLAG_INBOUND);
 3772           if (err) {
 3773             if (globals.debug > 2) {
 3774               ast_log(LOG_ERROR, "Inbound Call Failed %s %p\n",
 3775                       wmsg.callid, tech_pvt);
 3776             }
 3777             tech_destroy(tech_pvt, inchan);
 3778           }
 3779         } else {
 3780           ast_log(LOG_ERROR, "Cannot Create new Inbound Channel!\n");
 3781         }
 3782 
 3783         /* It is the job of the server to timeout on this call
 3784                                    if the call is not started */
 3785       }
 3786     }
 3787     if(globals.debug > 4) {
 3788       if (option_verbose > 2) {
 3789         ast_verbose(WOOMERA_DEBUG_PREFIX "Main Thread {%s} Select Return %d\n", profile->name, res);
 3790       }
 3791     }
 3792     usleep(100);
 3793   }
 3794 
 3795   if (woomera_socket > -1) {
 3796     int err;
 3797     err = woomera_printf(profile, woomera_socket, "BYE%s", WOOMERA_RECORD_SEPARATOR);
 3798     if (err < 0 || woomera_message_parse(woomera_socket,
 3799                                          &wmsg,
 3800                                          WOOMERA_HARD_TIMEOUT,
 3801                                          profile,
 3802                                          &profile->event_queue
 3803                                         ) < 0) {
 3804     }
 3805     woomera_close_socket(&woomera_socket);
 3806     profile->woomera_socket = -1;
 3807   }
 3808 
 3809   ast_set_flag(profile, PFLAG_DISABLED);
 3810 
 3811   ast_log(LOG_NOTICE, "Ended Woomera Thread {%s}.\n", profile->name);
 3812   woomera_profile_thread_running(profile, 1, -1);
 3813   return NULL;
 3814 }
 3815 
 3816 
 3817 /*!
 3818  * \brief Create a new thread using woomera_thread_run() as the entry point.
 3819  */
 3820 static void launch_woomera_thread(woomera_profile *profile)
 3821 {
 3822   pthread_attr_t attr;
 3823   int result = 0;
 3824 
 3825   result = pthread_attr_init(&attr);
 3826   pthread_attr_setschedpolicy(&attr, SCHED_RR);
 3827   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 3828   result = ast_pthread_create(&profile->thread, &attr, woomera_thread_run, profile);
 3829   result = pthread_attr_destroy(&attr);
 3830 }
 3831 
 3832 
 3833 /*!
 3834  * \brief Create a new thread using tech_monitor_thread() as the entry point.
 3835  */
 3836 static int launch_tech_thread(private_object *tech_pvt)
 3837 {
 3838   pthread_attr_t attr;
 3839   int result = 0;
 3840 
 3841   if (globals.debug > 2) {
 3842     if (option_verbose > 2) {
 3843       ast_verbose(WOOMERA_DEBUG_PREFIX "Tech Thread entry\n");
 3844     }
 3845   }
 3846 
 3847   if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) {
 3848     /* Sanity check should never happen */
 3849     ast_log(LOG_NOTICE,"Tech Thread failed call already hangup!\n");
 3850     return -1;
 3851   }
 3852 
 3853   result = pthread_attr_init(&attr);
 3854   pthread_attr_setschedpolicy(&attr, SCHED_RR);
 3855   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 3856   ast_set_flag(tech_pvt, TFLAG_INTHREAD);
 3857   result = ast_pthread_create(&tech_pvt->thread, &attr, tech_monitor_thread, tech_pvt);
 3858   if (result) {
 3859     ast_clear_flag(tech_pvt, TFLAG_INTHREAD);
 3860     ast_log(LOG_ERROR, "Failed to launch tech thread %s\n",
 3861             strerror(errno));
 3862   }
 3863   pthread_attr_destroy(&attr);
 3864 
 3865   return result;
 3866 }
 3867 
 3868 
 3869 /*!
 3870  * \brief Apply gain settings for a profile.
 3871  */
 3872 static void woomera_config_gain(woomera_profile *profile, float gain_val, int rx)
 3873 {
 3874   int j;
 3875   int k;
 3876   float linear_gain = pow(10.0, gain_val / 20.0);
 3877   unsigned char *gain;
 3878 
 3879   if (profile->coding == AST_FORMAT_SLINEAR){
 3880     ast_log(LOG_WARNING, "Coding not specified, %s value ignored\n", (rx)? "rxgain":"txgain");
 3881     return;
 3882   }
 3883 
 3884   if (gain_val == 0) {
 3885     goto woomera_config_gain_skip;
 3886   }
 3887 
 3888   if (rx) {
 3889     gain = profile->rxgain;
 3890   } else {
 3891     gain = profile->txgain;
 3892   }
 3893 
 3894   switch (profile->coding) {
 3895 
 3896   case AST_FORMAT_ALAW:
 3897     for (j = 0; j < 256; j++) {
 3898       if (gain_val) {
 3899         k = (int) (((float) alaw_to_linear(j)) * linear_gain);
 3900         if (k > 32767) k = 32767;
 3901         if (k < -32767) k = -32767;
 3902         gain[j] = linear_to_alaw(k);
 3903       } else {
 3904         gain[j] = j;
 3905       }
 3906     }
 3907     break;
 3908   case AST_FORMAT_ULAW:
 3909     for (j = 0; j < 256; j++) {
 3910       if (gain_val) {
 3911         k = (int) (((float) ulaw_to_linear(j)) * linear_gain);
 3912         if (k > 32767) k = 32767;
 3913         if (k < -32767) k = -32767;
 3914         gain[j] = linear_to_ulaw(k);
 3915       } else {
 3916         gain[j] = j;
 3917       }
 3918     }
 3919     break;
 3920   }
 3921 
 3922 woomera_config_gain_skip:
 3923 
 3924   if (rx) {
 3925     profile->rxgain_val=gain_val;
 3926   } else {
 3927     profile->txgain_val=gain_val;
 3928   }
 3929 }
 3930 
 3931 
 3932 /*!
 3933  * \brief Delete a woomera profile.
 3934  */
 3935 static void destroy_woomera_profile(woomera_profile *profile)
 3936 {
 3937   int i;
 3938   if (profile && ast_test_flag(profile, PFLAG_DYNAMIC)) {
 3939     for ( i = 0; i <= WOOMERA_MAX_TRUNKGROUPS; i++) {
 3940       if (profile->tg_context[i] != NULL) {
 3941         ast_free(profile->tg_context[i]);
 3942       }
 3943       if (profile->tg_language[i] != NULL) {
 3944         ast_free(profile->tg_language[i]);
 3945       }
 3946     }
 3947     ast_mutex_destroy(&profile->iolock);
 3948     ast_mutex_destroy(&profile->call_count_lock);
 3949     ast_mutex_destroy(&profile->event_queue.lock);
 3950     ast_free(profile);
 3951   }
 3952 }
 3953 
 3954 
 3955 /*!
 3956  * \brief Copy a woomera profile.
 3957  */
 3958 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile,
 3959                                               woomera_profile *default_profile)
 3960 {
 3961   memcpy(new_profile, default_profile, sizeof(woomera_profile));
 3962   memset(new_profile->tg_context, 0, sizeof(new_profile->tg_context));
 3963   memset(new_profile->tg_language, 0, sizeof(new_profile->tg_language));
 3964   return new_profile;
 3965 }
 3966 
 3967 
 3968 /*!
 3969  * \brief Create a new woomera profile.
 3970  */
 3971 static woomera_profile *create_woomera_profile(woomera_profile *default_profile)
 3972 {
 3973   woomera_profile *profile;
 3974 
 3975   if((profile = ast_malloc(sizeof(woomera_profile)))) {
 3976     clone_woomera_profile(profile, default_profile);
 3977     ast_mutex_init(&profile->iolock);
 3978     ast_mutex_init(&profile->call_count_lock);
 3979     ast_mutex_init(&profile->event_queue.lock);
 3980     ast_set_flag(profile, PFLAG_DYNAMIC);
 3981   }
 3982   return profile;
 3983 }
 3984 
 3985 
 3986 /*!
 3987  * \brief Load the woomera.conf file.
 3988  */
 3989 static int config_woomera(void)
 3990 {
 3991   struct ast_config *cfg;
 3992 #if defined (AST16)
 3993   struct ast_flags config_flags = {0};
 3994 #endif
 3995   char *entry;
 3996   struct ast_variable *v;
 3997   woomera_profile *profile;
 3998   int default_context_set = 0;
 3999   int count = 0;
 4000 
 4001   memset(&default_profile, 0, sizeof(default_profile));
 4002 
 4003 #if defined (AST_JB)
 4004   memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
 4005 #endif
 4006 
 4007   default_profile.coding = 0;
 4008 
 4009 #if defined (AST16)
 4010   if ((cfg = ast_config_load(configfile, config_flags))) {
 4011 #else
 4012   if ((cfg = ast_config_load(configfile))) {
 4013 #endif
 4014     for (entry = ast_category_browse(cfg, NULL); entry != NULL; entry = ast_category_browse(cfg, entry)) {
 4015       if (strcmp(entry, "settings") == 0) {
 4016 
 4017         for (v = ast_variable_browse(cfg, entry); v ; v = v->next) {
 4018           if (!strcmp(v->name, "debug")) {
 4019             globals.debug = atoi(v->value);
 4020           } else if (!strcmp(v->name, "more_threads")) {
 4021             globals.more_threads = ast_true(v->value);
 4022           }
 4023 #if defined (AST_JB)
 4024           if (ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0) {
 4025             ast_log(LOG_NOTICE, "Woomera AST JB Opt %s = %s \n",
 4026                 v->name,v->value);
 4027             continue;
 4028           }
 4029 #endif
 4030         }
 4031 
 4032       } else if (strcmp(entry, "applications") == 0) {
 4033         for (v = ast_variable_browse(cfg, entry); v ; v = v->next) {
 4034           if (!strcasecmp(v->name, "woomeraplayback")) {
 4035             capabilities.woomeraplayback = atoi(v->value);
 4036           } else if (!strcasecmp(v->name, "woomerabackground")) {
 4037             capabilities.woomerabackground = ast_true(v->value);
 4038           } else if (!strcasecmp(v->name, "woomerarecord")) {
 4039             capabilities.woomerarecord = ast_true(v->value);
 4040           } else if (!strcasecmp(v->name, "woomeraringback")) {
 4041             capabilities.woomeraringback = ast_true(v->value);
 4042           }
 4043         }
 4044 
 4045       } else {
 4046         int new = 0;
 4047         float gain;
 4048         count++;
 4049         if (!strcmp(entry, "default")) {
 4050           profile = &default_profile;
 4051         } else {
 4052           if ((profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, entry))) {
 4053             clone_woomera_profile(profile, &default_profile);
 4054           } else {
 4055             if ((profile = create_woomera_profile(&default_profile))) {
 4056               new = 1;
 4057             } else {
 4058               ast_log(LOG_ERROR, "Memory Error!\n");
 4059             }
 4060           }
 4061         }
 4062         strncpy(profile->name, entry, sizeof(profile->name) - 1);
 4063         profile->coding = AST_FORMAT_SLINEAR;
 4064         profile->send_dtmf_enable = 1;
 4065 
 4066         /*default is inbound and outbound enabled */
 4067         ast_set_flag(profile, PFLAG_INBOUND | PFLAG_OUTBOUND);
 4068         for (v = ast_variable_browse(cfg, entry); v ; v = v->next) {
 4069           if (!strcmp(v->name, "audio_ip")) {
 4070             strncpy(profile->audio_ip, v->value, sizeof(profile->audio_ip) - 1);
 4071           } else if (!strcmp(v->name, "host")) {
 4072             strncpy(profile->woomera_host, v->value, sizeof(profile->woomera_host) - 1);
 4073           } else if (!strcmp(v->name, "max_calls")) {
 4074             int max = atoi(v->value);
 4075             if (max > 0) {
 4076               profile->max_calls = max;
 4077             }
 4078           } else if (!strcmp(v->name, "port")) {
 4079             profile->woomera_port = atoi(v->value);
 4080           } else if (!strcmp(v->name, "disabled")) {
 4081             ast_set2_flag(profile, ast_true(v->value), PFLAG_DISABLED);
 4082           } else if (!strcmp(v->name, "inbound")) {
 4083             if (ast_false(v->value)) {
 4084               ast_clear_flag(profile, PFLAG_INBOUND);
 4085             }
 4086           } else if (!strcmp(v->name, "outbound")) {
 4087             if (ast_false(v->value)) {
 4088               ast_clear_flag(profile, PFLAG_OUTBOUND);
 4089             }
 4090           } else if (!strcmp(v->name, "context")) {
 4091             if(!default_context_set){
 4092               default_context_set = 1;
 4093               strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1);
 4094             }
 4095             strncpy(profile->context, v->value, sizeof(profile->context) - 1);
 4096           } else if (!strcmp(v->name, "default_context")) {
 4097             default_context_set = 1;
 4098             strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1);
 4099           } else if (!strcmp(v->name, "language")) {
 4100             strncpy(profile->language, v->value, sizeof(profile->language) - 1);
 4101           } else if (!strcmp(v->name, "group")) {
 4102             int group_num = atoi(v->value);
 4103             if (group_num < 0) {
 4104               ast_log(LOG_ERROR, "Invalid group:%d (less than zero) - ignoring\n", group_num);
 4105             } else if (group_num > WOOMERA_MAX_TRUNKGROUPS) {
 4106               ast_log(LOG_ERROR, "Invalid trunkgroup:%d (exceeds max:%d) -ignoring\n", group_num, WOOMERA_MAX_TRUNKGROUPS);
 4107             } else {
 4108               if (profile->tg_context[group_num] != NULL) {
 4109                 ast_free(profile->tg_context[group_num]);
 4110               }
 4111               profile->tg_context[group_num] = strdup(profile->context);
 4112 
 4113               if (profile->tg_language[group_num] != NULL) {
 4114                 ast_free(profile->tg_language[group_num]);
 4115               }
 4116               if (strlen(profile->language)){
 4117                 profile->tg_language[group_num] = strdup(profile->language);
 4118               }
 4119             }
 4120 
 4121           } else if (!strcmp(v->name, "dtmf_enable")) {
 4122             profile->dtmf_enable = atoi(v->value);
 4123           } else if (!strcmp(v->name, "send_dtmf")) {
 4124             profile->send_dtmf_enable = atoi(v->value);
 4125           } else if (!strcmp(v->name, "rtp_enable")) {
 4126             profile->rtp_enable = atoi(v->value);
 4127           } else if (!strcmp(v->name, "vrtp_enable")) {
 4128             profile->vrtp_enable = atoi(v->value);
 4129           } else if (!strcmp(v->name, "bridge_enable")) {
 4130             profile->bridge_enable = atoi(v->value);
 4131           } else if (!strcmp(v->name, "fax_detect")) {
 4132             profile->faxdetect = atoi(v->value);
 4133             ast_log(LOG_NOTICE, "Profile {%s} Fax Detect %s %p \n",
 4134               entry, profile->faxdetect?"Enabled":"Disabled", profile);
 4135 
 4136           } else if (!strcmp(v->name, "jb_enable")) {
 4137             profile->jb_enable = atoi(v->value);
 4138             ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p \n",
 4139                entry, profile->jb_enable ? "Enabled" : "Disabled", profile);
 4140 
 4141           } else if (!strcmp(v->name, "jbenable")) {
 4142             profile->jb_enable = atoi(v->value);
 4143             ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p\n",
 4144                     entry, profile->jb_enable ? "Enabled" : "Disabled", profile);
 4145 
 4146           } else if (!strcmp(v->name, "progress_enable")) {
 4147                          profile->progress_enable = atoi(v->value);
 4148 
 4149           } else if (!strcmp(v->name, "coding")) {
 4150             if (strcasecmp(v->value, "alaw") == 0) {
 4151               profile->coding = AST_FORMAT_ALAW;
 4152             }
 4153             else if (strcasecmp(v->value, "pcma") == 0) {
 4154               profile->coding = AST_FORMAT_ALAW;
 4155             }
 4156             else if (strcasecmp(v->value, "ulaw") == 0) {
 4157               profile->coding = AST_FORMAT_ULAW;
 4158             }
 4159             else if (strcasecmp(v->value, "pcmu") == 0) {
 4160               profile->coding = AST_FORMAT_ULAW;
 4161             }
 4162 
 4163           } else if (!strcmp(v->name, "videocoding")) {
 4164             if (strcasecmp(v->value, "h263") == 0) {
 4165               profile->videocoding = AST_FORMAT_H263;
 4166             }
 4167             else if (strcasecmp(v->value, "mpeg4") == 0) {
 4168               profile->videocoding = AST_FORMAT_MP4_VIDEO;
 4169             }
 4170 
 4171           } else if (!strcmp(v->name, "woomera_udp_seq")) {
 4172             int udp_seq = atoi(v->value);
 4173             if (udp_seq > 0) {
 4174               profile->udp_seq = 1;
 4175             }
 4176 
 4177           } else if (!strcmp(v->name, "base_media_port")) {
 4178             int base_port = atoi(v->value);
 4179             if (base_port > 0) {
 4180               woomera_base_media_port = base_port;
 4181               woomera_max_media_port = woomera_base_media_port + WOOMERA_MAX_MEDIA_PORTS;
 4182             }
 4183 
 4184           } else if (!strcmp(v->name, "max_media_ports")) {
 4185             int max_ports = atoi(v->value);
 4186             if (max_ports > 0 && max_ports > WOOMERA_MAX_MEDIA_PORTS) {
 4187               woomera_max_media_port = woomera_base_media_port + max_ports;
 4188             }
 4189 
 4190           } else if (!strcmp(v->name, "rxgain") && profile->coding) {
 4191             if (sscanf(v->value, "%f", &gain) != 1) {
 4192               ast_log(LOG_NOTICE, "Invalid rxgain: %s\n", v->value);
 4193             } else {
 4194               woomera_config_gain(profile,gain, 1);
 4195             }
 4196           } else if (!strcmp(v->name, "txgain") && profile->coding) {
 4197              if (sscanf(v->value, "%f", &gain) != 1) {
 4198               ast_log(LOG_NOTICE, "Invalid txgain: %s\n", v->value);
 4199             } else {
 4200               woomera_config_gain(profile, gain, 0);
 4201             }
 4202           }
 4203         }
 4204         ASTOBJ_CONTAINER_LINK(&woomera_profile_list, profile);
 4205       }
 4206     }
 4207     ast_config_destroy(cfg);
 4208   } else {
 4209     return 0;
 4210   }
 4211 
 4212   return count;
 4213 
 4214 }
 4215 
 4216 
 4217 /*!
 4218  * \brief Create a raw media socket.
 4219  */
 4220 static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client)
 4221 {
 4222   int rc, sd = -1;
 4223   struct sockaddr_in servAddr, *addr, cliAddr;
 4224   struct hostent hps, *hp;
 4225   struct hostent *result;
 4226   char buf[512];
 4227   int err = 0;
 4228 
 4229   memset(&hps, 0, sizeof(hps));
 4230   hp = &hps;
 4231 
 4232   if(sockaddr) {
 4233     addr = sockaddr;
 4234   } else {
 4235     addr = &servAddr;
 4236   }
 4237 
 4238   if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) > -1) {
 4239 
 4240     gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
 4241     if (result) {
 4242 
 4243       addr->sin_family = hp->h_addrtype;
 4244       memcpy((char *) &addr->sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
 4245       addr->sin_port = htons(port);
 4246 
 4247       if (globals.debug > 4) {
 4248         ast_log(LOG_NOTICE, "MEDIA udp IP=%s:%d\n", ast_inet_ntoa(addr->sin_addr), port);
 4249       }
 4250 
 4251       if (client) {
 4252         cliAddr.sin_family = AF_INET;
 4253         cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 4254         cliAddr.sin_port = htons(0);
 4255           rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
 4256       } else {
 4257         rc = bind(sd, (struct sockaddr *) addr, sizeof(cliAddr));
 4258       }
 4259       if (rc < 0) {
 4260         if (globals.debug > 4) {
 4261           ast_log(LOG_ERROR,
 4262                   "Failed to bind to udp socket  %s/%i %s\n",
 4263                    ip, port, strerror(errno));
 4264         }
 4265 
 4266         woomera_close_socket(&sd);
 4267 
 4268       } else if (globals.debug > 5) {
 4269         ast_log(LOG_NOTICE, "Socket Binded %s to %s/%d\n",
 4270               client ? "client" : "server", ip, port);
 4271       }
 4272 
 4273     } else {
 4274       ast_log(LOG_ERROR,
 4275           "Error opening udp: gethostbyname failed  %s/%i %s\n",
 4276           ip, port, strerror(errno));
 4277 
 4278       woomera_close_socket(&sd);
 4279     }
 4280   } else {
 4281     ast_log(LOG_ERROR,
 4282             "failed to create a socket! %s/%i %s\n",
 4283              ip, port, strerror(errno));
 4284   }
 4285 
 4286   return sd;
 4287 }
 4288 
 4289 /*!
 4290  * \brief Create an rtp session.
 4291  */
 4292 static struct ast_rtp * create_rtp(char *ip)
 4293 {
 4294   struct hostent hps, *hp;
 4295   struct hostent *result;
 4296   char buf[512];
 4297   int err = 0;
 4298   struct ast_rtp *rtp = NULL;
 4299   struct in_addr addr;
 4300   struct sockaddr_in us;
 4301 
 4302   memset(&hps, 0, sizeof(hps));
 4303   hp = &hps;
 4304 
 4305   gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
 4306   if (result)
 4307   {
 4308     memcpy((char *) &addr, hp->h_addr_list[0], hp->h_length);
 4309     rtp = ast_rtp_new_with_bindaddr(sched, io, 1 /*rtcp*/, 0, addr);
 4310 
 4311     if (rtp)
 4312     {
 4313       ast_rtp_get_us(rtp, &us);
 4314       if (globals.debug > 2) {
 4315         ast_log(LOG_DEBUG,"Created RTP IP=%s\n", ast_inet_ntoa(addr));
 4316       }
 4317     }
 4318     else
 4319     {
 4320       ast_log(LOG_ERROR,"Failed to create RTP IP=%s %s\n", ip, strerror(errno));
 4321     }
 4322   }
 4323   else
 4324   {
 4325     ast_log(LOG_ERROR,
 4326             "Failed to get host for RTP IP=%s %s\n",
 4327             ip, strerror(errno));
 4328   }
 4329 
 4330   return rtp;
 4331 }
 4332 
 4333 
 4334 /*!
 4335  * \brief Create a socket and connect it to the Woomera server specified in the profile.
 4336  */
 4337 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags)
 4338 {
 4339   struct sockaddr_in localAddr, remoteAddr;
 4340   struct hostent *hp, *result;
 4341   struct hostent ahp;
 4342   int res = 0, err = 0;
 4343   hp = &ahp;
 4344   char buf[512];
 4345 
 4346   *new_socket = -1;
 4347 
 4348   gethostbyname_r(profile->woomera_host, hp, buf, sizeof(buf), &result, &err);
 4349   if (result) {
 4350     remoteAddr.sin_family = hp->h_addrtype;
 4351     memcpy((char *) &remoteAddr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
 4352     remoteAddr.sin_port = htons(profile->woomera_port);
 4353     do {
 4354       /* create socket */
 4355       *new_socket = socket(AF_INET, SOCK_STREAM, 0);
 4356       if (*new_socket < 0) {
 4357         ast_log(LOG_ERROR, "Cannot open socket to %s/%d\n", profile->woomera_host, profile->woomera_port);
 4358         res = 0;
 4359         break;
 4360       }
 4361 
 4362       /* bind any port number */
 4363       localAddr.sin_family = AF_INET;
 4364       localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 4365       localAddr.sin_port = htons(0);
 4366 
 4367       res = bind(*new_socket, (struct sockaddr *) &localAddr, sizeof(localAddr));
 4368       if (res < 0) {
 4369         ast_log(LOG_ERROR, "Cannot bind to %s/%d\n", profile->woomera_host, profile->woomera_port);
 4370         woomera_close_socket(new_socket);
 4371         res = 0;
 4372         break;
 4373       }
 4374 
 4375       /* connect to server */
 4376       res = connect(*new_socket, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
 4377       if (res < 0) {
 4378         //ast_log(LOG_ERROR, "Cannot connect to {%s} %s:%d\n", profile->name, profile->woomera_host, profile->woomera_port);
 4379         res = 0;
 4380         woomera_close_socket(new_socket);
 4381         break;
 4382       }
 4383       res = 1;
 4384     } while(0);
 4385 
 4386   } else {
 4387     if (globals.debug > 2) {
 4388       ast_log(LOG_ERROR, "Host lookup failed for {%s} %s/%d\n",
 4389               profile->name, profile->woomera_host, profile->woomera_port);
 4390     }
 4391     res = 0;
 4392   }
 4393   if (res > 0) {
 4394     int flag = 1;
 4395     woomera_message wmsg;
 4396     memset(&wmsg,0,sizeof(wmsg));
 4397 
 4398     /* disable nagle's algorythm */
 4399     res = setsockopt(*new_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
 4400 
 4401     if (!(flags & WCFLAG_NOWAIT)) {
 4402       /* kickstart the session waiting for a HELLO */
 4403       res = woomera_printf(NULL, *new_socket, "%s", WOOMERA_RECORD_SEPARATOR);
 4404       if (res < 0 ) {
 4405         woomera_close_socket(new_socket);
 4406         return *new_socket;
 4407       }
 4408 
 4409       if ((res = woomera_message_parse(*new_socket,
 4410                                        &wmsg,
 4411                                        -5000, /*WOOMERA_HARD_TIMEOUT,*/
 4412                                        profile,
 4413                                        NULL
 4414                                       )) < 0) {
 4415         ast_log(LOG_ERROR, "{%s} Timed out waiting for a hello from woomera!\n", profile->name);
 4416         woomera_close_socket(new_socket);
 4417         return *new_socket;
 4418       }
 4419 
 4420       if (res > 0 && strcasecmp(wmsg.command, "HELLO")) {
 4421         ast_log(LOG_ERROR, "{%s} unexpected reply [%s] while waiting for a hello from woomera!\n", profile->name, wmsg.command);
 4422         woomera_close_socket(new_socket);
 4423       } else {
 4424         char *audio_format, *video_format;
 4425         if (globals.debug > 2) {
 4426           ast_log(LOG_NOTICE, "Woomera Got HELLO on connect! %s Version %s\n", profile->name, woomera_message_header(&wmsg, "Version"));
 4427         }
 4428         if (!svrversion_init && woomera_message_header(&wmsg, "Version")) {
 4429           svrversion_init = 1;
 4430           strncpy(svrversion,
 4431                   woomera_message_header(&wmsg, "Version"),
 4432                   sizeof(svrversion)-1);
 4433         }
 4434 
 4435         audio_format = woomera_message_header(&wmsg, "Raw-Format");
 4436         if (!audio_format) {
 4437           audio_format = woomera_message_header(&wmsg, "Raw-Audio-Format");
 4438         }
 4439         if (!audio_format) {
 4440           audio_format = woomera_message_header(&wmsg, "RTP-Audio-Format");
 4441         }
 4442 
 4443         if (audio_format) {
 4444 
 4445           profile->coding = AST_FORMAT_SLINEAR;
 4446 
 4447           if (strncasecmp(audio_format, "PCM-16", 6) == 0) {
 4448             profile->coding = AST_FORMAT_SLINEAR;
 4449           } else if (strncasecmp(audio_format, "ULAW", 4) == 0) {
 4450             profile->coding = AST_FORMAT_ULAW;
 4451           } else if (strncasecmp(audio_format, "PCMU", 4) == 0) {
 4452             profile->coding = AST_FORMAT_ULAW;
 4453           } else if (strncasecmp(audio_format, "ALAW", 4) == 0) {
 4454             profile->coding = AST_FORMAT_ALAW;
 4455           } else if (strncasecmp(audio_format, "PCMA", 4) == 0) {
 4456             profile->coding = AST_FORMAT_ALAW;
 4457           } else {
 4458             ast_log(LOG_ERROR, "Error: Invalid audio format %s\n",
 4459                     audio_format);
 4460           }
 4461 
 4462           if (globals.debug > 2) {
 4463             ast_log(LOG_NOTICE, "Setting audio format to %s %i (p%i:u%i:a%i)\n",
 4464                       audio_format, profile->coding,
 4465                       AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FORMAT_ALAW);
 4466           }
 4467         }
 4468 
 4469         video_format = woomera_message_header(&wmsg, "RTP-Video-Format");
 4470         if (video_format) {
 4471           profile->videocoding = AST_FORMAT_H261;
 4472           if (strncasecmp(video_format, "H261", 4) == 0) {
 4473             profile->videocoding = AST_FORMAT_H261;
 4474           } else if (strncasecmp(video_format, "H263", 4) == 0) {
 4475             profile->videocoding = AST_FORMAT_H263;
 4476           } else if (strncasecmp(video_format, "H263-1998", 9) == 0) {
 4477             profile->videocoding = AST_FORMAT_H263_PLUS;
 4478           } else if (strncasecmp(video_format, "H264", 4) == 0) {
 4479             profile->videocoding = AST_FORMAT_H264;
 4480           } else if (strncasecmp(video_format, "MPV4-ES", 5) == 0) {
 4481             profile->videocoding = AST_FORMAT_MP4_VIDEO;
 4482           } else {
 4483             ast_log(LOG_ERROR, "Error: Invalid video format %s\n", video_format);
 4484           }
 4485         }
 4486       }
 4487     }
 4488   } else {
 4489     /*
 4490     if (globals.debug > 2) {
 4491       ast_log(LOG_ERROR, "Woomera {%s} connection failed: %s/%d %s\n",
 4492         profile->name, profile->woomera_host, profile->woomera_port, strerror(errno));
 4493     }
 4494     */
 4495     woomera_close_socket(new_socket);
 4496   }
 4497 
 4498   return *new_socket;
 4499 }
 4500 
 4501 
 4502 /*!
 4503  * \brief Create a thread for each profile defined in the conf file.
 4504  */
 4505 static int init_woomera(void)
 4506 {
 4507   woomera_profile *profile;
 4508   ast_mutex_lock(&lock);
 4509 
 4510   if (!config_woomera()) {
 4511     ast_mutex_unlock(&lock);
 4512     return 0;
 4513   }
 4514   ASTOBJ_CONTAINER_TRAVERSE(&woomera_profile_list, 1, do {
 4515     ASTOBJ_RDLOCK(iterator);
 4516     profile = iterator;
 4517     if (!ast_test_flag(profile, PFLAG_DISABLED)) {
 4518       launch_woomera_thread(profile);
 4519     }
 4520     ASTOBJ_UNLOCK(iterator);
 4521   } while(0));
 4522 
 4523   ast_mutex_unlock(&lock);
 4524   return 1;
 4525 }
 4526 
 4527 
 4528 /*!
 4529  * \brief Allocate and initialise a channel struct.
 4530  */
 4531 static struct ast_channel *woomera_new(const char *type,
 4532                                        int format,
 4533                                        void *data,
 4534                                        int *cause,
 4535                                        woomera_profile *parent_profile)
 4536 {
 4537   private_object *tech_pvt;
 4538   struct ast_channel *chan = NULL;
 4539   char name[100];
 4540 
 4541   snprintf(name, sizeof(name), "%s/%s-%04x", type, (char *)data, rand() & 0xffff);
 4542 
 4543   if (!(tech_pvt = ast_malloc(sizeof(private_object)))) {
 4544     ast_log(LOG_ERROR, "Memory Error!\n");
 4545     return NULL;
 4546   }
 4547   memset(tech_pvt, 0, sizeof(private_object));
 4548 
 4549 #if defined (AST14) || defined (AST16)
 4550   chan =  ast_channel_alloc(0, AST_STATE_DOWN, "", "", "", "", "", 0, "%s", name);
 4551 #else
 4552   chan = ast_channel_alloc(1);
 4553 #endif
 4554 
 4555   if (chan) {
 4556     chan->nativeformats = WFORMAT;
 4557 #if !defined (AST14) && !defined (AST16)
 4558     chan->type = type;
 4559     snprintf(chan->name, sizeof(chan->name), "%s/%s-%04x", chan->type, (char *)data, rand() & 0xffff);
 4560 #endif
 4561 
 4562     chan->writeformat = chan->rawwriteformat = chan->readformat = WFORMAT;
 4563     chan->_state = AST_STATE_DOWN;
 4564     chan->_softhangup = 0;
 4565 
 4566     tech_count++;
 4567     tech_pvt->coding = WFORMAT;
 4568 
 4569     ast_mutex_init(&tech_pvt->iolock);
 4570     ast_mutex_init(&tech_pvt->event_queue.lock);
 4571     tech_pvt->command_channel = -1;
 4572     chan->tech_pvt = tech_pvt;
 4573     chan->tech = &technology;
 4574     tech_pvt->udp_socket = -1;
 4575 
 4576     ast_clear_flag(chan, AST_FLAGS_ALL);
 4577     memset(&tech_pvt->frame, 0, sizeof(tech_pvt->frame));
 4578     tech_pvt->frame.frametype = AST_FRAME_VOICE;
 4579     tech_pvt->frame.subclass = WFORMAT;
 4580     tech_pvt->frame.offset = AST_FRIENDLY_OFFSET;
 4581 
 4582     tech_pvt->owner = chan;
 4583 
 4584     chan->nativeformats = tech_pvt->coding | tech_pvt->videocoding;
 4585     chan->writeformat = chan->rawwriteformat = chan->readformat = tech_pvt->coding;
 4586     tech_pvt->frame.subclass = tech_pvt->coding;
 4587 
 4588     tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING;
 4589 
 4590     ast_copy_string(tech_pvt->mohinterpret, mohinterpret, sizeof(tech_pvt->mohinterpret));
 4591     ast_copy_string(tech_pvt->mohsuggest, mohsuggest, sizeof(tech_pvt->mohsuggest));
 4592 
 4593     ASTOBJ_CONTAINER_LINK(&private_object_list, tech_pvt);
 4594 
 4595     ast_mutex_lock(&usecnt_lock);
 4596     usecnt++;
 4597     ast_mutex_unlock(&usecnt_lock);
 4598 
 4599   } else {
 4600     ast_log(LOG_ERROR, "Can't allocate a channel\n");
 4601   }
 4602 
 4603   return chan;
 4604 }
 4605 
 4606 
 4607 /**************************** CHANNEL INTERFACES ******************************/
 4608 
 4609 
 4610 /*!
 4611  * Channel interface.
 4612  * \brief Parse 'data' a url-like destination string, allocate a channel and a private
 4613  * structure and return the newly-setup channel.
 4614  */
 4615 static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause)
 4616 {
 4617   struct ast_channel *chan = NULL;
 4618 
 4619   if (globals.panic) {
 4620     return NULL;
 4621   }
 4622 
 4623   if ((chan = woomera_new(type, format, data, cause, NULL))) {
 4624     private_object *tech_pvt;
 4625 
 4626     tech_pvt = chan->tech_pvt;
 4627 
 4628     if (tech_pvt->owner) {
 4629       tech_pvt->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
 4630     }
 4631 
 4632     ast_set_flag(tech_pvt, TFLAG_PBX); /* so we know we don't have to free the channel ourselves */
 4633 
 4634     if (globals.debug > 1 && option_verbose > 1) {
 4635       if (option_verbose > 2) {
 4636         ast_verbose(WOOMERA_DEBUG_PREFIX "+++REQ %s\n", chan->name);
 4637       }
 4638     }
 4639 
 4640   } else {
 4641     ast_log(LOG_ERROR, "Woomera: Can't allocate a channel\n");
 4642   }
 4643 
 4644   return chan;
 4645 }
 4646 
 4647 #if defined (AST14) || defined (AST16)
 4648 
 4649 /*!
 4650  * Channel interface.
 4651  */
 4652 static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 4653 {
 4654   return 0;
 4655 }
 4656 #endif
 4657 
 4658 
 4659 /*!
 4660  * Channel interface.
 4661  * \brief Send a DTMF character.
 4662  */
 4663 static int tech_send_digit(struct ast_channel *self, char digit)
 4664 {
 4665   private_object *tech_pvt = self->tech_pvt;
 4666 
 4667   if ( tech_pvt->send_dtmf_enable == 0 ) {
 4668      /* Returning non-zero to cause Asterisk to send the digits using
 4669       * in-band tones.
 4670       */
 4671     return 1;
 4672   }
 4673 
 4674   int res = 0;
 4675 
 4676   if (globals.debug > 1 && option_verbose > 2) {
 4677     if (option_verbose > 2) {
 4678       ast_verbose(WOOMERA_DEBUG_PREFIX "+++DIGIT %s '%c'\n", self->name, digit);
 4679     }
 4680   }
 4681 
 4682   /* Save the digits for the monitor thread to send the DTMF command.
 4683    */
 4684   ast_mutex_lock(&tech_pvt->iolock);
 4685   snprintf(tech_pvt->dtmfbuf + strlen(tech_pvt->dtmfbuf), sizeof(tech_pvt->dtmfbuf), "%c", digit);
 4686   ast_set_flag(tech_pvt, TFLAG_DTMF);
 4687   ast_mutex_unlock(&tech_pvt->iolock);
 4688 
 4689   return res;
 4690 }
 4691 
 4692 
 4693 /*!
 4694  * Channel interface.
 4695  * \brief Initiate a call on a channel.
 4696  * 'dest' has been passed telling you where to call but you may already have
 4697  * that information from the requester method not sure why it sends it twice,
 4698  * maybe it changed since then *shrug* You also have timeout (in ms) so you can
 4699  * tell how long the caller is willing to wait for the call to be complete.
 4700  */
 4701 static int tech_call(struct ast_channel *self, char *dest, int timeout)
 4702 {
 4703   private_object *tech_pvt = self->tech_pvt;
 4704   char *workspace;
 4705   char *p;
 4706   char *c;
 4707 
 4708 #if !defined (AST14) && !defined (AST16)
 4709   self->type = WOOMERA_CHAN_NAME;
 4710 #endif
 4711 
 4712   self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 4713 
 4714   if (globals.panic) {
 4715     goto tech_call_failed;
 4716   }
 4717 
 4718   if (globals.debug > 2) {
 4719     ast_log(LOG_NOTICE, "TECH CALL %s (%s <%s>)  pres=0x%02X dest=%s\n",
 4720             self->name, self->cid.cid_name,
 4721             self->cid.cid_num,
 4722             self->cid.cid_pres,
 4723             dest);
 4724   }
 4725 
 4726   if (self->cid.cid_name) {
 4727     strncpy(tech_pvt->cid_name, self->cid.cid_name, sizeof(tech_pvt->cid_name)-1);
 4728   }
 4729 
 4730   if (self->cid.cid_num) {
 4731     strncpy(tech_pvt->cid_num, self->cid.cid_num, sizeof(tech_pvt->cid_num)-1);
 4732   }
 4733 
 4734   tech_pvt->cid_pres = self->cid.cid_pres;
 4735 
 4736   if (self->cid.cid_rdnis) {
 4737     tech_pvt->cid_rdnis = strdup(self->cid.cid_rdnis);
 4738   }
 4739 
 4740   /* Parse out dialstring parts.
 4741    * [profile/][protocol:]address
 4742    */
 4743   if ((workspace = ast_strdupa(dest))) {
 4744     char *addr, *profile_name, *protocol = NULL;
 4745     woomera_profile *profile;
 4746     int err;
 4747 
 4748     if ((addr = strchr(workspace, ':'))) {
 4749       *addr = '\0';
 4750       addr++;
 4751       if ((protocol = strchr(workspace, '/'))) {
 4752         profile_name = workspace;
 4753         *protocol = '\0';
 4754         protocol++;
 4755       }
 4756       else {
 4757         profile_name = "default";
 4758         protocol = workspace;
 4759       }
 4760     } else {
 4761       profile_name = "default";
 4762       protocol = NULL;
 4763       addr = workspace;
 4764     }
 4765 
 4766     if (! (profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, profile_name))) {
 4767       ast_log(LOG_WARNING, "Profile %s not found, using default\n", profile_name);
 4768       profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, "default");
 4769     }
 4770 
 4771     if (!profile) {
 4772       ast_log(LOG_ERROR, "Call aborted, unable to find profile: %s\n", profile_name);
 4773       goto tech_call_failed;
 4774     }
 4775 
 4776     if (!ast_test_flag(profile, PFLAG_OUTBOUND)) {
 4777       ast_log(LOG_ERROR, "This profile (%s) is not allowed to make outbound calls! Call Aborted!\n", profile_name);
 4778       goto tech_call_failed;
 4779     }
 4780 
 4781     if (profile->max_calls) {
 4782       if (profile->call_count >= profile->max_calls) {
 4783         if (globals.debug > 1 && option_verbose > 2) {
 4784           ast_log(LOG_ERROR, "This profile (%s) is at call limit of %d\n",
 4785                   profile_name, profile->max_calls);
 4786         }
 4787         goto tech_call_failed;
 4788       }
 4789     }
 4790 
 4791     snprintf(tech_pvt->dest, sizeof(tech_pvt->dest), "%s", addr ? addr : "");
 4792     snprintf(tech_pvt->proto, sizeof(tech_pvt->proto), "%s", protocol ? protocol : "");
 4793 
 4794     if (globals.debug > 2) {
 4795       ast_log(LOG_NOTICE, "TECH CALL: profile=%s proto=%s addr=%s audiocoding=%x videocoding=%x\n",
 4796               profile_name, protocol, addr, profile->coding,  profile->videocoding);
 4797     }
 4798 
 4799     tech_pvt->timeout = timeout;
 4800     err = tech_init(tech_pvt, profile, TFLAG_OUTBOUND);
 4801     if (err) {
 4802       if (globals.debug > 2) {
 4803         ast_log(LOG_ERROR, "Outbound Call Failed \n");
 4804       }
 4805       goto tech_call_failed;
 4806     }
 4807 
 4808 #if 1
 4809     if ((p = strrchr(self->name, '/'))) {
 4810       c = p-1;
 4811       if (*c == 'c' || *c == 'C') {
 4812         ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED);
 4813         ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER);
 4814       }
 4815     }
 4816 #endif
 4817 
 4818     woomera_send_progress(tech_pvt);
 4819   }
 4820   self->hangupcause = AST_CAUSE_NORMAL_CLEARING;
 4821   return 0;
 4822 
 4823 tech_call_failed:
 4824 
 4825   if (globals.debug > 1 && option_verbose > 2) {
 4826     ast_log(LOG_ERROR, "Error: Outbound Call Failed %p \n", tech_pvt);
 4827   }
 4828   self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 4829   my_ast_softhangup(self, tech_pvt, AST_SOFTHANGUP_EXPLICIT);
 4830   return -1;
 4831 }
 4832 
 4833 
 4834 /*!
 4835  * Channel interface.
 4836  * End a call on channel 'self'
 4837  * Now is your chance to tear down and free the private object
 4838  * from the channel it's about to be freed so you must do so now
 4839  * or the object is lost.  Well I guess you could tag it for reuse
 4840  * or for destruction and let a monitor thread deal with it too.
 4841  * during the load_module routine you have every right to start up
 4842  * your own fancy schmancy bunch of threads or whatever else
 4843  * you want to do.
 4844  */
 4845 static int tech_hangup(struct ast_channel *self)
 4846 {
 4847   const char *ds;
 4848   private_object *tech_pvt = self->tech_pvt;
 4849   int res = 0;
 4850 
 4851   if (globals.debug > 2) {
 4852     ast_log(LOG_NOTICE, "TECH HANGUP [%s] tech_pvt=%p c=%p\n", self->name, tech_pvt, self);
 4853   }
 4854 
 4855   if (tech_pvt) {
 4856 
 4857     ast_mutex_lock(&tech_pvt->iolock);
 4858 
 4859     ast_set_flag(tech_pvt, TFLAG_TECHHANGUP);
 4860     tech_pvt->owner = NULL;
 4861     self->tech_pvt = NULL;
 4862 
 4863     if (!self ||
 4864        (!(ds = pbx_builtin_getvar_helper(self, "DIALSTATUS")) &&
 4865         !(ds = ast_cause2str(self->hangupcause)))) {
 4866       ds = "NOEXIST";
 4867     }
 4868 
 4869     ast_copy_string(tech_pvt->ds, ds, sizeof(tech_pvt->ds));
 4870 
 4871     ds = pbx_builtin_getvar_helper(self, "PRI_CAUSE");
 4872     if (ds && atoi(ds)) {
 4873       tech_pvt->pri_cause = atoi(ds);
 4874     } else if (self->hangupcause) {
 4875       tech_pvt->pri_cause = self->hangupcause;
 4876     } else {
 4877       tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING;
 4878     }
 4879 
 4880     if (globals.debug > 2) {
 4881       ast_log(LOG_NOTICE, "TECH HANGUP [%s] Cause=%i HangCause=%i ds=%s\n",
 4882               self->name, tech_pvt->pri_cause, self->hangupcause,  ds ? ds : "N/A");
 4883     }
 4884 
 4885     if (tech_pvt->dsp) {
 4886       tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
 4887       ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
 4888       tech_pvt->ast_dsp = 0;
 4889     }
 4890 
 4891     if (ast_test_flag(tech_pvt, TFLAG_INTHREAD)) {
 4892       ast_set_flag(tech_pvt, TFLAG_ABORT);
 4893       ast_set_flag(tech_pvt, TFLAG_DESTROY);
 4894 
 4895       if (globals.debug > 2) {
 4896         ast_log(LOG_NOTICE, "TECH HANGUP IN THREAD! tpvt=%p\n",
 4897             tech_pvt);
 4898       }
 4899 
 4900       self->tech_pvt = NULL;
 4901       ast_mutex_unlock(&tech_pvt->iolock);
 4902 
 4903     } else {
 4904       int ast_hangup = 0;
 4905 
 4906       if (globals.debug > 4) {
 4907         ast_log(LOG_NOTICE, "TECH HANGUP:  Destroying tech not in thread! Callid=%s tech_pvt=%p Dir=%s\n",
 4908                 tech_pvt->callid, tech_pvt,
 4909                 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN" );
 4910       }
 4911 
 4912       if (ast_test_flag(tech_pvt, TFLAG_AST_HANGUP)) {
 4913         ast_hangup = 1;
 4914       }
 4915       self->tech_pvt = NULL;
 4916       ast_mutex_unlock(&tech_pvt->iolock);
 4917 
 4918       if (!ast_test_flag(tech_pvt, TFLAG_DESTROY)) {
 4919 
 4920         if (ast_hangup && tech_pvt->profile) {
 4921           ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 4922           tech_pvt->profile->call_ast_hungup--;
 4923           ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 4924         }
 4925 
 4926         tech_destroy(tech_pvt,NULL);
 4927         if (globals.debug > 2) {
 4928           ast_log(LOG_NOTICE, "TECH HANGUP NOT IN THREAD!\n");
 4929         }
 4930       } else {
 4931         ast_log(LOG_ERROR, "Tech Hangup -> Device already destroyed. Should not happend! \n");
 4932       }
 4933     }
 4934   } else {
 4935     if (globals.debug > 2) {
 4936       ast_log(LOG_NOTICE, "ERROR: NO TECH ON TECH HANGUP!\n");
 4937     }
 4938   }
 4939 
 4940   self->tech_pvt = NULL;
 4941 
 4942   return res;
 4943 }
 4944 
 4945 
 4946 /*!
 4947  * Channel interface.
 4948  * Answer a call on a channel.
 4949  * If being 'answered' means anything special to your channel
 4950  * now is your chance to do it!
 4951  */
 4952 static int tech_answer(struct ast_channel *self)
 4953 {
 4954   private_object *tech_pvt;
 4955   int res = 0;
 4956 
 4957   tech_pvt = self->tech_pvt;
 4958   if (!tech_pvt) {
 4959     return -1;
 4960   }
 4961 
 4962   ast_mutex_lock(&tech_pvt->iolock);
 4963 
 4964   if (globals.debug > 1 && option_verbose > 1) {
 4965     if (option_verbose > 2) {
 4966       ast_verbose(WOOMERA_DEBUG_PREFIX "+++ANSWER %s\n", self->name);
 4967     }
 4968   }
 4969 
 4970   if (!ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
 4971     /* Only answer the inbound calls */
 4972     ast_set_flag(tech_pvt, TFLAG_ANSWER);
 4973   } else {
 4974     ast_log(LOG_ERROR, "Warning: AST trying to Answer OUTBOUND Call!\n");
 4975   }
 4976 
 4977   ast_set_flag(tech_pvt, TFLAG_UP);
 4978   ast_setstate(self, AST_STATE_UP);
 4979 
 4980   ast_mutex_unlock(&tech_pvt->iolock);
 4981 
 4982   return res;
 4983 }
 4984 
 4985 /*!
 4986  * Try to route faxes to the 'fax' extension.
 4987  */
 4988 static void handle_fax(private_object *tech_pvt)
 4989 {
 4990   struct ast_channel *owner;
 4991 
 4992   owner = tech_pvt->owner;
 4993 
 4994   if (tech_pvt->owner) {
 4995     ast_verbose(WOOMERA_DEBUG_PREFIX "FAX TONE %s\n", tech_pvt->callid);
 4996 
 4997     if (!tech_pvt->faxhandled) {
 4998       tech_pvt->faxhandled++;
 4999       if (strcmp(owner->exten, "fax")) {
 5000 #if defined (AST14) || defined (AST16)
 5001         const char *target_context = S_OR(owner->macrocontext, owner->context);
 5002 #else
 5003         const char *target_context = ast_strlen_zero(owner->macrocontext) ? owner->context : owner->macrocontext;
 5004 #endif
 5005         if (ast_exists_extension(owner, target_context, "fax", 1, owner->cid.cid_num)) {
 5006           if (option_verbose > 2) {
 5007             ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", owner->name);
 5008           }
 5009 
 5010           pbx_builtin_setvar_helper(owner, "FAXEXTEN", owner->exten);
 5011           if (ast_async_goto(owner, target_context, "fax", 1))
 5012             ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", owner->name, target_context);
 5013         } else {
 5014           ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
 5015         }
 5016       }
 5017     }
 5018   }
 5019 }
 5020 
 5021 
 5022 /*!
 5023  * Channel interface.
 5024  * \brief Read an audio frame from a channel.
 5025  * You need to read data from your channel and convert/transfer the
 5026  * data into a newly allocated struct ast_frame object.
 5027  */
 5028 static struct ast_frame *tech_read(struct ast_channel *self)
 5029 {
 5030   private_object *tech_pvt = self->tech_pvt;
 5031   int res = 0;
 5032   struct ast_frame *f,*rf;
 5033 
 5034   rf = NULL;
 5035 
 5036   if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT))
 5037   {
 5038     return NULL;
 5039   }
 5040 
 5041   if (tech_pvt->rtp_enable)
 5042   {
 5043     switch(self->fdno) {
 5044       case 0:
 5045         rf = ast_rtp_read(tech_pvt->rtp);   /* RTP Audio */
 5046         break;
 5047 
 5048       case 1:
 5049         rf = ast_rtp_read(tech_pvt->vrtp);  /* RTP Video */
 5050         if (globals.debug > 4) {
 5051           if (option_verbose > 4) {
 5052             ast_verbose(WOOMERA_DEBUG_PREFIX "VIDEO READ %s \n", self->name);
 5053           }
 5054         }
 5055         break;
 5056 
 5057       default:
 5058         ast_verbose(WOOMERA_DEBUG_PREFIX "tech_read() %s fdno=%d \n", self->name, self->fdno);
 5059         break;
 5060     }
 5061 
 5062     if (rf)
 5063     {
 5064       /* Don't forward RFC2833 */
 5065       if (rf->frametype == AST_FRAME_DTMF_BEGIN || rf->frametype == AST_FRAME_DTMF_END) {
 5066         ast_log(LOG_DTMF, " Ignoring DTMF (%c) in RTP frame \n", rf->subclass);
 5067         tech_pvt->frame.frametype = AST_FRAME_NULL;
 5068       } else {
 5069         tech_pvt->frame.frametype = rf->frametype;
 5070         tech_pvt->frame.subclass = rf->subclass;
 5071         tech_pvt->frame.offset = rf->offset;
 5072         tech_pvt->frame.datalen = rf->datalen;
 5073         tech_pvt->frame.samples = rf->samples;
 5074         tech_pvt->frame.data = rf->data;
 5075       }
 5076     }
 5077   }
 5078   else
 5079   {
 5080 
 5081 tech_read_again:
 5082 
 5083     if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT)) {
 5084       return NULL;
 5085     }
 5086 
 5087     res = waitfor_socket(tech_pvt->udp_socket, 1000);
 5088 
 5089     if (res < 1) {
 5090       return NULL;
 5091 
 5092     } else if (res == 0) {
 5093       goto tech_read_again;
 5094     }
 5095 
 5096     res = read(tech_pvt->udp_socket, tech_pvt->fdata + AST_FRIENDLY_OFFSET, FRAME_LEN);
 5097 
 5098     if (res < 1) {
 5099       return NULL;
 5100     }
 5101 
 5102     /* Used for adding sequence numbers to udp packets.
 5103        should only be used for debugging */
 5104     if (tech_pvt->profile->udp_seq){
 5105       char *rxdata = (char*)(tech_pvt->fdata + AST_FRIENDLY_OFFSET);
 5106       res -= 4;
 5107 
 5108       if (tech_pvt->rx_udp_seq == 0) {
 5109         tech_pvt->rx_udp_seq = *((unsigned int*)(&rxdata[res]));
 5110         if (globals.debug > 2) {
 5111           ast_log(LOG_NOTICE, "%s: Starting Rx Sequence %i Len=%i!\n", self->name,tech_pvt->rx_udp_seq, res);
 5112         }
 5113       } else {
 5114         tech_pvt->rx_udp_seq++;
 5115         if (tech_pvt->rx_udp_seq != *((unsigned int*)(&rxdata[res]))) {
 5116           ast_log(LOG_NOTICE, "%s: Error: Missing Rx Sequence Expect %i Received %i!\n",
 5117                   self->name,tech_pvt->rx_udp_seq, *((unsigned int*)(&rxdata[res])));
 5118           tech_pvt->rx_udp_seq = *((unsigned int*)(&rxdata[res]));
 5119         }
 5120       }
 5121     }
 5122 
 5123     /* Used for checking incoming udp stream. Should only be used for debugging. */
 5124     if (tech_pvt->profile->rx_sync_check_opt) {
 5125       int i;
 5126       unsigned char *data = (unsigned char*)(tech_pvt->fdata + AST_FRIENDLY_OFFSET);
 5127       for (i = 0; i < res; i++) {
 5128         if (tech_pvt->sync_r == 0) {
 5129           if (data[i] == 0x01) {
 5130             if (globals.debug > 2) {
 5131               ast_log(LOG_NOTICE, "%s: R Sync Acheived Offset=%i\n", self->name,i);
 5132             }
 5133             tech_pvt->sync_r = 1;
 5134             tech_pvt->sync_data_r = data[i];
 5135           }
 5136         } else {
 5137           tech_pvt->sync_data_r++;
 5138           if (tech_pvt->sync_data_r != data[i]) {
 5139             ast_log(LOG_NOTICE, "%s: R Sync Lost: Expected %i  Got %i  Offset=%i\n",
 5140                     self->name, tech_pvt->sync_data_r, data[i], i);
 5141             tech_pvt->sync_r = 0;
 5142           }
 5143         }
 5144       }
 5145     }
 5146 
 5147     tech_pvt->frame.frametype = AST_FRAME_VOICE;
 5148     tech_pvt->frame.subclass = tech_pvt->coding;
 5149     tech_pvt->frame.offset = AST_FRIENDLY_OFFSET;
 5150     tech_pvt->frame.datalen = res;
 5151     tech_pvt->frame.samples = res;
 5152     tech_pvt->frame.woo_ast_data_ptr = tech_pvt->fdata + AST_FRIENDLY_OFFSET;
 5153   }
 5154 
 5155   f = &tech_pvt->frame;
 5156 
 5157   /*
 5158    * adjust rx levels on raw voice frames.
 5159    */
 5160   if ((tech_pvt->frame.frametype == AST_FRAME_VOICE) && tech_pvt->profile->rxgain_val) {
 5161     int i;
 5162     unsigned char *data = tech_pvt->frame.woo_ast_data_ptr;
 5163     for (i = 0; i < tech_pvt->frame.datalen; i++ ) {
 5164       data[i] = tech_pvt->profile->rxgain[data[i]];
 5165     }
 5166   }
 5167 
 5168   if (tech_pvt->owner && (tech_pvt->faxdetect || tech_pvt->ast_dsp)) {
 5169     f = ast_dsp_process(tech_pvt->owner, tech_pvt->dsp, &tech_pvt->frame);
 5170     if (f && f->frametype == AST_FRAME_DTMF) {
 5171       int answer = 0;
 5172 
 5173       if(ast_test_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED)) {
 5174         ast_mutex_lock(&tech_pvt->iolock);
 5175         if(ast_test_flag(tech_pvt, TFLAG_CONFIRM_ANSWER)){
 5176           ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER);
 5177           if(ast_test_flag(tech_pvt, TFLAG_ANSWER_RECEIVED)) {
 5178             answer = 1;
 5179           }
 5180         }
 5181         ast_mutex_unlock(&tech_pvt->iolock);
 5182         if (answer){
 5183           struct ast_frame answer_frame = {AST_FRAME_CONTROL, AST_CONTROL_ANSWER};
 5184           struct ast_channel *owner = tech_get_owner(tech_pvt);
 5185           ast_log(LOG_DEBUG, "Confirm answer on %s!\n", self->name);
 5186 
 5187           if (owner) {
 5188             ast_setstate(owner, AST_STATE_UP);
 5189             ast_queue_frame(owner, &answer_frame);
 5190             ast_set_flag(tech_pvt, TFLAG_UP);
 5191 
 5192             ast_mutex_lock(&tech_pvt->profile->call_count_lock);
 5193             tech_pvt->profile->call_ok++;
 5194             ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
 5195           } else {
 5196             ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds));
 5197             tech_pvt->pri_cause = 44;
 5198             ast_set_flag(tech_pvt, TFLAG_ABORT);
 5199           }
 5200         }
 5201       }
 5202       if (f->subclass == 'f' && tech_pvt->faxdetect) {
 5203         handle_fax(tech_pvt);
 5204       }
 5205       if (answer == 0 && globals.debug > 2) {
 5206         ast_log(LOG_NOTICE, "%s: Detected inband DTMF digit: %c\n",
 5207                 self->name, f->subclass);
 5208       }
 5209     }
 5210     //woomera_tx2ast_frm(tech_pvt, tech_pvt->frame.data, tech_pvt->frame.datalen);
 5211   }
 5212 
 5213   if (globals.debug > 4) {
 5214     if (option_verbose > 2) {
 5215       ast_verbose(WOOMERA_DEBUG_PREFIX "+++READ %s %d coding %d\n", self->name, res,
 5216                   tech_pvt->coding);
 5217     }
 5218   }
 5219 
 5220   return f;
 5221 }
 5222 
 5223 
 5224 /*!
 5225  * Channel interface.
 5226  * \brief  Write an audio frame to a channel.
 5227  * Yep, this is the opposite of tech_read, you need to examine
 5228  * a frame and transfer the data to your technology's audio stream.
 5229  * You do not have any responsibility to destroy this frame and you should
 5230  * consider it to be read-only.
 5231  */
 5232 static int tech_write(struct ast_channel *self, struct ast_frame *frame)
 5233 {
 5234   private_object *tech_pvt = self->tech_pvt;
 5235   int res = 0, i = 0;
 5236 
 5237   if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT)) {
 5238     return -1;
 5239   }
 5240 
 5241   /* Used for debugging only never in production */
 5242   if (tech_pvt->profile->tx_sync_check_opt) {
 5243     unsigned char *data = frame->woo_ast_data_ptr;
 5244     for (i = 0; i < frame->datalen; i++) {
 5245       if (tech_pvt->sync_w == 0) {
 5246         if (data[i] == 0x01 && data[i+1] == 0x02) {
 5247           ast_log(LOG_NOTICE, "%s: W Sync Acheived Offset=%i\n", self->name,i);
 5248           tech_pvt->sync_w = 1;
 5249           tech_pvt->sync_data_w = data[i];
 5250         }
 5251       } else if (tech_pvt->sync_w == 1) {
 5252         tech_pvt->sync_data_w++;
 5253         if (tech_pvt->sync_data_w != data[i]) {
 5254           ast_log(LOG_NOTICE, "%s: W Sync Lost: Expected %i  Got %i  Offset=%i\n",
 5255               self->name,
 5256               tech_pvt->sync_data_w, data[i], i);
 5257           tech_pvt->sync_w = 0;
 5258           if (0) {
 5259             int x;
 5260             ast_log(LOG_NOTICE, "%s: PRINTING FRAME Len=%i\n",
 5261                 self->name,frame->datalen);
 5262             for (x = 0; x < frame->datalen; x++) {
 5263               ast_log(LOG_NOTICE, "%s: Off=%i Data %i\n",
 5264               self->name, x, data[x]);
 5265             }
 5266           }
 5267         }
 5268       }
 5269     }
 5270 
 5271   /* Used for debugging only never in production */
 5272   } else if (tech_pvt->profile->tx_sync_gen_opt) {
 5273     unsigned char *data = frame->woo_ast_data_ptr;
 5274     int x;
 5275     for (x = 0; x < frame->datalen; x++) {
 5276       data[x] = ++tech_pvt->sync_data_w;
 5277     }
 5278   }
 5279 
 5280   if (ast_test_flag(tech_pvt, TFLAG_MEDIA) && frame->datalen) {
 5281     if (frame->frametype == AST_FRAME_VOICE) {
 5282 
 5283       if (tech_pvt->profile->txgain_val) {
 5284         unsigned char *data = frame->woo_ast_data_ptr;
 5285         for (i = 0; i < frame->datalen; i++) {
 5286           data[i] = tech_pvt->profile->txgain[data[i]];
 5287         }
 5288       }
 5289 
 5290       if (tech_pvt->profile->udp_seq){
 5291         unsigned char *txdata = frame->woo_ast_data_ptr;
 5292         tech_pvt->tx_udp_seq++;
 5293         *((unsigned int*)&txdata[frame->datalen]) = tech_pvt->tx_udp_seq;
 5294         frame->datalen += 4;
 5295       }
 5296 
 5297       if (tech_pvt->rtp_enable){
 5298         i = ast_rtp_write(tech_pvt->rtp, frame);
 5299       }
 5300       else {
 5301         i = sendto(tech_pvt->udp_socket, frame->woo_ast_data_ptr, frame->datalen, 0,
 5302                    (struct sockaddr *) &tech_pvt->udpwrite, sizeof(tech_pvt->udpwrite));
 5303       }
 5304 
 5305       if (i < 0) {
 5306         return -1;
 5307       }
 5308       if (globals.debug > 4) {
 5309         if (option_verbose > 4) {
 5310           ast_verbose(WOOMERA_DEBUG_PREFIX "+++AUDIO WRITE %s %d\n", self->name, i);
 5311         }
 5312       }
 5313 
 5314 
 5315     } else {
 5316       ast_log(LOG_NOTICE, "Invalid frame type %d sent\n", frame->frametype);
 5317     }
 5318   }
 5319 
 5320   return res;
 5321 }
 5322 
 5323 
 5324 /*!
 5325  * Channel interface.
 5326  * \brief Write a video frame to my channel.
 5327  */
 5328 static int tech_write_video(struct ast_channel *self, struct ast_frame *frame)
 5329 {
 5330   private_object *tech_pvt;
 5331   int res = 0;
 5332 
 5333   tech_pvt = self->tech_pvt;
 5334   if (tech_pvt->vrtp)
 5335   {
 5336     res = ast_rtp_write(tech_pvt->vrtp, frame);
 5337   }
 5338 
 5339   if (globals.debug > 4) {
 5340     if (option_verbose > 4) {
 5341       ast_verbose(WOOMERA_DEBUG_PREFIX "+++VIDEO WRITE %s %d\n", self->name, res);
 5342     }
 5343   }
 5344   return res;
 5345 }
 5346 
 5347 
 5348 /*!
 5349  * Channel interface.
 5350  * \brief Read an exception audio frame from my channel.
 5351  */
 5352 static struct ast_frame *tech_exception(struct ast_channel *self)
 5353 {
 5354   private_object *tech_pvt;
 5355 
 5356   tech_pvt = self->tech_pvt;
 5357   if (globals.debug > 1 && option_verbose > 2) {
 5358     if (option_verbose > 2) {
 5359       ast_verbose(WOOMERA_DEBUG_PREFIX "+++EXCEPT %s\n", self->name);
 5360     }
 5361   }
 5362 
 5363   return &ast_null_frame;
 5364 }
 5365 
 5366 
 5367 /*!
 5368  * Channel interface.
 5369  * \brief  Indicate a condition to a channe.
 5370  */
 5371 #ifdef  USE_TECH_INDICATE
 5372 #if defined (AST14) || defined (AST16)
 5373 static int tech_indicate(struct ast_channel *self, int condition, const void *data, size_t datalen)
 5374 #else
 5375 static int tech_indicate(struct ast_channel *self, int condition)
 5376 #endif
 5377 {
 5378   private_object *tech_pvt;
 5379   int res = -1;
 5380 
 5381   tech_pvt = self->tech_pvt;
 5382   if (!tech_pvt) {
 5383     return res;
 5384   }
 5385 
 5386   ast_mutex_lock(&tech_pvt->iolock);
 5387 
 5388   switch (condition) {
 5389 
 5390   case AST_CONTROL_RINGING:
 5391     if (globals.debug > 3) {
 5392       ast_log(LOG_NOTICE, "TECH INDICATE: Ringing\n");
 5393     }
 5394     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5395       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5396     }
 5397     break;
 5398 
 5399   case AST_CONTROL_BUSY:/home/test/woomera/clients/asterisk/chan_woomera
 5400     if (globals.debug > 3) {
 5401       ast_log(LOG_NOTICE, "TECH INDICATE: Busy\n");
 5402     }
 5403     ast_copy_string(tech_pvt->ds, "BUSY", sizeof(tech_pvt->ds));
 5404     tech_pvt->pri_cause = 17;
 5405     ast_set_flag(tech_pvt, TFLAG_ABORT);
 5406     break;
 5407 
 5408   case AST_CONTROL_CONGESTION:
 5409     if (globals.debug > 3) {
 5410       ast_log(LOG_NOTICE, "TECH INDICATE: Congestion\n");
 5411     }
 5412     ast_copy_string(tech_pvt->ds, "BUSY", sizeof(tech_pvt->ds));
 5413     tech_pvt->pri_cause = 17;
 5414     ast_set_flag(tech_pvt, TFLAG_ABORT);
 5415     break;
 5416 
 5417   case AST_CONTROL_PROCEEDING:
 5418     if (globals.debug > 3) {
 5419       ast_log(LOG_NOTICE, "TECH INDICATE: Proceeding\n");
 5420     }
 5421     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5422       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5423     }
 5424     break;
 5425 
 5426   case AST_CONTROL_PROGRESS:
 5427     if (globals.debug > 3) {
 5428       ast_log(LOG_NOTICE, "TECH INDICATE: Progress\n");
 5429     }
 5430     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5431       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5432     }
 5433     break;
 5434 
 5435   case AST_CONTROL_HOLD:
 5436     if (globals.debug > 3) {
 5437       ast_log(LOG_NOTICE, "TECH INDICATE: Hold\n");
 5438     }
 5439     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5440       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5441     }
 5442 #if defined (AST14) || defined (AST16)
 5443     ast_moh_start(self, data, tech_pvt->mohinterpret);
 5444 #endif
 5445     break;
 5446 
 5447   case AST_CONTROL_UNHOLD:
 5448     if (globals.debug > 3) {
 5449       ast_log(LOG_NOTICE, "TECH INDICATE: UnHold\n");
 5450     }
 5451     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5452       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5453     }
 5454 #if defined (AST14) || defined (AST16)
 5455     ast_moh_stop(self);
 5456 #endif
 5457     break;
 5458 
 5459   case AST_CONTROL_VIDUPDATE:
 5460     if (globals.debug > 3) {
 5461       ast_log(LOG_NOTICE, "TECH INDICATE: Vidupdate\n");
 5462     }
 5463     if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) {
 5464       ast_set_flag(tech_pvt, TFLAG_ACCEPT);
 5465     }
 5466     break;
 5467 
 5468 #ifdef WOO_CONTROL_SRC_FEATURE
 5469   case AST_CONTROL_SRCUPDATE:
 5470     res = 0;
 5471     break;
 5472 #endif
 5473   case -1:
 5474     res = -1;
 5475     break;
 5476 
 5477   default:
 5478     ast_log(LOG_NOTICE, "Don't know how to indicate condition %d\n", condition);
 5479     res = -1;
 5480     break;
 5481   }
 5482 
 5483   ast_mutex_unlock(&tech_pvt->iolock);
 5484 
 5485   return res;
 5486 }
 5487 #endif
 5488 
 5489 /*!
 5490  * Channel interface.
 5491  * \brief  Add any finishing touches to a channel if it is masqueraded.
 5492  */
 5493 static int tech_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 5494 {
 5495   struct private_object *p;
 5496 
 5497   if (!oldchan || !newchan) {
 5498     ast_log(LOG_ERROR, "Error: Invalid Pointers oldchan=%p newchan=%p\n", oldchan, newchan);
 5499     return -1;
 5500   }
 5501   if (!newchan->tech_pvt) {
 5502     ast_log(LOG_ERROR, "Error: Invalid Pointer newchan->tech_pvt=%p\n",
 5503             newchan->tech_pvt);
 5504     return -1;
 5505   }
 5506 
 5507   p = newchan->tech_pvt;
 5508 
 5509   ast_mutex_lock(&p->iolock);
 5510   if (p->owner == oldchan) {
 5511     p->owner = newchan;
 5512   } else {
 5513     ast_log(LOG_ERROR, "Error: New p owner=%p instead of %p \n",
 5514             p->owner, oldchan);
 5515   }
 5516 
 5517 #if 0
 5518   if (newchan->_state == AST_STATE_RINGING)
 5519     dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
 5520 
 5521   update_conf(p);
 5522 #endif
 5523 
 5524   if (globals.debug > 1 && option_verbose > 2) {
 5525     if (option_verbose > 2) {
 5526       ast_verbose(WOOMERA_DEBUG_PREFIX "+++FIXUP ChOld=%s ChNew=%s\n",
 5527                                                 oldchan->name, newchan->name);
 5528     }
 5529   }
 5530 
 5531   ast_mutex_unlock(&p->iolock);
 5532   return 0;
 5533 }
 5534 
 5535 
 5536 /*!
 5537  * Channel interface.
 5538  * \brief Send html data on a channel.
 5539  */
 5540 static int tech_send_html(struct ast_channel *self, int subclass, const char *data, int datalen)
 5541 {
 5542   private_object *tech_pvt;
 5543   int res = 0;
 5544 
 5545   tech_pvt = self->tech_pvt;
 5546   return res;
 5547 }
 5548 
 5549 
 5550 /*!
 5551  * Channel interface.
 5552  * \brief Send plain text data on a channel.
 5553  */
 5554 static int tech_send_text(struct ast_channel *self, const char *text)
 5555 {
 5556   int res = 0;
 5557   return res;
 5558 }
 5559 
 5560 
 5561 /*!
 5562  * Channel interface.
 5563  * \brief Send image data on a channel.
 5564  */
 5565 static int tech_send_image(struct ast_channel *self, struct ast_frame *frame)
 5566 {
 5567   int res = 0;
 5568   return res;
 5569 }
 5570 
 5571 
 5572 /*!
 5573  * Channel interface.
 5574  * \brief Set options on a channel.
 5575  */
 5576 static int tech_setoption(struct ast_channel *self, int option, void *data, int datalen)
 5577 {
 5578   int res = 0;
 5579 
 5580   if (globals.debug > 1 && option_verbose > 2) {
 5581     if (option_verbose > 2) {
 5582       ast_verbose(WOOMERA_DEBUG_PREFIX "+++SETOPT %s\n",self->name);
 5583     }
 5584   }
 5585   return res;
 5586 
 5587 }
 5588 
 5589 
 5590 /*!
 5591  * Channel interface.
 5592  * \brief  Get options from a channel.
 5593  */
 5594 static int tech_queryoption(struct ast_channel *self, int option, void *data, int *datalen)
 5595 {
 5596   int res = 0;
 5597 
 5598   if (globals.debug > 1 && option_verbose > 2) {
 5599     if (option_verbose > 2) {
 5600       ast_verbose(WOOMERA_DEBUG_PREFIX "+++GETOPT %s\n", self->name);
 5601     }
 5602   }
 5603   return res;
 5604 }
 5605 
 5606 
 5607 /*!
 5608  * Channel interface.
 5609  * \brief Get a pointer to a channel that may be bridged to our channel.
 5610  */
 5611 #if 0
 5612 static struct ast_channel *tech_bridged_channel(struct ast_channel *self, struct ast_channel *bridge)
 5613 {
 5614   struct ast_channel *chan = NULL;
 5615 
 5616   if (globals.debug > 1 && option_verbose > 2) {
 5617     ast_verbose(WOOMERA_DEBUG_PREFIX "+++BRIDGED %s\n", self->name);
 5618   }
 5619   return chan;
 5620 }
 5621 #endif
 5622 
 5623 
 5624 /*!
 5625  * Channel interface.
 5626  * \brief Technology-specific code executed to perform a transfer.
 5627  */
 5628 static int tech_transfer(struct ast_channel *self, const char *newdest)
 5629 {
 5630   int res = -1;
 5631 
 5632   if (globals.debug > 1 && option_verbose > 2) {
 5633     if (option_verbose > 2) {
 5634       ast_verbose(WOOMERA_DEBUG_PREFIX "+++TRANSFER %s\n", self->name);
 5635     }
 5636   }
 5637   return res;
 5638 }
 5639 
 5640 
 5641 /*!
 5642  * \brief  Technology-specific code executed to natively bridge 2 of our channels
 5643  */
 5644 #if 0
 5645 static enum ast_bridge_result tech_bridge(struct ast_channel *c0,
 5646                                           struct ast_channel *c1,
 5647                                           int flags,
 5648                                           struct ast_frame **fo,
 5649                                           struct ast_channel **rc,
 5650                                           int timeoutms)
 5651 {
 5652   int res = -1;
 5653 
 5654   if (globals.debug > 1) {
 5655     ast_verbose(WOOMERA_DEBUG_PREFIX "+++BRIDGE %s\n", c0->name);
 5656   }
 5657   return res;
 5658 }
 5659 #endif
 5660 
 5661 
 5662 #if defined(AST16)
 5663 static char *ast16_woomera_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 5664 {
 5665   switch (cmd) {
 5666     case CLI_INIT:
 5667       e->command = "woomera";
 5668       e->usage = "Usage: woomera <profile> <cmd> <option>\n";
 5669       return NULL;
 5670     case CLI_GENERATE:
 5671       return NULL;
 5672   }
 5673 
 5674   woomera_cli(a->fd, a->argc, a->argv);
 5675   return CLI_SUCCESS;
 5676 }
 5677 #endif
 5678 
 5679 
 5680 /*!
 5681  * \brief Command line handler.
 5682  */
 5683 static int woomera_cli(int fd, int argc, char *argv[])
 5684 {
 5685   struct woomera_profile *profile;
 5686   char *profile_name = "default";
 5687 
 5688   if (argc > 2) {
 5689 
 5690     profile_name = argv[1];
 5691     profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, profile_name);
 5692     if (!profile) {
 5693 
 5694       if (strcmp(profile_name,"version") == 0) {
 5695         ast_cli(fd, "Woomera version %s : Server version %s  \n",
 5696           WOOMERA_VERSION, svrversion);
 5697         return 0;
 5698       }
 5699 
 5700       ast_cli(fd, "Woomera: Invalid profile name %s\n", profile_name);
 5701       return 0;
 5702     }
 5703 
 5704     if (!strcmp(argv[2], "debug")) {
 5705       if (argc > 3) {
 5706         globals.debug = atoi(argv[3]);
 5707       }
 5708       ast_cli(fd, "Woomera debug=%d\n", globals.debug);
 5709 
 5710 
 5711     } else if (!strcmp(argv[2], "coding")) {
 5712 
 5713       switch (profile->coding) {
 5714       case AST_FORMAT_ALAW:
 5715         ast_cli(fd, " Woomera {%s} coding=ALAW (PCMA)\n", profile_name);
 5716         break;
 5717       case AST_FORMAT_ULAW:
 5718         ast_cli(fd, " Woomera {%s} coding=ULAW (PCMU)\n", profile_name);
 5719         break;
 5720       case AST_FORMAT_SLINEAR:
 5721         ast_cli(fd, " Woomera {%s} coding=PCM-16\n", profile_name);
 5722         break;
 5723       default:
 5724         ast_cli(fd, " Woomera {%s} invalid coding=%d {internal error}",
 5725           profile_name, profile->coding);
 5726         break;
 5727 
 5728       }
 5729 
 5730     } else if (!strcmp(argv[2], "videocoding")) {
 5731 
 5732       switch (profile->videocoding) {
 5733       case AST_FORMAT_H261:
 5734         ast_cli(fd, " Woomera {%s} videocoding=H261\n", profile_name);
 5735         break;
 5736       case AST_FORMAT_H263:
 5737         ast_cli(fd, " Woomera {%s} videocoding=H263\n", profile_name);
 5738         break;
 5739       case AST_FORMAT_H263_PLUS:
 5740         ast_cli(fd, " Woomera {%s} videocoding=H263-1998\n", profile_name);
 5741         break;
 5742       case AST_FORMAT_H264:
 5743         ast_cli(fd, " Woomera {%s} videocoding=H264\n", profile_name);
 5744         break;
 5745       case AST_FORMAT_MP4_VIDEO:
 5746         ast_cli(fd, " Woomera {%s} videocoding=MPV4-ES\n", profile_name);
 5747         break;
 5748       default:
 5749         ast_cli(fd, " Woomera {%s} invalid coding=%d {internal error}",
 5750           profile_name, profile->coding);
 5751         break;
 5752       }
 5753     } else if (!strcmp(argv[2], "call_status")) {
 5754 
 5755       ast_cli(fd, "Woomera {%s} calls=%d tcalls=%d (out=%d in=%d ok=%d end=%d abort=%d hup_pend=%d use=%d)\n",
 5756           profile->name,
 5757           profile->call_count,
 5758           profile->call_out+profile->call_in,
 5759           profile->call_out,
 5760           profile->call_in,
 5761           profile->call_ok,
 5762           profile->call_end,
 5763           profile->call_abort,
 5764           profile->call_ast_hungup,
 5765           usecnt);
 5766 
 5767     } else if (!strcmp(argv[2], "version")) {
 5768 
 5769       ast_cli(fd, "Woomera version %s : Server version %s  \n",
 5770         WOOMERA_VERSION, svrversion);
 5771 
 5772     } else if (!strcmp(argv[2], "panic")) {
 5773       if (argc > 3) {
 5774         globals.panic = atoi(argv[3]);
 5775       }
 5776       ast_cli(fd, "Woomera panic=%d           \n", globals.panic);
 5777 
 5778     } else if (!strcmp(argv[2], "rxgain")) {
 5779       float gain;
 5780       if (argc > 3) {
 5781         if (sscanf(argv[3], "%f", &gain) != 1) {
 5782           ast_cli(fd, "Woomera Invalid rxgain: %s\n", argv[3]);
 5783         } else {
 5784           woomera_config_gain(profile,gain,1);
 5785         }
 5786       }
 5787       ast_cli(fd, "Woomera {%s} rxgain: %f\n", profile_name, profile->rxgain_val);
 5788 
 5789     } else if (!strcmp(argv[2], "txgain")) {
 5790       float gain;
 5791       if (argc > 3) {
 5792         if (sscanf(argv[3], "%f", &gain) != 1) {
 5793           ast_cli(fd, "Woomera Invalid txgain: %s\n", argv[3]);
 5794         } else {
 5795           woomera_config_gain(profile,gain,0);
 5796         }
 5797       }
 5798       ast_cli(fd, "Woomera {%s} txgain: %f\n", profile_name, profile->txgain_val);
 5799 
 5800     } else if (!strcmp(argv[2], "threads")) {
 5801       ast_cli(fd, "chan_woomera is using %s threads!\n",
 5802           globals.more_threads ? "more" : "less");
 5803 
 5804     } else if (!strcmp(argv[2], "debug")) {
 5805 
 5806       if (argc > 3) {
 5807         int debuglevel = atoi(argv[3]);
 5808         if (debuglevel < 0 || debuglevel > 5) {
 5809           ast_cli(fd, "Invalid Woomera debug level: %i\n", debuglevel);
 5810         } else {
 5811           ast_cli(fd,"Setting Woomera debug level to %i\n", debuglevel);
 5812           globals.debug = debuglevel;
 5813         }
 5814       } else {
 5815         ast_cli(fd, "Invalid Woomera debug usage\n");
 5816       }
 5817     } else if (!strcmp(argv[2], "abort")) {
 5818       global_set_flag(TFLAG_ABORT);
 5819     }
 5820 
 5821   } else {
 5822     ast_cli(fd, "Usage: woomera <profile> <cmd> <option>\n");
 5823   }
 5824   return 0;
 5825 }
 5826 
 5827 
 5828 
 5829 
 5830 #ifdef CALLWEAVER
 5831 #ifdef CALLWEAVER_OPBX_CLI_ENTRY
 5832 static struct opbx_cli_entry cli_woomera[] = {
 5833 # else
 5834 #ifdef CALLWEAVER_CW_CLI_ENTRY
 5835 static struct cw_cli_entry cli_woomera[] = {
 5836 #else
 5837 static struct cw_clicmd cli_woomera[] = {
 5838 #endif
 5839 #endif
 5840   {
 5841     .cmda = { "woomera", "default", "version", NULL },
 5842     .handler = woomera_cli,
 5843     .summary = "Woomera Version",
 5844     //.usage = pri_debug_help,
 5845     //.generator = complete_span_4,
 5846   },
 5847 };
 5848 
 5849 #else
 5850 /*!
 5851  *  Woomera Cli commands definition
 5852  */
 5853 #if defined (AST16)
 5854 static struct ast_cli_entry cli_woomera[] = {
 5855   AST_CLI_DEFINE(ast16_woomera_cli, "Prints Woomera options"),
 5856 };
 5857 #else
 5858 static struct ast_cli_entry  cli_woomera = { { "woomera", NULL }, woomera_cli, "Woomera", "Woomera" };
 5859 #endif
 5860 #endif
 5861 
 5862 /******************************* CORE INTERFACE ********************************************
 5863  * These are module-specific interface functions that are common to every module
 5864  * To be used to initilize/de-initilize, reload and track the use count of a loadable module.
 5865  */
 5866 
 5867 static void urg_handler(int num)
 5868 {
 5869   signal(num, urg_handler);
 5870   return;
 5871 }
 5872 
 5873 
 5874 int usecount(void)
 5875 {
 5876   int res;
 5877   ast_mutex_lock(&usecnt_lock);
 5878   res = usecnt;
 5879   ast_mutex_unlock(&usecnt_lock);
 5880   return res;
 5881 }
 5882 
 5883 
 5884 #if 0
 5885 static char *key(void)
 5886 {
 5887   return ASTERISK_GPL_KEY;
 5888 }
 5889 
 5890 
 5891 /* returns a descriptive string to the system console */
 5892 char *description(void)
 5893 {
 5894   return (char *) desc;
 5895 }
 5896 #endif
 5897 
 5898 /*!
 5899  * \brief get the channel.
 5900  */
 5901 static struct ast_channel * tech_get_owner( private_object *tech_pvt)
 5902 {
 5903   struct ast_channel *owner = NULL;
 5904 
 5905   ast_mutex_lock(&tech_pvt->iolock);
 5906   if (!ast_test_flag(tech_pvt, TFLAG_TECHHANGUP) && tech_pvt->owner) {
 5907     owner = tech_pvt->owner;
 5908   }
 5909   ast_mutex_unlock(&tech_pvt->iolock);
 5910 
 5911   return owner;
 5912 }
 5913 
 5914 
 5915 /*!
 5916  * \brief Handle EVENT MEDIA message.
 5917  */
 5918 static int woomera_event_media(private_object *tech_pvt, woomera_message *wmsg)
 5919 {
 5920   char *raw_audio_header;
 5921   char *rtp_video_header;
 5922   char *rtp_audio_header;
 5923 
 5924   char *hw_dtmf;
 5925   char ip[25];
 5926   char vip[25];
 5927 
 5928   char *ptr;
 5929   int port = 0;
 5930   int vport = 0;
 5931 
 5932   struct hostent hps, *hp;
 5933   struct hostent *result;
 5934   struct ast_channel *owner;
 5935   char buf[512];
 5936   int err = 0;
 5937 
 5938   memset(&hps, 0, sizeof(hps));
 5939   hp = &hps;
 5940 
 5941   if (tech_pvt->rtp_enable) {
 5942     rtp_audio_header = woomera_message_header(wmsg, "RTP-Audio");
 5943     if (rtp_audio_header == NULL) {
 5944       ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 5945       tech_pvt->pri_cause = 111;
 5946       return 1;
 5947     }
 5948 
 5949     strncpy(ip, rtp_audio_header, sizeof(ip) - 1);
 5950     if ((ptr = strchr(ip, '/'))) {
 5951       *ptr = '\0';
 5952       ptr++;
 5953       port = atoi(ptr);
 5954     }
 5955     else if ((ptr = strchr(ip, ':'))) {
 5956       *ptr = '\0';
 5957       ptr++;
 5958       port = atoi(ptr);
 5959     }
 5960 
 5961     rtp_video_header = woomera_message_header(wmsg, "RTP-Video");
 5962     if (rtp_video_header) {
 5963       strncpy(vip, rtp_video_header, sizeof(vip) - 1);
 5964       if ((ptr = strchr(vip, '/'))) {
 5965         *ptr = '\0';
 5966         ptr++;
 5967         vport = atoi(ptr);
 5968       }
 5969       else if ((ptr = strchr(vip, ':'))) {
 5970         *ptr = '\0';
 5971         ptr++;
 5972         vport = atoi(ptr);
 5973       }
 5974     }
 5975   }
 5976   else
 5977   {
 5978     raw_audio_header = woomera_message_header(wmsg, "Raw-Audio");
 5979     if (raw_audio_header == NULL) {
 5980       ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
 5981       tech_pvt->pri_cause = 111;
 5982       return 1;
 5983     }
 5984 
 5985     strncpy(ip, raw_audio_header, sizeof(ip) - 1);
 5986     if ((ptr = strchr(ip, '/'))) {
 5987       *ptr = '\0';
 5988       ptr++;
 5989       port = atoi(ptr);
 5990     } else if ((ptr = strchr(ip, ':'))) {
 5991       *ptr = '\0';
 5992       ptr++;
 5993       port = atoi(ptr);
 5994     }
 5995 
 5996 #if 0
 5997     audio_codec = woomera_message_header(wmsg, "Receive-Audio-Codec");
 5998     if (audio_codec) {
 5999       if (!strcasecmp(audio_codec,"G.711-uLaw-64k")) {
 6000         tech_pvt->coding = AST_FORMAT_ULAW;
 6001         ast_log(LOG_NOTICE, "MEDIA GOT ULAW\n");
 6002       } else if (!strcasecmp(audio_codec,"G.711-aLaw-64k")) {
 6003         tech_pvt->coding = AST_FORMAT_ALAW;
 6004         ast_log(LOG_NOTICE, "MEDIA GOT ALAW\n");
 6005       }
 6006     }
 6007 #endif
 6008   }
 6009 
 6010   hw_dtmf = woomera_message_header(wmsg, "DTMF");
 6011   if (hw_dtmf != NULL) {
 6012     if (strncmp(hw_dtmf, "OutofBand", 9) == 0) {
 6013       if (option_verbose > 2) {
 6014         ast_verbose(WOOMERA_DEBUG_PREFIX "HW DTMF supported %s\n", tech_pvt->callid);
 6015       }
 6016       if (tech_pvt->dsp) {
 6017         tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
 6018         ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
 6019       }
 6020     } else {
 6021       if (option_verbose > 2) {
 6022         ast_verbose(WOOMERA_DEBUG_PREFIX "HW DTMF not supported %s\n", tech_pvt->callid);
 6023       }
 6024     }
 6025   }
 6026 
 6027   /* If we are already in MEDIA mode then
 6028    * ignore this message */
 6029   if (ast_test_flag(tech_pvt, TFLAG_MEDIA)) {
 6030     return 0;
 6031   }
 6032 
 6033   gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
 6034   if (result) {
 6035 
 6036     tech_pvt->udpwrite.sin_family = hp->h_addrtype;
 6037     memcpy((char *) &tech_pvt->udpwrite.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
 6038     tech_pvt->udpwrite.sin_port = htons(port);
 6039 
 6040     if (globals.debug > 4) {
 6041       ast_log(LOG_NOTICE,"MEDIA EVENT UdpWrite IP=%s:%d\n",
 6042               ast_inet_ntoa(tech_pvt->udpwrite.sin_addr), port);
 6043     }
 6044 
 6045     if ( vport ) {
 6046       struct sockaddr_in video;
 6047       gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
 6048       if (result)
 6049       {
 6050         video.sin_family = hp->h_addrtype;
 6051         memcpy((char *) &video.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
 6052         video.sin_port = htons(vport);
 6053         if (tech_pvt->vrtp)
 6054           ast_rtp_set_peer(tech_pvt->vrtp, &video);
 6055       }
 6056     }
 6057 
 6058     ast_set_flag(tech_pvt, TFLAG_MEDIA);
 6059     tech_pvt->timeout = 0;
 6060 
 6061     if (tech_pvt->rtp_enable) {
 6062       ast_rtp_set_peer(tech_pvt->rtp, &tech_pvt->udpwrite);
 6063     }
 6064 
 6065     my_tech_pvt_and_owner_lock(tech_pvt);
 6066 
 6067     owner = tech_pvt->owner;
 6068     if (!owner) {
 6069       tech_pvt->pri_cause = 44;
 6070       ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds));
 6071       my_tech_pvt_and_owner_unlock(tech_pvt);
 6072       return -1;
 6073     }
 6074 
 6075     if (ast_test_flag(tech_pvt, TFLAG_INBOUND)) {
 6076       int pbx_res;
 6077 
 6078 #if defined (AST14) || defined (AST16)
 6079       ast_setstate(owner, AST_STATE_RINGING);
 6080 #endif
 6081       pbx_res = ast_pbx_start(owner);
 6082 
 6083       if (pbx_res) {
 6084 
 6085         my_tech_pvt_and_owner_unlock(tech_pvt);
 6086 
 6087         ast_log(LOG_NOTICE, "Failed to start PBX on %s \n", tech_pvt->callid);
 6088         ast_set_flag(tech_pvt, TFLAG_ABORT);
 6089         ast_clear_flag(tech_pvt, TFLAG_PBX);
 6090         owner->tech_pvt = NULL;
 6091         tech_pvt->owner = NULL;
 6092         ast_copy_string(tech_pvt->ds, "SWITCH_CONGESTION", sizeof(tech_pvt->ds));
 6093         tech_pvt->pri_cause = 42;
 6094         ast_hangup(owner);
 6095         /* Let destroy hangup */
 6096         return -1;
 6097       } else {
 6098 #if !defined (AST14) && !defined (AST16)
 6099         ast_setstate(owner, AST_STATE_RINGING);
 6100 #endif
 6101         ast_set_flag(tech_pvt, TFLAG_PBX);
 6102         owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
 6103 
 6104         woomera_send_progress(tech_pvt);
 6105       }
 6106     } else { /* OUTBOUND */
 6107 #if 1
 6108       ast_queue_control(owner, AST_CONTROL_RINGING);
 6109       if (owner->_state != AST_STATE_UP) {
 6110         ast_setstate(owner, AST_STATE_RINGING);
 6111       }
 6112 #endif
 6113       /* Do nothing for the outbound call, the PBX flag was already set.
 6114        */
 6115     }
 6116 
 6117     my_tech_pvt_and_owner_unlock(tech_pvt);
 6118     return 0;
 6119 
 6120   } else {
 6121     if (globals.debug) {
 6122       ast_log(LOG_ERROR, "{%s} Cannot resolve %s\n", tech_pvt->profile->name, ip);
 6123     }
 6124     ast_copy_string(tech_pvt->ds, "NO_ROUTE_DESTINATION", sizeof(tech_pvt->ds));
 6125     tech_pvt->pri_cause = 3;
 6126     return -1;
 6127   }
 6128 
 6129   return -1;
 6130 }
 6131 
 6132 
 6133 /*!
 6134  * \brief Handle an EVENT INCOMING message.
 6135  */
 6136 static int woomera_event_incoming(private_object *tech_pvt)
 6137 {
 6138   char *exten;
 6139   char *cid_name=NULL;
 6140   char *cid_num;
 6141   char *cid_rdnis;
 6142   char *tg_string = "1";
 6143   char *pres_string;
 6144   char *screen_string;
 6145   char *bearer_cap_string;
 6146   char *uil1p_string; /* User Layer 1 Info */
 6147   int validext;
 6148   int presentation = 0;
 6149   woomera_message wmsg;
 6150   struct ast_channel *owner;
 6151 
 6152   wmsg = tech_pvt->call_info;
 6153 
 6154   if (globals.debug > 2) {
 6155     ast_log(LOG_NOTICE, "WOOMERA EVENT %s : callid=%s tech_callid=%s tpvt=%p\n",
 6156             wmsg.command, wmsg.callid, tech_pvt->callid, tech_pvt);
 6157   }
 6158 
 6159   if (ast_strlen_zero(tech_pvt->profile->context)) {
 6160     if (globals.debug > 2) {
 6161       ast_log(LOG_NOTICE, "No Context Found %s tpvt=%p\n", tech_pvt->callid, tech_pvt);
 6162     }
 6163     ast_log(LOG_NOTICE, "No context configured for inbound calls aborting call!\n");
 6164     ast_set_flag(tech_pvt, TFLAG_ABORT);
 6165     return -1;
 6166   }
 6167 
 6168   exten = woomera_message_header(&wmsg, "Local-Number");
 6169   if (!exten || ast_strlen_zero(exten)) {
 6170     exten = "s";
 6171   }
 6172 
 6173   tg_string = woomera_message_header(&wmsg, "Trunk-Group");
 6174   if (!tg_string || ast_strlen_zero(tg_string)) {
 6175     tg_string = "1";
 6176   }
 6177 
 6178   pres_string = woomera_message_header(&wmsg, "Presentation");
 6179   if (pres_string && !ast_strlen_zero(pres_string)) {
 6180     presentation |= ( atoi(pres_string) << 5) & 0xF0;
 6181   }
 6182 
 6183   screen_string = woomera_message_header(&wmsg, "Screening");
 6184   if (screen_string && !ast_strlen_zero(screen_string)) {
 6185     presentation |= atoi(screen_string) & 0x0F;
 6186   }
 6187 
 6188   cid_name = woomera_message_header(&wmsg, "Remote-Name");
 6189   if (cid_name) {
 6190     cid_name = ast_strdupa(woomera_message_header(&wmsg, "Remote-Name"));
 6191   }
 6192 
 6193   if (cid_name && (cid_num = strchr(cid_name, '!'))) {
 6194     *cid_num = '\0';
 6195     cid_num++;
 6196   } else {
 6197     cid_num = woomera_message_header(&wmsg, "Remote-Number");
 6198   }
 6199 
 6200   bearer_cap_string = woomera_message_header(&wmsg, "Bearer-Cap");
 6201   tech_pvt->capability = woomera_capability_to_ast(bearer_cap_string);
 6202 
 6203   uil1p_string = woomera_message_header(&wmsg, "uil1p");
 6204   tech_pvt->coding = woomera_coding_to_ast(uil1p_string);
 6205   if (tech_pvt->coding < 0) {
 6206     tech_pvt->coding = tech_pvt->profile->coding;
 6207   }
 6208 
 6209   cid_rdnis = woomera_message_header(&wmsg, "RDNIS");
 6210 
 6211   owner = tech_pvt->owner;
 6212   if (owner) {
 6213     int group = atoi(tg_string);
 6214     if (group >= 0 &&
 6215         group <= WOOMERA_MAX_TRUNKGROUPS &&
 6216         tech_pvt->profile->tg_context[group] != NULL) {
 6217 
 6218       strncpy(owner->context, tech_pvt->profile->tg_context[group], sizeof(owner->context) - 1);
 6219 
 6220       if (tech_pvt->profile->tg_language[group] != NULL &&
 6221           strlen(tech_pvt->profile->tg_language[group])) {
 6222           ast_string_field_set(owner, language, (char*)tech_pvt->profile->tg_language[group]);
 6223       }
 6224     } else {
 6225       snprintf(owner->context, sizeof(owner->context) - 1,
 6226                "%s%s",
 6227                tech_pvt->profile->default_context,
 6228                tg_string);
 6229     }
 6230 
 6231     owner->transfercapability = tech_pvt->capability;
 6232     pbx_builtin_setvar_helper(owner, "TRANSFERCAPABILITY", ast_transfercapability2str(tech_pvt->capability));
 6233     pbx_builtin_setvar_helper(owner, "CALLTYPE", ast_transfercapability2str(tech_pvt->capability));
 6234 
 6235     owner->nativeformats = tech_pvt->coding | tech_pvt->videocoding;
 6236     owner->writeformat = owner->rawwriteformat = owner->readformat = tech_pvt->coding;
 6237     tech_pvt->frame.subclass = tech_pvt->coding;
 6238 
 6239     strncpy(owner->exten, exten, sizeof(owner->exten) - 1);
 6240     ast_set_callerid(owner, cid_num, cid_name, cid_num);
 6241     owner->cid.cid_pres = presentation;
 6242     owner->cid.cid_dnid = ast_strdup(woomera_message_header(&wmsg, "Local-Number"));
 6243 
 6244     if (cid_rdnis) {
 6245       owner->cid.cid_rdnis = ast_strdup(cid_rdnis);
 6246       pbx_builtin_setvar_helper(owner, "RDNIS", cid_rdnis);
 6247     }
 6248 
 6249     validext = ast_exists_extension(owner,
 6250