<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][15047] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=15047">15047</a></dd>
<dt>Author</dt> <dd>gmaruzz</dd>
<dt>Date</dt> <dd>2009-10-02 08:19:23 -0500 (Fri, 02 Oct 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>gsmopen: renaming filenames to gsmopen</pre>

<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopengsmopenconfxml">freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.conf.xml</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopengsmopenh">freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopengsmopen_protocolc">freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenmod_gsmopenc">freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.c</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopencelliaxconfxml">freeswitch/branches/gmaruzz/mod_gsmopen/celliax.conf.xml</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopencelliaxh">freeswitch/branches/gmaruzz/mod_gsmopen/celliax.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopencelliax_protocolc">freeswitch/branches/gmaruzz/mod_gsmopen/celliax_protocol.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenmod_celliaxc">freeswitch/branches/gmaruzz/mod_gsmopen/mod_celliax.c</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchbranchesgmaruzzmod_gsmopencelliaxconfxml"></a>
<div class="delfile"><h4>Deleted: freeswitch/branches/gmaruzz/mod_gsmopen/celliax.conf.xml</h4></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopencelliaxh"></a>
<div class="delfile"><h4>Deleted: freeswitch/branches/gmaruzz/mod_gsmopen/celliax.h</h4></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopencelliax_protocolc"></a>
<div class="delfile"><h4>Deleted: freeswitch/branches/gmaruzz/mod_gsmopen/celliax_protocol.c</h4></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopengsmopenconfxmlfromrev15046freeswitchbranchesgmaruzzmod_gsmopencelliaxconfxml"></a>
<div class="copfile"><h4>Copied: freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.conf.xml (from rev 15046, freeswitch/branches/gmaruzz/mod_gsmopen/celliax.conf.xml) (0 => 15047)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.conf.xml                                (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.conf.xml        2009-10-02 13:19:23 UTC (rev 15047)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+&lt;configuration name=&quot;gsmopen.conf&quot; description=&quot;GSMopen Configuration&quot;&gt;
+  &lt;global_settings&gt;
+    &lt;param name=&quot;debug&quot; value=&quot;8&quot;/&gt;
+    &lt;param name=&quot;dialplan&quot; value=&quot;XML&quot;/&gt;
+    &lt;param name=&quot;context&quot; value=&quot;default&quot;/&gt;
+    &lt;param name=&quot;hold-music&quot; value=&quot;$${moh_uri}&quot;/&gt;
+    &lt;param name=&quot;destination&quot; value=&quot;9999&quot;/&gt;
+  &lt;/global_settings&gt;
+  &lt;!-- one entry here per gsmopen interface --&gt;
+  &lt;per_interface_settings&gt;
+    &lt;interface id=&quot;1&quot; name=&quot;interface1&quot;&gt;
+        &lt;param name=&quot;hold-music&quot; value=&quot;$${moh_uri}&quot;/&gt;
+        &lt;param name=&quot;dialplan&quot; value=&quot;XML&quot;/&gt;
+        &lt;param name=&quot;context&quot; value=&quot;default&quot;/&gt;
+            &lt;param name=&quot;destination&quot; value=&quot;5000&quot;/&gt;
+    &lt;/interface&gt;
+    &lt;!-- following interfaces are commented out!
+    --&gt;
+  &lt;/per_interface_settings&gt;
+&lt;/configuration&gt;
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopengsmopenhfromrev15046freeswitchbranchesgmaruzzmod_gsmopencelliaxh"></a>
<div class="copfile"><h4>Copied: freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h (from rev 15046, freeswitch/branches/gmaruzz/mod_gsmopen/celliax.h) (0 => 15047)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h                                (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h        2009-10-02 13:19:23 UTC (rev 15047)
</span><span class="lines">@@ -0,0 +1,565 @@
</span><ins>+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II &lt;anthmct@yahoo.com&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_gsmopen) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_gsmopen.c -- GSM compatible Endpoint Module
+ *
+ */
+
+#define MY_EVENT_INCOMING_SMS &quot;gsmopen::incoming_sms&quot;
+
+#undef GIOVA48
+
+#ifndef GIOVA48
+#define SAMPLES_PER_FRAME 160
+#else // GIOVA48
+#define SAMPLES_PER_FRAME 960
+#endif // GIOVA48
+
+
+#ifndef GIOVA48
+#define     GSMOPEN_FRAME_SIZE   160
+#else //GIOVA48
+#define     GSMOPEN_FRAME_SIZE   960
+#endif //GIOVA48
+#define     SAMPLERATE_GSMOPEN   8000
+
+#define GSMOPEN_ALSA
+#include &lt;switch.h&gt;
+#include &lt;switch_version.h&gt;
+#include &lt;termios.h&gt;
+#include &lt;sys/ioctl.h&gt;
+#include &lt;iconv.h&gt;
+#include &lt;libteletone.h&gt;
+
+#ifdef GSMOPEN_ALSA
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#define ALSA_PCM_NEW_SW_PARAMS_API
+#include &lt;alsa/asoundlib.h&gt;
+#endif /* GSMOPEN_ALSA */
+
+
+#ifndef WIN32
+#include &lt;sys/time.h&gt;
+#include &lt;X11/Xlib.h&gt;
+#include &lt;X11/Xlibint.h&gt;
+#include &lt;X11/Xatom.h&gt;
+#endif //WIN32
+
+#ifdef _MSC_VER
+//Windows macro  for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+#define         PROTOCOL_ALSA_VOICEMODEM   4
+#define         PROTOCOL_AT   2
+#define         PROTOCOL_FBUS2   1
+#define         PROTOCOL_NO_SERIAL   3
+
+#define                AT_BUFSIZ 8192
+//FIXME FIXME FIXME #define AT_MESG_MAX_LENGTH 2048 /* much more than 10 SMSs */
+#define AT_MESG_MAX_LENGTH 2048        /* much more than 10 SMSs */
+//FIXME FIXME FIXME #define AT_MESG_MAX_LINES 256   /* 256 lines, so it can contains the results of AT+CLAC, that gives all the AT commands the phone supports */
+#define AT_MESG_MAX_LINES 20        /* 256 lines, so it can contains the results of AT+CLAC, that gives all the AT commands the phone supports */
+
+//#define SAMPLERATE_GSMOPEN 16000
+//#define SAMPLES_PER_FRAME SAMPLERATE_GSMOPEN/50
+
+#ifndef GSMOPEN_SVN_VERSION
+#define GSMOPEN_SVN_VERSION SWITCH_VERSION_REVISION
+#endif /* GSMOPEN_SVN_VERSION */
+
+typedef enum {
+        TFLAG_IO = (1 &lt;&lt; 0),
+        TFLAG_INBOUND = (1 &lt;&lt; 1),
+        TFLAG_OUTBOUND = (1 &lt;&lt; 2),
+        TFLAG_DTMF = (1 &lt;&lt; 3),
+        TFLAG_VOICE = (1 &lt;&lt; 4),
+        TFLAG_HANGUP = (1 &lt;&lt; 5),
+        TFLAG_LINEAR = (1 &lt;&lt; 6),
+        TFLAG_CODEC = (1 &lt;&lt; 7),
+        TFLAG_BREAK = (1 &lt;&lt; 8)
+} TFLAGS;
+
+typedef enum {
+        GFLAG_MY_CODEC_PREFS = (1 &lt;&lt; 0)
+} GFLAGS;
+
+#define DEBUGA_GSMOPEN(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][DEBUG_GSMOPEN  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+#define DEBUGA_CALL(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][DEBUG_CALL  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+#define DEBUGA_PBX(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][DEBUG_PBX  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+#define ERRORA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][ERRORA  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+#define WARNINGA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][WARNINGA  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+#define NOTICA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,                 &quot;rev &quot;GSMOPEN_SVN_VERSION &quot;[%p|%-7lx][NOTICA  %-5d][%-10s][%2d,%2d,%2d] &quot; __VA_ARGS__ );
+
+#define GSMOPEN_P_LOG NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt-&gt;name ? tech_pvt-&gt;name : &quot;none&quot; : &quot;none&quot;, -1, tech_pvt ? tech_pvt-&gt;interface_state : -1, tech_pvt ? tech_pvt-&gt;phone_callflow : -1
+
+/*********************************/
+#define GSMOPEN_CAUSE_NORMAL                1
+#define GSMOPEN_CAUSE_FAILURE                2
+#define GSMOPEN_CAUSE_NO_ANSWER                3
+/*********************************/
+#define GSMOPEN_FRAME_DTMF                1
+/*********************************/
+#define GSMOPEN_CONTROL_RINGING                1
+#define GSMOPEN_CONTROL_ANSWER                2
+#define GSMOPEN_CONTROL_HANGUP                3
+#define GSMOPEN_CONTROL_BUSY                4
+
+/*********************************/
+#define                GSMOPEN_STATE_IDLE                                0
+#define                GSMOPEN_STATE_DOWN                                1
+#define                GSMOPEN_STATE_RING                                2
+#define                GSMOPEN_STATE_DIALING                                3
+#define                GSMOPEN_STATE_BUSY                                4
+#define                GSMOPEN_STATE_UP                                5
+#define                GSMOPEN_STATE_RINGING                                6
+#define                GSMOPEN_STATE_PRERING                                7
+#define                GSMOPEN_STATE_ERROR_DOUBLE_CALL                        8
+#define                GSMOPEN_STATE_SELECTED                                9
+#define         GSMOPEN_STATE_HANGUP_REQUESTED                        10
+#define                GSMOPEN_STATE_PREANSWER                                11
+/*********************************/
+/* call flow from the device */
+#define         CALLFLOW_CALL_IDLE                                0
+#define         CALLFLOW_CALL_DOWN                                1
+#define         CALLFLOW_INCOMING_RING                                2
+#define         CALLFLOW_CALL_DIALING                                3
+#define         CALLFLOW_CALL_LINEBUSY                                4
+#define         CALLFLOW_CALL_ACTIVE                                5
+#define         CALLFLOW_INCOMING_HANGUP                        6
+#define         CALLFLOW_CALL_RELEASED                                7
+#define         CALLFLOW_CALL_NOCARRIER                                8
+#define         CALLFLOW_CALL_INFLUX                                9
+#define         CALLFLOW_CALL_INCOMING                                10
+#define         CALLFLOW_CALL_FAILED                                11
+#define         CALLFLOW_CALL_NOSERVICE                                12
+#define         CALLFLOW_CALL_OUTGOINGRESTRICTED                13
+#define         CALLFLOW_CALL_SECURITYFAIL                        14
+#define         CALLFLOW_CALL_NOANSWER                                15
+#define         CALLFLOW_STATUS_FINISHED                        16
+#define         CALLFLOW_STATUS_CANCELLED                        17
+#define         CALLFLOW_STATUS_FAILED                                18
+#define         CALLFLOW_STATUS_REFUSED                                19
+#define         CALLFLOW_STATUS_RINGING                                20
+#define         CALLFLOW_STATUS_INPROGRESS                        21
+#define         CALLFLOW_STATUS_UNPLACED                        22
+#define         CALLFLOW_STATUS_ROUTING                                23
+#define         CALLFLOW_STATUS_EARLYMEDIA                        24
+#define         CALLFLOW_INCOMING_CALLID                        25
+#define         CALLFLOW_STATUS_REMOTEHOLD                        26
+#define         CALLFLOW_CALL_REMOTEANSWER                        27
+#define         CALLFLOW_CALL_HANGUP_REQUESTED                        28
+
+/*********************************/
+
+#define         AT_OK   0
+#define         AT_ERROR   1
+
+#define GSMOPEN_MAX_INTERFACES 64
+
+#ifndef WIN32
+struct GSMopenHandles {
+        Window gsmopen_win;
+        Display *disp;
+        Window win;
+        int currentuserhandle;
+        int api_connected;
+        int fdesc[2];
+};
+#else //WIN32
+
+struct GSMopenHandles {
+        HWND win32_hInit_MainWindowHandle;
+        HWND win32_hGlobal_GSMAPIWindowHandle;
+        HINSTANCE win32_hInit_ProcessHandle;
+        char win32_acInit_WindowClassName[128];
+        UINT win32_uiGlobal_MsgID_GSMControlAPIAttach;
+        UINT win32_uiGlobal_MsgID_GSMControlAPIDiscover;
+        int currentuserhandle;
+        int api_connected;
+        switch_file_t *fdesc[2];
+};
+
+#endif //WIN32
+
+/*! 
+ * \brief structure for storing the results of AT commands, in an array of AT_MESG_MAX_LINES * AT_MESG_MAX_LENGTH chars
+ */
+struct s_result {
+        int elemcount;
+        char result[AT_MESG_MAX_LINES][AT_MESG_MAX_LENGTH];
+};
+
+struct ciapa_struct {
+        int state;
+        int hangupcause;
+};
+typedef struct ciapa_struct ciapa_t;
+
+struct private_object {
+        unsigned int flags;
+        switch_codec_t read_codec;
+        switch_codec_t write_codec;
+        switch_frame_t read_frame;
+        unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+        char session_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+        switch_caller_profile_t *caller_profile;
+        switch_mutex_t *mutex;
+        switch_mutex_t *flag_mutex;
+
+        char interface_id[80];
+        char name[80];
+        char dialplan[80];
+        char context[80];
+        char dial_regex[256];
+        char fail_dial_regex[256];
+        char hold_music[256];
+        char type[256];
+        char X11_display[256];
+#ifdef WIN32
+        unsigned short tcp_cli_port;
+        unsigned short tcp_srv_port;
+#else
+        int tcp_cli_port;
+        int tcp_srv_port;
+#endif
+        struct GSMopenHandles GSMopenHandles;
+
+        int interface_state;                /*!&lt; \brief 'state' of the interface (channel) */
+        char language[80];                        /*!&lt; \brief default Asterisk dialplan language for this interface */
+        char exten[80];                                /*!&lt; \brief default Asterisk dialplan extension for this interface */
+        int gsmopen_sound_rate;                /*!&lt; \brief rate of the sound device, in Hz, eg: 8000 */
+        char callid_name[50];
+        char callid_number[50];
+        double playback_boost;
+        double capture_boost;
+        int stripmsd;
+        char gsmopen_call_id[512];
+        int gsmopen_call_ongoing;
+        char gsmopen_friends[4096];
+        char gsmopen_fullname[512];
+        char gsmopen_displayname[512];
+        int phone_callflow;                        /*!&lt; \brief 'callflow' of the gsmopen interface (as opposed to phone interface) */
+        int gsmopen;                                /*!&lt; \brief config flag, bool, GSM support on this interface (0 if false, -1 if true) */
+        int control_to_send;
+#ifdef WIN32
+        switch_file_t *audiopipe[2];
+        switch_file_t *audiogsmopenpipe[2];
+        switch_file_t *gsmopen_sound_capt_fd;        /*!&lt; \brief file descriptor for sound capture dev */
+#else                                                        /* WIN32 */
+        int audiopipe[2];
+        int audiogsmopenpipe[2];
+        int gsmopen_sound_capt_fd;        /*!&lt; \brief file descriptor for sound capture dev */
+#endif                                                        /* WIN32 */
+        switch_thread_t *tcp_srv_thread;
+        switch_thread_t *tcp_cli_thread;
+        switch_thread_t *gsmopen_signaling_thread;
+        switch_thread_t *gsmopen_api_thread;
+        //short audiobuf[SAMPLES_PER_FRAME];
+        //int audiobuf_is_loaded;
+
+        //int phonebook_listing;
+        //int phonebook_querying;
+        //int phonebook_listing_received_calls;
+
+        //int phonebook_first_entry;
+        //int phonebook_last_entry;
+        //int phonebook_number_lenght;
+        //int phonebook_text_lenght;
+        int gsmopen_dir_entry_extension_prefix;
+        char gsmopen_user[256];
+        char gsmopen_password[256];
+        char destination[256];
+        struct timeval answer_time;
+
+        struct timeval transfer_time;
+        char transfer_callid_number[50];
+        char gsmopen_transfer_call_id[512];
+        int running;
+        unsigned long ib_calls;
+        unsigned long ob_calls;
+        unsigned long ib_failed_calls;
+        unsigned long ob_failed_calls;
+
+
+        char controldevice_name[50];        /*!&lt; \brief name of the serial device controlling the interface, possibly none */
+        int controldevprotocol;                /*!&lt; \brief which protocol is used for serial control of this interface */
+        char controldevprotocolname[50];        /*!&lt; \brief name of the serial device controlling protocol, one of &quot;at&quot; &quot;fbus2&quot; &quot;no_serial&quot; &quot;alsa_voicemodem&quot; */
+        int controldevfd;                        /*!&lt; \brief serial controlling file descriptor for this interface */
+        //pthread_t controldev_thread;  /*!&lt; \brief serial control thread for this interface, running during the call */
+        speed_t controldevice_speed;
+        int controldev_dead;
+
+        char at_dial_pre_number[64];
+        char at_dial_post_number[64];
+        char at_dial_expect[64];
+        unsigned int at_early_audio;
+        char at_hangup[64];
+        char at_hangup_expect[64];
+        char at_answer[64];
+        char at_answer_expect[64];
+        unsigned int at_initial_pause;
+        char at_preinit_1[64];
+        char at_preinit_1_expect[64];
+        char at_preinit_2[64];
+        char at_preinit_2_expect[64];
+        char at_preinit_3[64];
+        char at_preinit_3_expect[64];
+        char at_preinit_4[64];
+        char at_preinit_4_expect[64];
+        char at_preinit_5[64];
+        char at_preinit_5_expect[64];
+        unsigned int at_after_preinit_pause;
+
+        char at_postinit_1[64];
+        char at_postinit_1_expect[64];
+        char at_postinit_2[64];
+        char at_postinit_2_expect[64];
+        char at_postinit_3[64];
+        char at_postinit_3_expect[64];
+        char at_postinit_4[64];
+        char at_postinit_4_expect[64];
+        char at_postinit_5[64];
+        char at_postinit_5_expect[64];
+
+        char at_send_dtmf[64];
+
+        char at_query_battchg[64];
+        char at_query_battchg_expect[64];
+        char at_query_signal[64];
+        char at_query_signal_expect[64];
+        char at_call_idle[64];
+        char at_call_incoming[64];
+        char at_call_active[64];
+        char at_call_failed[64];
+        char at_call_calling[64];
+
+#define CIEV_STRING_SIZE 64
+        char at_indicator_noservice_string[64];
+        char at_indicator_nosignal_string[64];
+        char at_indicator_lowsignal_string[64];
+        char at_indicator_lowbattchg_string[64];
+        char at_indicator_nobattchg_string[64];
+        char at_indicator_callactive_string[64];
+        char at_indicator_nocallactive_string[64];
+        char at_indicator_nocallsetup_string[64];
+        char at_indicator_callsetupincoming_string[64];
+        char at_indicator_callsetupoutgoing_string[64];
+        char at_indicator_callsetupremoteringing_string[64];
+
+        int at_indicator_callp;
+        int at_indicator_callsetupp;
+        int at_indicator_roamp;
+        int at_indicator_battchgp;
+        int at_indicator_servicep;
+        int at_indicator_signalp;
+
+        int at_has_clcc;
+        int at_has_ecam;
+
+        char at_cmgw[16];
+        int no_ucs2;
+        time_t gsmopen_serial_sync_period;
+
+        time_t gsmopen_serial_synced_timestamp;
+        struct s_result line_array;
+
+
+        int unread_sms_msg_id;
+        int reading_sms_msg;
+        char sms_message[4800];
+        char sms_sender[256];
+        char sms_date[256];
+        char sms_body[4800];
+        int sms_cnmi_not_supported;
+        char sms_receiving_program[256];
+
+
+        struct timeval call_incoming_time;
+        switch_mutex_t *controldev_lock;
+
+        int phonebook_listing;
+        int phonebook_querying;
+        int phonebook_listing_received_calls;
+
+        int phonebook_first_entry;
+        int phonebook_last_entry;
+        int phonebook_number_lenght;
+        int phonebook_text_lenght;
+        FILE *phonebook_writing_fp;
+
+        struct timeval ringtime;
+        ciapa_t *owner;
+#ifdef GSMOPEN_ALSA
+        snd_pcm_t *alsac;                        /*!&lt; \brief handle of the ALSA capture audio device */
+        snd_pcm_t *alsap;                        /*!&lt; \brief handle of the ALSA playback audio device */
+        char alsacname[50];                        /*!&lt; \brief name of the ALSA capture audio device */
+        char alsapname[50];                        /*!&lt; \brief name of the ALSA playback audio device */
+        int alsa_period_size;                /*!&lt; \brief ALSA period_size, in byte */
+        int alsa_periods_in_buffer;        /*!&lt; \brief how many periods in ALSA buffer, to calculate buffer_size */
+        unsigned long int alsa_buffer_size;        /*!&lt; \brief ALSA buffer_size, in byte */
+        int alsawrite_filled;
+        int alsa_capture_is_mono;
+        int alsa_play_is_mono;
+        struct pollfd pfd;
+#endif                                                        // GSMOPEN_ALSA
+
+        time_t audio_play_reset_timestamp;
+        int audio_play_reset_period;
+
+        switch_timer_t timer_read;
+        switch_timer_t timer_write;
+        teletone_dtmf_detect_state_t dtmf_detect;
+        switch_time_t old_dtmf_timestamp;
+
+};
+
+typedef struct private_object private_t;
+
+void *SWITCH_THREAD_FUNC gsmopen_api_thread_func(switch_thread_t *thread, void *obj);
+int gsmopen_audio_read(private_t * tech_pvt);
+int gsmopen_audio_init(private_t * tech_pvt);
+int gsmopen_signaling_read(private_t * tech_pvt);
+
+int gsmopen_call(private_t * tech_pvt, char *idest, int timeout);
+int gsmopen_senddigit(private_t * tech_pvt, char digit);
+
+void *gsmopen_do_tcp_srv_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC gsmopen_do_tcp_srv_thread(switch_thread_t *thread, void *obj);
+
+void *gsmopen_do_tcp_cli_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC gsmopen_do_tcp_cli_thread(switch_thread_t *thread, void *obj);
+
+void *gsmopen_do_gsmopenapi_thread_func(void *obj);
+void *SWITCH_THREAD_FUNC gsmopen_do_gsmopenapi_thread(switch_thread_t *thread, void *obj);
+int dtmf_received(private_t * tech_pvt, char *value);
+int start_audio_threads(private_t * tech_pvt);
+int new_inbound_channel(private_t * tech_pvt);
+int outbound_channel_answered(private_t * tech_pvt);
+//int gsmopen_signaling_write(private_t * tech_pvt, char *msg_to_gsmopen);
+#if defined(WIN32) &amp;&amp; !defined(__CYGWIN__)
+int gsmopen_pipe_read(switch_file_t *pipe, short *buf, int howmany);
+int gsmopen_pipe_write(switch_file_t *pipe, short *buf, int howmany);
+/* Visual C do not have strsep ? */
+char *strsep(char **stringp, const char *delim);
+#else
+int gsmopen_pipe_read(int pipe, short *buf, int howmany);
+int gsmopen_pipe_write(int pipe, short *buf, int howmany);
+#endif /* WIN32 */
+int gsmopen_close_socket(unsigned int fd);
+private_t *find_available_gsmopen_interface_rr(private_t * tech_pvt_calling);
+int remote_party_is_ringing(private_t * tech_pvt);
+int remote_party_is_early_media(private_t * tech_pvt);
+//int gsmopen_answer(private_t * tech_pvt, char *id, char *value);
+int gsmopen_transfer(private_t * tech_pvt, char *id, char *value);
+int gsmopen_socket_create_and_bind(private_t * tech_pvt, int *which_port);
+
+
+
+
+
+void *gsmopen_do_controldev_thread(void *data);
+int gsmopen_serial_init(private_t * tech_pvt, speed_t controldevice_speed);
+int gsmopen_serial_monitor(private_t * tech_pvt);
+int gsmopen_serial_sync(private_t * tech_pvt);
+int gsmopen_serial_sync_AT(private_t * tech_pvt);
+int gsmopen_serial_config(private_t * tech_pvt);
+int gsmopen_serial_config_AT(private_t * tech_pvt);
+
+#define gsmopen_serial_write_AT_expect(P, D, S) gsmopen_serial_write_AT_expect1(P, D, S, 1, 2)
+#define gsmopen_serial_write_AT_expect_noexpcr(P, D, S) gsmopen_serial_write_AT_expect1(P, D, S, 0, 2)
+#define gsmopen_serial_write_AT_expect_noexpcr_tout(P, D, S, T) gsmopen_serial_write_AT_expect1(P, D, S, 0, T)
+// 20.5 sec timeout, used for querying the SIM and sending SMSs
+#define gsmopen_serial_write_AT_expect_longtime(P, D, S) gsmopen_serial_write_AT_expect1(P, D, S, 1, 20)
+#define gsmopen_serial_write_AT_expect_longtime_noexpcr(P, D, S) gsmopen_serial_write_AT_expect1(P, D, S, 0, 20)
+int gsmopen_serial_write_AT(private_t * tech_pvt, const char *data);
+int gsmopen_serial_write_AT_nocr(private_t * tech_pvt, const char *data);
+int gsmopen_serial_write_AT_ack(private_t * tech_pvt, const char *data);
+int gsmopen_serial_write_AT_ack_nocr_longtime(private_t * tech_pvt, const char *data);
+int gsmopen_serial_write_AT_noack(private_t * tech_pvt, const char *data);
+int gsmopen_serial_write_AT_expect1(private_t * tech_pvt, const char *data, const char *expected_string, int expect_crlf, int seconds);
+int gsmopen_serial_AT_expect(private_t * tech_pvt, const char *expected_string, int expect_crlf, int seconds);
+int gsmopen_serial_read_AT(private_t * tech_pvt, int look_for_ack, int timeout_usec, int timeout_sec, const char *expected_string, int expect_crlf);
+int gsmopen_serial_read(private_t * tech_pvt);
+#ifdef NOTDEF
+int gsmopen_serial_getstatus(private_t * tech_pvt);
+int gsmopen_serial_hangup(private_t * tech_pvt);
+int gsmopen_serial_answer(private_t * tech_pvt);
+int gsmopen_serial_answer_AT(private_t * tech_pvt);
+int gsmopen_serial_hangup_AT(private_t * tech_pvt);
+int gsmopen_serial_call_AT(private_t * tech_pvt, char *dstr);
+int gsmopen_serial_getstatus_AT(private_t * tech_pvt);
+#endif // NOTDEF
+#define RESULT_FAILURE 0
+#define RESULT_SUCCESS 1
+int utf_to_ucs2(private_t * tech_pvt, char *utf_in, size_t inbytesleft, char *ucs2_out, size_t outbytesleft);
+int ucs2_to_utf8(private_t * tech_pvt, char *ucs2_in, char *utf8_out, size_t outbytesleft);
+//#define PUSHA_UNLOCKA(x)    pthread_cleanup_push(gsmopen_unlocka_log, (void *) x);
+//#define POPPA_UNLOCKA(x)    pthread_cleanup_pop(0);
+
+#define PUSHA_UNLOCKA(x)    if(option_debug &gt; 100) ERRORA(&quot;PUSHA_UNLOCKA: %p\n&quot;, GSMOPEN_P_LOG, (void *)x);
+#define POPPA_UNLOCKA(x)    if(option_debug &gt; 100) ERRORA(&quot;POPPA_UNLOCKA: %p\n&quot;, GSMOPEN_P_LOG, (void *)x);
+//#define LOKKA(x)    if(option_debug &gt; 100) ERRORA(&quot;LOKKA: %p\n&quot;, GSMOPEN_P_LOG, (void *)x);
+#define LOKKA(x)    switch_mutex_lock(x);
+#define UNLOCKA(x)  switch_mutex_unlock(x);
+//#define UNLOCKA(x)    if(option_debug &gt; 100) ERRORA(&quot;UNLOCKA: %p\n&quot;, GSMOPEN_P_LOG, (void *)x);
+
+#define gsmopen_queue_control(x, y) ERRORA(&quot;gsmopen_queue_control: %p, %d\n&quot;, GSMOPEN_P_LOG, (void *)x, y);
+
+#define ast_setstate(x, y) ERRORA(&quot;ast_setstate: %p, %d\n&quot;, GSMOPEN_P_LOG, (void *)x, y);
+
+int gsmopen_serial_read(private_t * tech_pvt);
+int gsmopen_answer(private_t * tech_pvt);
+int gsmopen_serial_answer(private_t * tech_pvt);
+int gsmopen_serial_answer_AT(private_t * tech_pvt);
+int gsmopen_serial_hangup(private_t * tech_pvt);
+int gsmopen_serial_hangup_AT(private_t * tech_pvt);
+int gsmopen_hangup(private_t * tech_pvt);
+int gsmopen_serial_call(private_t * tech_pvt, char *dstr);
+int gsmopen_serial_call_AT(private_t * tech_pvt, char *dstr);
+int gsmopen_sendsms(private_t * tech_pvt, char *dest, char *text);
+
+#ifdef GSMOPEN_ALSA
+int alsa_init(private_t * tech_pvt);
+int alsa_shutdown(private_t * tech_pvt);
+snd_pcm_t *alsa_open_dev(private_t * tech_pvt, snd_pcm_stream_t stream);
+int alsa_write(private_t * tech_pvt, short *data, int datalen);
+int alsa_read(private_t * tech_pvt, short *data, int datalen);
+
+#endif /* GSMOPEN_ALSA */
+
+
+void gsmopen_store_boost(char *s, double *boost);
+int gsmopen_sound_boost(void *data, int samples_num, double boost);
+int sms_incoming(private_t * tech_pvt, char *value);
+int gsmopen_ring(private_t * tech_pvt);
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopengsmopen_protocolcfromrev15046freeswitchbranchesgmaruzzmod_gsmopencelliax_protocolc"></a>
<div class="copfile"><h4>Copied: freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.c (from rev 15046, freeswitch/branches/gmaruzz/mod_gsmopen/celliax_protocol.c) (0 => 15047)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.c                                (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.c        2009-10-02 13:19:23 UTC (rev 15047)
</span><span class="lines">@@ -0,0 +1,3002 @@
</span><ins>+#include &quot;gsmopen.h&quot;
+
+#ifdef ASTERISK
+#define gsmopen_sleep usleep
+#define gsmopen_strncpy strncpy
+#define tech_pvt p
+extern int gsmopen_debug;
+extern char *gsmopen_console_active;
+#else /* FREESWITCH */
+#define gsmopen_sleep switch_sleep
+#define gsmopen_strncpy switch_copy_string
+extern switch_memory_pool_t *gsmopen_module_pool;
+extern switch_endpoint_interface_t *gsmopen_endpoint_interface;
+#endif /* ASTERISK */
+//int samplerate_gsmopen = SAMPLERATE_GSMOPEN;
+
+extern int running;
+int gsmopen_dir_entry_extension = 1;
+
+int option_debug = 100;
+
+
+
+int gsmopen_serial_init(private_t * tech_pvt, speed_t controldevice_speed)
+{
+        int fd;
+        int rt;
+        struct termios tp;
+
+/* if there is a file descriptor, close it. But it is probably just an old value, so don't check for close success*/
+        fd = tech_pvt-&gt;controldevfd;
+        if (fd) {
+                close(fd);
+        }
+/*  open the serial port */
+#ifdef __CYGWIN__
+        fd = open(tech_pvt-&gt;controldevice_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
+        sleep(1);
+        close(fd);
+#endif /* __CYGWIN__ */
+        fd = open(tech_pvt-&gt;controldevice_name, O_RDWR | O_NOCTTY | O_NONBLOCK);
+        if (fd == -1) {
+                DEBUGA_GSMOPEN(&quot;serial error: %s\n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                tech_pvt-&gt;controldevfd = fd;
+                return -1;
+        }
+/*  flush it */
+        rt = tcflush(fd, TCIFLUSH);
+        if (rt == -1) {
+                ERRORA(&quot;serial error: %s&quot;, GSMOPEN_P_LOG, strerror(errno));
+        }
+/*  attributes */
+        tp.c_cflag = B0 | CS8 | CLOCAL | CREAD | HUPCL;
+        tp.c_iflag = IGNPAR;
+        tp.c_cflag &amp;= ~CRTSCTS;
+        tp.c_oflag = 0;
+        tp.c_lflag = 0;
+        tp.c_cc[VMIN] = 1;
+        tp.c_cc[VTIME] = 0;
+/*  set controldevice_speed */
+        rt = cfsetispeed(&amp;tp, tech_pvt-&gt;controldevice_speed);
+        if (rt == -1) {
+                ERRORA(&quot;serial error: %s, speed was: %d&quot;, GSMOPEN_P_LOG, strerror(errno), tech_pvt-&gt;controldevice_speed);
+        }
+        rt = cfsetospeed(&amp;tp, tech_pvt-&gt;controldevice_speed);
+        if (rt == -1) {
+                ERRORA(&quot;serial error: %s&quot;, GSMOPEN_P_LOG, strerror(errno));
+        }
+/*  set port attributes */
+        if (tcsetattr(fd, TCSADRAIN, &amp;tp) == -1) {
+                ERRORA(&quot;serial error: %s&quot;, GSMOPEN_P_LOG, strerror(errno));
+        }
+        rt = tcsetattr(fd, TCSANOW, &amp;tp);
+        if (rt == -1) {
+                ERRORA(&quot;serial error: %s&quot;, GSMOPEN_P_LOG, strerror(errno));
+        }
+        unsigned int status = 0;
+#ifndef __CYGWIN__
+        ioctl(fd, TIOCMGET, &amp;status);
+        status |= TIOCM_DTR;                /*  Set DTR high */
+        status &amp;= ~TIOCM_RTS;                /*  Set RTS low */
+        ioctl(fd, TIOCMSET, &amp;status);
+        ioctl(fd, TIOCMGET, &amp;status);
+        unsigned int flags = TIOCM_DTR;
+        ioctl(fd, TIOCMBIS, &amp;flags);
+        flags = TIOCM_RTS;
+        ioctl(fd, TIOCMBIC, &amp;flags);
+        ioctl(fd, TIOCMGET, &amp;status);
+#else /* __CYGWIN__ */
+        ioctl(fd, TIOCMGET, &amp;status);
+        status |= TIOCM_DTR;                /*  Set DTR high */
+        status &amp;= ~TIOCM_RTS;                /*  Set RTS low */
+        ioctl(fd, TIOCMSET, &amp;status);
+#endif /* __CYGWIN__ */
+        tech_pvt-&gt;controldevfd = fd;
+        DEBUGA_GSMOPEN(&quot;Syncing Serial\n&quot;, GSMOPEN_P_LOG);
+        rt = gsmopen_serial_sync(tech_pvt);
+        if (rt == -1) {
+                ERRORA(&quot;Serial init error\n&quot;, GSMOPEN_P_LOG);
+                return -1;
+        }
+        return (fd);
+}
+
+int gsmopen_serial_read(private_t * tech_pvt)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_read_AT(tech_pvt, 0, 100000, 0, NULL, 1);        // a 10th of a second timeout
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_read_FBUS2(tech_pvt);
+#endif /* GSMOPEN_FBUS2 */
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_read_CVM_BUSMAIL(tech_pvt);
+#endif /* GSMOPEN_CVM */
+        return -1;
+}
+
+
+int gsmopen_serial_sync(private_t * tech_pvt)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_sync_AT(tech_pvt);
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_sync_FBUS2(tech_pvt);
+#endif /* GSMOPEN_FBUS2 */
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_sync_CVM_BUSMAIL(tech_pvt);
+#endif /* GSMOPEN_CVM */
+
+        return -1;
+}
+
+int gsmopen_serial_config(private_t * tech_pvt)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_config_AT(tech_pvt);
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_config_FBUS2(tech_pvt);
+#endif /* GSMOPEN_FBUS2 */
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_config_CVM_BUSMAIL(tech_pvt);
+#endif /* GSMOPEN_CVM */
+        return -1;
+}
+
+int gsmopen_serial_config_AT(private_t * tech_pvt)
+{
+        int res;
+
+/* initial_pause? */
+        if (tech_pvt-&gt;at_initial_pause) {
+                DEBUGA_GSMOPEN(&quot;sleeping for %d usec\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_initial_pause);
+                usleep(tech_pvt-&gt;at_initial_pause);
+        }
+
+/* go until first empty preinit string, or last preinit string */
+        while (1) {
+
+                if (strlen(tech_pvt-&gt;at_preinit_1)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_preinit_1, tech_pvt-&gt;at_preinit_1_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_preinit_1, tech_pvt-&gt;at_preinit_1_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_preinit_2)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_preinit_2, tech_pvt-&gt;at_preinit_2_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_preinit_2, tech_pvt-&gt;at_preinit_2_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_preinit_3)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_preinit_3, tech_pvt-&gt;at_preinit_3_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_preinit_3, tech_pvt-&gt;at_preinit_3_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_preinit_4)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_preinit_4, tech_pvt-&gt;at_preinit_4_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_preinit_4, tech_pvt-&gt;at_preinit_4_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_preinit_5)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_preinit_5, tech_pvt-&gt;at_preinit_5_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_preinit_5, tech_pvt-&gt;at_preinit_5_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                break;
+        }
+
+/* after_preinit_pause? */
+        if (tech_pvt-&gt;at_after_preinit_pause) {
+                DEBUGA_GSMOPEN(&quot;sleeping for %d usec\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_after_preinit_pause);
+                usleep(tech_pvt-&gt;at_after_preinit_pause);
+        }
+
+        /* phone, brother, art you alive? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT&quot;);
+        if (res) {
+                ERRORA(&quot;no response to AT\n&quot;, GSMOPEN_P_LOG);
+                return -1;
+        }
+        /* for motorola, bring it back to &quot;normal&quot; mode if it happens to be in another mode */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+mode=0&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+mode=0 does not get OK from the phone. If it is NOT Motorola,&quot; &quot; no problem.\n&quot;, GSMOPEN_P_LOG);
+        }
+        usleep(50000);
+        /* for motorola end */
+
+        /* reset AT configuration to phone default */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;ATZ&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;ATZ failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* disable AT command echo */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;ATE0&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;ATE0 failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* disable extended error reporting */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CMEE=0&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CMEE failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* various phone manufacturer identifier */
+        char at_command[5];
+        int i;
+        for (i = 0; i &lt; 10; i++) {
+                memset(at_command, 0, sizeof(at_command));
+                sprintf(at_command, &quot;ATI%d&quot;, i);
+                res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
+                if (res) {
+                        DEBUGA_GSMOPEN(&quot;ATI%d command failed, continue\n&quot;, GSMOPEN_P_LOG, i);
+                }
+        }
+
+        /* phone manufacturer */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CGMI&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CGMI failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* phone model */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CGMM&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CGMM failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CGSN&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CGSN failed\n&quot;, GSMOPEN_P_LOG);
+        }
+
+/* this take a lot of time to complete on devices with slow serial link (eg.: 9600bps) */
+        /* signal incoming SMS with a +CMTI unsolicited msg */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CNMI=3,1,0,0,0&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CNMI=3,1,0,0,0 failed, continue\n&quot;, GSMOPEN_P_LOG);
+                tech_pvt-&gt;sms_cnmi_not_supported = 1;
+                tech_pvt-&gt;gsmopen_serial_sync_period = 30;
+        }
+        /* what is the Message Center address (number) to which the SMS has to be sent? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCA?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CSCA? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* what is the Message Format of SMSs? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CMGF?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CMGF? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CMGF=1&quot;);        //TODO: support phones that only accept pdu mode
+        if (res) {
+                ERRORA(&quot;Error setting SMS sending mode to TEXT on the cellphone\n&quot;, GSMOPEN_P_LOG);
+                return RESULT_FAILURE;
+        }
+        /* what is the Charset of SMSs? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CSCS? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        tech_pvt-&gt;no_ucs2 = 0;
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS=\&quot;UCS2\&quot;&quot;);
+        if (res) {
+                WARNINGA(&quot;AT+CSCS=\&quot;UCS2\&quot; (set TE messages to ucs2)  do not got OK from the phone, let's try with 'GSM'\n&quot;, GSMOPEN_P_LOG);
+                tech_pvt-&gt;no_ucs2 = 1;
+        }
+
+        if (tech_pvt-&gt;no_ucs2) {
+                res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS=\&quot;GSM\&quot;&quot;);
+                if (res) {
+                        WARNINGA(&quot;AT+CSCS=\&quot;GSM\&quot; (set TE messages to GSM)  do not got OK from the phone\n&quot;, GSMOPEN_P_LOG);
+                }
+                //res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSMP=17,167,0,16&quot;); //&quot;flash&quot;, class 0  sms 7 bit
+                res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSMP=17,167,0,0&quot;);        //normal, 7 bit message
+                if (res) {
+                        WARNINGA(&quot;AT+CSMP do not got OK from the phone, continuing\n&quot;, GSMOPEN_P_LOG);
+                }
+        } else {
+                //res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSMP=17,167,0,20&quot;); //&quot;flash&quot;, class 0 sms 16 bit unicode
+                res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSMP=17,167,0,8&quot;);        //unicode, 16 bit message
+                if (res) {
+                        WARNINGA(&quot;AT+CSMP do not got OK from the phone, continuing\n&quot;, GSMOPEN_P_LOG);
+                }
+        }
+
+        /* is the unsolicited reporting of mobile equipment event supported? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CMER=?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CMER=? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* request unsolicited reporting of mobile equipment indicators' events, to be screened by categories reported by +CIND=? */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CMER=3,0,0,1&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CMER=? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* is the solicited reporting of mobile equipment indications supported? */
+
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CIND=?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CIND=? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        /* is the unsolicited reporting of call monitoring supported? sony-ericsson specific */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT*ECAM=?&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT*ECAM=? failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* enable the unsolicited reporting of call monitoring. sony-ericsson specific */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT*ECAM=1&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT*ECAM=1 failed, continue\n&quot;, GSMOPEN_P_LOG);
+                tech_pvt-&gt;at_has_ecam = 0;
+        } else {
+                tech_pvt-&gt;at_has_ecam = 1;
+        }
+
+        /* disable unsolicited signaling of call list */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CLCC=0&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CLCC=0 failed, continue\n&quot;, GSMOPEN_P_LOG);
+                tech_pvt-&gt;at_has_clcc = 0;
+        } else {
+                tech_pvt-&gt;at_has_clcc = 1;
+        }
+
+        /* give unsolicited caller id when incoming call */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CLIP=1&quot;);
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+CLIP failed, continue\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* for motorola */
+        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+MCST=1&quot;);        /* motorola call control codes
+                                                                                                                                   (to know when call is disconnected (they
+                                                                                                                                   don't give you &quot;no carrier&quot;) */
+        if (res) {
+                DEBUGA_GSMOPEN(&quot;AT+MCST=1 does not get OK from the phone. If it is NOT Motorola,&quot; &quot; no problem.\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* for motorola end */
+
+/* go until first empty postinit string, or last postinit string */
+        while (1) {
+
+                if (strlen(tech_pvt-&gt;at_postinit_1)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_postinit_1, tech_pvt-&gt;at_postinit_1_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_postinit_1, tech_pvt-&gt;at_postinit_1_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_postinit_2)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_postinit_2, tech_pvt-&gt;at_postinit_2_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_postinit_2, tech_pvt-&gt;at_postinit_2_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_postinit_3)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_postinit_3, tech_pvt-&gt;at_postinit_3_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_postinit_3, tech_pvt-&gt;at_postinit_3_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_postinit_4)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_postinit_4, tech_pvt-&gt;at_postinit_4_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_postinit_4, tech_pvt-&gt;at_postinit_4_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                if (strlen(tech_pvt-&gt;at_postinit_5)) {
+                        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_postinit_5, tech_pvt-&gt;at_postinit_5_expect);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;%s does not get %s from the phone. Continuing.\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_postinit_5, tech_pvt-&gt;at_postinit_5_expect);
+                        }
+                } else {
+                        break;
+                }
+
+                break;
+        }
+
+        return 0;
+}
+
+
+int gsmopen_serial_sync_AT(private_t * tech_pvt)
+{
+        usleep(10000);                                /* 10msec */
+        time(&amp;tech_pvt-&gt;gsmopen_serial_synced_timestamp);
+        return 0;
+}
+int gsmopen_serial_read_AT(private_t * tech_pvt, int look_for_ack, int timeout_usec, int timeout_sec, const char *expected_string, int expect_crlf)
+{
+        int select_err=1;
+        int res;
+        fd_set read_fds;
+        struct timeval timeout;
+        char tmp_answer[AT_BUFSIZ];
+        char tmp_answer2[AT_BUFSIZ];
+        char *tmp_answer_ptr;
+        char *last_line_ptr;
+        int i = 0;
+        int read_count = 0;
+        int la_counter = 0;
+        int at_ack = -1;
+        int la_read = 0;
+
+        FD_ZERO(&amp;read_fds);
+        FD_SET(tech_pvt-&gt;controldevfd, &amp;read_fds);
+
+        //NOTICA (&quot; INSIDE this gsmopen_serial_device %s \n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;controldevice_name);
+        tmp_answer_ptr = tmp_answer;
+        memset(tmp_answer, 0, sizeof(char) * AT_BUFSIZ);
+
+        timeout.tv_sec = timeout_sec;
+        timeout.tv_usec = timeout_usec;
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+
+        while ((!tech_pvt-&gt;controldev_dead) &amp;&amp; ((select_err = select(tech_pvt-&gt;controldevfd + 1, &amp;read_fds, NULL, NULL, &amp;timeout)) &gt; 0) ) {
+                timeout.tv_sec = timeout_sec;        //reset the timeout, linux modify it
+                timeout.tv_usec = timeout_usec;        //reset the timeout, linux modify it
+                read_count = read(tech_pvt-&gt;controldevfd, tmp_answer_ptr, AT_BUFSIZ - (tmp_answer_ptr - tmp_answer));
+
+                if (read_count == 0) {
+                        ERRORA
+                                (&quot;read 0 bytes!!! Nenormalno! Marking this gsmopen_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the phone is stuck, switched off, power down or battery exhausted\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;controldevice_name);
+                        tech_pvt-&gt;controldev_dead = 1;
+                        close(tech_pvt-&gt;controldevfd);
+                        UNLOCKA(tech_pvt-&gt;controldev_lock);
+                        if (tech_pvt-&gt;owner) {
+                                tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                        }
+                        return -1;
+                }
+
+                if (option_debug &gt; 90) {
+                        //DEBUGA_GSMOPEN(&quot;1 read %d bytes, --|%s|--\n&quot;, GSMOPEN_P_LOG, read_count, tmp_answer_ptr);
+                        //DEBUGA_GSMOPEN(&quot;2 read %d bytes, --|%s|--\n&quot;, GSMOPEN_P_LOG, read_count, tmp_answer);
+                }
+                tmp_answer_ptr = tmp_answer_ptr + read_count;
+
+                char *token_ptr;
+
+                la_counter = 0;
+                memset(tmp_answer2, 0, sizeof(char) * AT_BUFSIZ);
+                strcpy(tmp_answer2, tmp_answer);
+                if ((token_ptr = strtok(tmp_answer2, &quot;\n\r&quot;))) {
+                        last_line_ptr = token_ptr;
+                        strncpy(tech_pvt-&gt;line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
+                        if (strlen(token_ptr) &gt; AT_MESG_MAX_LENGTH) {
+                                WARNINGA
+                                        (&quot;AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n&quot;,
+                                         GSMOPEN_P_LOG, token_ptr, tech_pvt-&gt;line_array.result[la_counter]);
+                        }
+                        la_counter++;
+                        while ((token_ptr = strtok(NULL, &quot;\n\r&quot;))) {
+                                last_line_ptr = token_ptr;
+                                strncpy(tech_pvt-&gt;line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
+                                if (strlen(token_ptr) &gt; AT_MESG_MAX_LENGTH) {
+                                        WARNINGA
+                                                (&quot;AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n&quot;,
+                                                 GSMOPEN_P_LOG, token_ptr, tech_pvt-&gt;line_array.result[la_counter]);
+                                }
+                                la_counter++;
+                        }
+                } else {
+                        last_line_ptr = tmp_answer;
+                }
+
+                if (expected_string &amp;&amp; !expect_crlf) {
+                        DEBUGA_GSMOPEN
+                                (&quot;last_line_ptr=|%s|, expected_string=|%s|, expect_crlf=%d, memcmp(last_line_ptr, expected_string, strlen(expected_string)) = %d\n&quot;,
+                                 GSMOPEN_P_LOG, last_line_ptr, expected_string, expect_crlf, memcmp(last_line_ptr, expected_string, strlen(expected_string)));
+                }
+
+                if (expected_string &amp;&amp; !expect_crlf &amp;&amp; !memcmp(last_line_ptr, expected_string, strlen(expected_string))
+                        ) {
+                        strncpy(tech_pvt-&gt;line_array.result[la_counter], last_line_ptr, AT_MESG_MAX_LENGTH);
+                        // match expected string -&gt; accept it withtout CRLF
+                        la_counter++;
+
+                }
+                /* if the last line read was not a complete line, we'll read the rest in the future */
+                else if (tmp_answer[strlen(tmp_answer) - 1] != '\r' &amp;&amp; tmp_answer[strlen(tmp_answer) - 1] != '\n')
+                        la_counter--;
+
+                /* let's list the complete lines read so far, without re-listing the lines that has yet been listed */
+                if (option_debug &gt; 1) {
+                        for (i = la_read; i &lt; la_counter; i++)
+                                DEBUGA_GSMOPEN(&quot;Read line %d: |%s|\n&quot;, GSMOPEN_P_LOG, i, tech_pvt-&gt;line_array.result[i]);
+                }
+
+                /* let's interpret the complete lines read so far (WITHOUT looking for OK, ERROR, and EXPECTED_STRING), without re-interpreting the lines that has been yet interpreted, so we're sure we don't miss anything */
+                for (i = la_read; i &lt; la_counter; i++) {
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;RING&quot;) == 0)) {
+                                /* with first RING we wait for callid */
+                                gettimeofday(&amp;(tech_pvt-&gt;ringtime), NULL);
+                                /* give CALLID (+CLIP) a chance, wait for the next RING before answering */
+                                if (tech_pvt-&gt;phone_callflow == CALLFLOW_INCOMING_RING) {
+                                        /* we're at the second ring, set the interface state, will be answered by gsmopen_do_monitor */
+                                        DEBUGA_GSMOPEN(&quot;|%s| got second RING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                        tech_pvt-&gt;interface_state = GSMOPEN_STATE_RING;
+                                } else {
+                                        /* we're at the first ring, so there is no CALLID yet thus clean the previous one 
+                                           just in case we don't receive the caller identification in this new call */
+                                        memset(tech_pvt-&gt;callid_name, 0, sizeof(tech_pvt-&gt;callid_name));
+                                        memset(tech_pvt-&gt;callid_number, 0, sizeof(tech_pvt-&gt;callid_number));
+                                        /* only send AT+CLCC? if the device previously reported its support */
+                                        if (tech_pvt-&gt;at_has_clcc != 0) {
+                                                /* we're at the first ring, try to get CALLID (with +CLCC) */
+                                                DEBUGA_GSMOPEN(&quot;|%s| got first RING, sending AT+CLCC?\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                res = gsmopen_serial_write_AT_noack(tech_pvt, &quot;AT+CLCC?&quot;);
+                                                if (res) {
+                                                        ERRORA(&quot;AT+CLCC? (call list) was not correctly sent to the phone\n&quot;, GSMOPEN_P_LOG);
+                                                }
+                                        } else {
+                                                DEBUGA_GSMOPEN(&quot;|%s| got first RING, but not sending AT+CLCC? as this device &quot;
+                                                                           &quot;seems not to support\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                        }
+                                }
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_INCOMING_RING;
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CLCC&quot;, 5) == 0)) {
+                                /* with clcc we wait for clip */
+                                memset(tech_pvt-&gt;callid_name, 0, sizeof(tech_pvt-&gt;callid_name));
+                                memset(tech_pvt-&gt;callid_number, 0, sizeof(tech_pvt-&gt;callid_number));
+                                int commacount = 0;
+                                int a = 0;
+                                int b = 0;
+                                int c = 0;
+
+                                for (a = 0; a &lt; strlen(tech_pvt-&gt;line_array.result[i]); a++) {
+
+                                        if (tech_pvt-&gt;line_array.result[i][a] == ',') {
+                                                commacount++;
+                                        }
+                                        if (commacount == 5) {
+                                                if (tech_pvt-&gt;line_array.result[i][a] != ',' &amp;&amp; tech_pvt-&gt;line_array.result[i][a] != '&quot;') {
+                                                        tech_pvt-&gt;callid_number[b] = tech_pvt-&gt;line_array.result[i][a];
+                                                        b++;
+                                                }
+                                        }
+                                        if (commacount == 7) {
+                                                if (tech_pvt-&gt;line_array.result[i][a] != ',' &amp;&amp; tech_pvt-&gt;line_array.result[i][a] != '&quot;') {
+                                                        tech_pvt-&gt;callid_name[c] = tech_pvt-&gt;line_array.result[i][a];
+                                                        c++;
+                                                }
+                                        }
+                                }
+
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_INCOMING_RING;
+                                DEBUGA_GSMOPEN(&quot;|%s| CLCC CALLID: name is %s, number is %s\n&quot;, GSMOPEN_P_LOG,
+                                                           tech_pvt-&gt;line_array.result[i],
+                                                           tech_pvt-&gt;callid_name[0] ? tech_pvt-&gt;callid_name : &quot;not available&quot;,
+                                                           tech_pvt-&gt;callid_number[0] ? tech_pvt-&gt;callid_number : &quot;not available&quot;);
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CLIP&quot;, 5) == 0)) {
+                                /* with CLIP, we want to answer right away */
+                                memset(tech_pvt-&gt;callid_name, 0, sizeof(tech_pvt-&gt;callid_name));
+                                memset(tech_pvt-&gt;callid_number, 0, sizeof(tech_pvt-&gt;callid_number));
+
+                                int commacount = 0;
+                                int a = 0;
+                                int b = 0;
+                                int c = 0;
+
+                                for (a = 7; a &lt; strlen(tech_pvt-&gt;line_array.result[i]); a++) {
+                                        if (tech_pvt-&gt;line_array.result[i][a] == ',') {
+                                                commacount++;
+                                        }
+                                        if (commacount == 0) {
+                                                if (tech_pvt-&gt;line_array.result[i][a] != ',' &amp;&amp; tech_pvt-&gt;line_array.result[i][a] != '&quot;') {
+                                                        tech_pvt-&gt;callid_number[b] = tech_pvt-&gt;line_array.result[i][a];
+                                                        b++;
+                                                }
+                                        }
+                                        if (commacount == 4) {
+                                                if (tech_pvt-&gt;line_array.result[i][a] != ',' &amp;&amp; tech_pvt-&gt;line_array.result[i][a] != '&quot;') {
+                                                        tech_pvt-&gt;callid_name[c] = tech_pvt-&gt;line_array.result[i][a];
+                                                        c++;
+                                                }
+                                        }
+                                }
+
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_RING) {
+                                        gettimeofday(&amp;(tech_pvt-&gt;call_incoming_time), NULL);
+                                        DEBUGA_GSMOPEN(&quot;GSMOPEN_STATE_RING call_incoming_time.tv_sec=%ld\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec);
+
+                                }
+
+                                tech_pvt-&gt;interface_state = GSMOPEN_STATE_RING;
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_INCOMING_RING;
+                                DEBUGA_GSMOPEN(&quot;|%s| CLIP INCOMING CALLID: name is %s, number is %s\n&quot;, GSMOPEN_P_LOG,
+                                                           tech_pvt-&gt;line_array.result[i],
+                                                           (strlen(tech_pvt-&gt;callid_name) &amp;&amp; tech_pvt-&gt;callid_name[0] != 1) ? tech_pvt-&gt;callid_name : &quot;not available&quot;,
+                                                           strlen(tech_pvt-&gt;callid_number) ? tech_pvt-&gt;callid_number : &quot;not available&quot;);
+
+                                if (!strlen(tech_pvt-&gt;callid_number)) {
+                                        strcpy(tech_pvt-&gt;callid_number, &quot;not available&quot;);
+                                }
+
+                                if (!strlen(tech_pvt-&gt;callid_name) &amp;&amp; tech_pvt-&gt;callid_name[0] != 1) {
+                                        strncpy(tech_pvt-&gt;callid_name, tech_pvt-&gt;callid_number, sizeof(tech_pvt-&gt;callid_name));
+                                        //strncpy(tech_pvt-&gt;callid_name, tech_pvt-&gt;callid_number, sizeof(tech_pvt-&gt;callid_name)) ;
+                                        snprintf(tech_pvt-&gt;callid_name, sizeof(tech_pvt-&gt;callid_name), &quot;GSMopen: %s&quot;, tech_pvt-&gt;callid_number);
+                                }
+
+                                DEBUGA_GSMOPEN(&quot;|%s| CLIP INCOMING CALLID: NOW name is %s, number is %s\n&quot;, GSMOPEN_P_LOG,
+                                                           tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;callid_name, tech_pvt-&gt;callid_number);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;BUSY&quot;) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_LINEBUSY;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_LINEBUSY\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_BUSY);
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_BUSY);
+                                } else {
+                                        ERRORA(&quot;Why BUSY now?\n&quot;, GSMOPEN_P_LOG);
+                                }
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;NO ANSWER&quot;) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_NOANSWER;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_NOANSWER\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_NO_ANSWER;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                } else {
+                                        ERRORA(&quot;Why NO ANSWER now?\n&quot;, GSMOPEN_P_LOG);
+                                }
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;NO CARRIER&quot;) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_NOCARRIER;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_NOCARRIER\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN) {
+                                        //cicopet
+                                        switch_core_session_t *session = NULL;
+                                        switch_channel_t *channel = NULL;
+
+tech_pvt-&gt;interface_state = GSMOPEN_STATE_DOWN;
+
+                                        session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+                                        if(session){
+                                                channel = switch_core_session_get_channel(session);
+                                                //gsmopen_hangup(tech_pvt);
+                                                switch_core_session_rwunlock(session);
+                                                switch_channel_hangup(channel, 0);
+                                        }
+                                        //
+                                        //tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                        //gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                } else {
+                                        ERRORA(&quot;Why NO CARRIER now?\n&quot;, GSMOPEN_P_LOG);
+                                }
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CBC:&quot;, 5) == 0)) {
+                                int power_supply, battery_strenght, err;
+
+                                power_supply = battery_strenght = 0;
+
+                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][6], &quot;%d,%d&quot;, &amp;power_supply, &amp;battery_strenght);
+                                if (err &lt; 2) {
+                                        DEBUGA_GSMOPEN(&quot;|%s| is not formatted as: |+CBC: xx,yy| now trying  |+CBC:xx,yy|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                        err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][5], &quot;%d,%d&quot;, &amp;power_supply, &amp;battery_strenght);
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CBC: Powered by %s, battery strenght=%d\n&quot;, GSMOPEN_P_LOG,
+                                                                   tech_pvt-&gt;line_array.result[i], power_supply ? &quot;power supply&quot; : &quot;battery&quot;, battery_strenght);
+
+                                }
+
+                                if (err &lt; 2) {
+                                        DEBUGA_GSMOPEN(&quot;|%s| is not formatted as: |+CBC:xx,yy| giving up\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                }
+
+                                else {
+                                        if (option_debug &gt; 1)
+                                                DEBUGA_GSMOPEN(&quot;|%s| +CBC: Powered by %s, battery strenght=%d\n&quot;, GSMOPEN_P_LOG,
+                                                                           tech_pvt-&gt;line_array.result[i], power_supply ? &quot;power supply&quot; : &quot;battery&quot;, battery_strenght);
+                                        if (!power_supply) {
+                                                if (battery_strenght &lt; 10) {
+                                                        ERRORA(&quot;|%s| BATTERY ALMOST EXHAUSTED\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                } else if (battery_strenght &lt; 20) {
+                                                        WARNINGA(&quot;|%s| BATTERY LOW\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                                }
+
+                                        }
+                                }
+
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CSQ:&quot;, 5) == 0)) {
+                                int signal_quality, ber, err;
+
+                                signal_quality = ber = 0;
+
+                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][6], &quot;%d,%d&quot;, &amp;signal_quality, &amp;ber);
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CSQ: Signal Quality: %d, Error Rate=%d\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i], signal_quality, ber);
+                                if (err &lt; 2) {
+                                        ERRORA(&quot;|%s| is not formatted as: |+CSQ: xx,yy|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                } else {
+                                        if (signal_quality &lt; 11 || signal_quality == 99) {
+                                                WARNINGA
+                                                        (&quot;|%s| CELLPHONE GETS ALMOST NO SIGNAL, consider to move it or additional antenna\n&quot;,
+                                                         GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                        } else if (signal_quality &lt; 15) {
+                                                WARNINGA(&quot;|%s| CELLPHONE GETS SIGNAL LOW\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                        }
+
+                                }
+
+                        }
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGW:&quot;, 6) == 0)) {
+                                int err;
+
+                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][7], &quot;%s&quot;, tech_pvt-&gt;at_cmgw);
+                                DEBUGA_GSMOPEN(&quot;|%s| +CMGW: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_cmgw);
+                                if (err &lt; 1) {
+                                        ERRORA(&quot;|%s| is not formatted as: |+CMGW: xxxx|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                }
+
+                        }
+
+                        /* at_call_* are unsolicited messages sent by the modem to signal us about call processing activity and events */
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_call_idle) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_IDLE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        DEBUGA_GSMOPEN(&quot;just received a remote HANGUP\n&quot;, GSMOPEN_P_LOG);
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_NORMAL;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                        DEBUGA_GSMOPEN(&quot;just sent GSMOPEN_CONTROL_HANGUP\n&quot;, GSMOPEN_P_LOG);
+                                }
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_call_incoming) == 0)) {
+
+                                //char list_command[64];
+
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_INCOMING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                if (tech_pvt-&gt;phone_callflow != CALLFLOW_CALL_INCOMING &amp;&amp; tech_pvt-&gt;phone_callflow != CALLFLOW_INCOMING_RING) {
+                                        //mark the time of CALLFLOW_CALL_INCOMING
+                                        gettimeofday(&amp;(tech_pvt-&gt;call_incoming_time), NULL);
+                                        tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_INCOMING;
+                                        DEBUGA_GSMOPEN(&quot;CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec);
+
+                                }
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_call_active) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_ACTIVE;
+                                DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_ACTIVE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                if (tech_pvt-&gt;interface_state == CALLFLOW_CALL_DIALING || tech_pvt-&gt;interface_state == CALLFLOW_STATUS_EARLYMEDIA) {
+                                        DEBUGA_PBX(&quot;just received a remote ANSWER\n&quot;, GSMOPEN_P_LOG);
+                                        if (tech_pvt-&gt;phone_callflow == GSMOPEN_STATE_UP) {
+                                                //gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_RINGING);
+                                                DEBUGA_PBX(&quot;just sent GSMOPEN_CONTROL_RINGING\n&quot;, GSMOPEN_P_LOG);
+                                                DEBUGA_PBX(&quot;going to send GSMOPEN_CONTROL_ANSWER\n&quot;, GSMOPEN_P_LOG);
+                                                //gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_ANSWER);
+                                                tech_pvt-&gt;interface_state = CALLFLOW_CALL_REMOTEANSWER;
+                                                DEBUGA_PBX(&quot;just sent GSMOPEN_CONTROL_ANSWER\n&quot;, GSMOPEN_P_LOG);
+                                        }
+                                } else {
+                                }
+                                //tech_pvt-&gt;interface_state = GSMOPEN_STATE_UP;
+                                //DEBUGA_PBX(&quot;just interface_state UP\n&quot;, GSMOPEN_P_LOG);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_call_calling) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_DIALING;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_DIALING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_call_failed) == 0)) {
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_FAILED;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_FAILED\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                }
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CSCA:&quot;, 6) == 0)) {        //TODO SMS FIXME in config!
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CSCA: Message Center Address!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGF:&quot;, 6) == 0)) {        //TODO SMS FIXME in config!
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGF: Message Format!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMTI:&quot;, 6) == 0)) {        //TODO SMS FIXME in config!
+                                int err;
+                                int pos;
+
+                                //FIXME all the following commands in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMTI: Incoming SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][12], &quot;%d&quot;, &amp;pos);
+                                if (err &lt; 1) {
+                                        ERRORA(&quot;|%s| is not formatted as: |+CMTI: \&quot;MT\&quot;,xx|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                } else {
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMTI: Incoming SMS in position: %d!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i], pos);
+                                        tech_pvt-&gt;unread_sms_msg_id = pos;
+                                        usleep(1000);
+
+                                        if (tech_pvt-&gt;unread_sms_msg_id) {
+                                                char at_command[256];
+
+                                                if (tech_pvt-&gt;no_ucs2 == 0) {
+                                                        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS=\&quot;UCS2\&quot;&quot;);
+                                                        if (res) {
+                                                                ERRORA(&quot;AT+CSCS=\&quot;UCS2\&quot; (set TE messages to ucs2)  do not got OK from the phone, continuing\n&quot;, GSMOPEN_P_LOG);
+                                                                //memset(tech_pvt-&gt;sms_message, 0, sizeof(tech_pvt-&gt;sms_message));
+                                                        }
+                                                }
+
+                                                memset(at_command, 0, sizeof(at_command));
+                                                sprintf(at_command, &quot;AT+CMGR=%d&quot;, tech_pvt-&gt;unread_sms_msg_id);
+                                                memset(tech_pvt-&gt;sms_message, 0, sizeof(tech_pvt-&gt;sms_message));
+
+                                                tech_pvt-&gt;reading_sms_msg = 1;
+                                                res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
+                                                tech_pvt-&gt;reading_sms_msg = 0;
+                                                if (res) {
+                                                        ERRORA(&quot;AT+CMGR (read SMS) do not got OK from the phone, message sent was:|||%s|||\n&quot;, GSMOPEN_P_LOG, at_command);
+                                                }
+                                                res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS=\&quot;GSM\&quot;&quot;);
+                                                if (res) {
+                                                        ERRORA(&quot;AT+CSCS=\&quot;GSM\&quot; (set TE messages to GSM) do not got OK from the phone\n&quot;, GSMOPEN_P_LOG);
+                                                }
+                                                memset(at_command, 0, sizeof(at_command));
+                                                sprintf(at_command, &quot;AT+CMGD=%d&quot;, tech_pvt-&gt;unread_sms_msg_id);        /* delete the message */
+                                                tech_pvt-&gt;unread_sms_msg_id = 0;
+                                                res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
+                                                if (res) {
+                                                        ERRORA(&quot;AT+CMGD (Delete SMS) do not got OK from the phone, message sent was:|||%s|||\n&quot;, GSMOPEN_P_LOG, at_command);
+                                                }
+
+                                                if (strlen(tech_pvt-&gt;sms_message)) {
+                                                        //FIXME manager_event(EVENT_FLAG_SYSTEM, &quot;GSMOPENincomingsms&quot;,
+                                                        //FIXME &quot;Interface: %s\r\nSMS_Message: %s\r\n&quot;, tech_pvt-&gt;name,
+                                                        //FIXME tech_pvt-&gt;sms_message);
+
+                                                        res=sms_incoming(tech_pvt, tech_pvt-&gt;sms_message);
+
+                                                        if (strlen(tech_pvt-&gt;sms_receiving_program)) {
+                                                                int fd1[2];
+                                                                pid_t pid1;
+                                                                char *arg1[] = { tech_pvt-&gt;sms_receiving_program, (char *) NULL };
+                                                                int i;
+
+                                                                DEBUGA_GSMOPEN(&quot;incoming SMS message:&gt;&gt;&gt;%s&lt;&lt;&lt;\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;sms_message);
+                                                                res=pipe(fd1);
+                                                                pid1 = fork();
+
+                                                                if (pid1 == 0) {        //child
+                                                                        int err;
+
+                                                                        dup2(fd1[0], 0);        // Connect stdin to pipe output
+                                                                        close(fd1[1]);        // close input pipe side
+                                                                        close(tech_pvt-&gt;controldevfd);
+                                                                        setsid();        //session id
+                                                                        err = execvp(arg1[0], arg1);        //exec our program, with stdin connected to pipe output
+                                                                        if (err) {
+                                                                                ERRORA
+                                                                                        (&quot;'sms_receiving_program' is set in config file to '%s', and it gave us back this error: %d, (%s). SMS received was:---%s---\n&quot;,
+                                                                                         GSMOPEN_P_LOG, tech_pvt-&gt;sms_receiving_program, err, strerror(errno), tech_pvt-&gt;sms_message);
+                                                                        }
+                                                                        close(fd1[0]);        // close output pipe side
+                                                                }
+//starting here continue the parent
+                                                                close(fd1[0]);        // close output pipe side
+                                                                // write the msg on the pipe input
+                                                                for (i = 0; i &lt; strlen(tech_pvt-&gt;sms_message); i++) {
+                                                                        res=write(fd1[1], &amp;tech_pvt-&gt;sms_message[i], 1);
+                                                                }
+                                                                close(fd1[1]);        // close pipe input, let our program know we've finished
+                                                        } else {
+                                                                ERRORA
+                                                                        (&quot;got SMS incoming message, but 'sms_receiving_program' is not set in config file. SMS received was:---%s---\n&quot;,
+                                                                         GSMOPEN_P_LOG, tech_pvt-&gt;sms_message);
+                                                        }
+                                                }
+#if 1                                                        //is this one needed? maybe it can interrupt an incoming call that is just to announce itself
+                                                if (tech_pvt-&gt;phone_callflow == CALLFLOW_CALL_IDLE &amp;&amp; tech_pvt-&gt;interface_state == GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner == NULL) {
+                                                        /* we're not in a call, neither calling */
+                                                        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CKPD=\&quot;EEE\&quot;&quot;);
+                                                        if (res) {
+                                                                ERRORA(&quot;AT+CKPD=\&quot;EEE\&quot; (cellphone screen back to user) do not got OK from the phone\n&quot;, GSMOPEN_P_LOG);
+                                                        }
+                                                }
+#endif
+                                        }                        //unread_msg_id
+
+                                }                                //CMTI well formatted
+
+                        }                                        //CMTI
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+MMGL:&quot;, 6) == 0)) {        //TODO MOTOROLA SMS FIXME in config!
+                                int err = 0;
+                                //int unread_msg_id=0;
+
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +MMGL: Listing Motorola SMSs!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][7], &quot;%d&quot;, &amp;tech_pvt-&gt;unread_sms_msg_id);
+                                if (err &lt; 1) {
+                                        ERRORA(&quot;|%s| is not formatted as: |+MMGL: xx|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                }
+                        }
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGL:&quot;, 6) == 0)) {        //TODO  SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGL: Listing SMSs!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+MMGR:&quot;, 6) == 0)) {        //TODO MOTOROLA SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +MMGR: Reading Motorola SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;reading_sms_msg)
+                                        tech_pvt-&gt;reading_sms_msg++;
+                        }
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGR: \&quot;STO U&quot;, 13) == 0)) {        //TODO  SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGR: Reading stored UNSENT SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        } else if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGR: \&quot;STO S&quot;, 13) == 0)) {        //TODO  SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGR: Reading stored SENT SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        } else if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGR: \&quot;REC R&quot;, 13) == 0)) {        //TODO  SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGR: Reading received READ SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        } else if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGR: \&quot;REC U&quot;, 13) == 0)) {        //TODO  SMS FIXME in config!
+                                if (option_debug)
+                                        DEBUGA_GSMOPEN(&quot;|%s| +CMGR: Reading received UNREAD SMS!\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;reading_sms_msg)
+                                        tech_pvt-&gt;reading_sms_msg++;
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;+MCST: 17&quot;) == 0)) {        /* motorola call processing unsolicited messages */
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_INFLUX;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_INFLUX\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;+MCST: 68&quot;) == 0)) {        /* motorola call processing unsolicited messages */
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_NOSERVICE;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_NOSERVICE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                }
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;+MCST: 70&quot;) == 0)) {        /* motorola call processing unsolicited messages */
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_OUTGOINGRESTRICTED;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_OUTGOINGRESTRICTED\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                }
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;+MCST: 72&quot;) == 0)) {        /* motorola call processing unsolicited messages */
+                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_SECURITYFAIL;
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| CALLFLOW_CALL_SECURITYFAIL\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN &amp;&amp; tech_pvt-&gt;owner) {
+                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                }
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CPBR&quot;, 5) == 0)) {        /* phonebook stuff begins */
+
+                                if (tech_pvt-&gt;phonebook_querying) {        /* probably phonebook struct begins */
+                                        int err, first_entry, last_entry, number_lenght, text_lenght;
+
+                                        if (option_debug)
+                                                DEBUGA_GSMOPEN(&quot;phonebook struct: |%s|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                        err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][8], &quot;%d-%d),%d,%d&quot;, &amp;first_entry, &amp;last_entry, &amp;number_lenght, &amp;text_lenght);
+                                        if (err &lt; 4) {
+
+                                                err = sscanf(&amp;tech_pvt-&gt;line_array.result[i][7], &quot;%d-%d,%d,%d&quot;, &amp;first_entry, &amp;last_entry, &amp;number_lenght, &amp;text_lenght);
+                                        }
+
+                                        if (err &lt; 4) {
+                                                ERRORA
+                                                        (&quot;phonebook struct: |%s| is nor formatted as: |+CPBR: (1-750),40,14| neither as: |+CPBR: 1-750,40,14|\n&quot;,
+                                                         GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                        } else {
+
+                                                if (option_debug)
+                                                        DEBUGA_GSMOPEN
+                                                                (&quot;First entry: %d, last entry: %d, phone number max lenght: %d, text max lenght: %d\n&quot;,
+                                                                 GSMOPEN_P_LOG, first_entry, last_entry, number_lenght, text_lenght);
+                                                tech_pvt-&gt;phonebook_first_entry = first_entry;
+                                                tech_pvt-&gt;phonebook_last_entry = last_entry;
+                                                tech_pvt-&gt;phonebook_number_lenght = number_lenght;
+                                                tech_pvt-&gt;phonebook_text_lenght = text_lenght;
+                                        }
+
+                                } else {                /* probably phonebook entry begins */
+
+                                        if (tech_pvt-&gt;phonebook_listing) {
+                                                int err, entry_id, entry_type;
+
+                                                char entry_number[256];
+                                                char entry_text[256];
+
+                                                if (option_debug)
+                                                        DEBUGA_GSMOPEN(&quot;phonebook entry: |%s|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                                err =
+                                                        sscanf(&amp;tech_pvt-&gt;line_array.result[i][7], &quot;%d,\&quot;%255[0-9+]\&quot;,%d,\&quot;%255[^\&quot;]\&quot;&quot;, &amp;entry_id, entry_number, &amp;entry_type, entry_text);
+                                                if (err &lt; 4) {
+                                                        ERRORA
+                                                                (&quot;err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\&quot;+39025458068\&quot;,145,\&quot;ciao a tutti\&quot;|\n&quot;,
+                                                                 GSMOPEN_P_LOG, err, tech_pvt-&gt;line_array.result[i]);
+                                                } else {
+                                                        //TODO: sanitize entry_text
+                                                        if (option_debug)
+                                                                DEBUGA_GSMOPEN(&quot;Number: %s, Text: %s, Type: %d\n&quot;, GSMOPEN_P_LOG, entry_number, entry_text, entry_type);
+                                                        /* write entry in phonebook file */
+                                                        if (tech_pvt-&gt;phonebook_writing_fp) {
+                                                                gsmopen_dir_entry_extension++;
+
+                                                                fprintf(tech_pvt-&gt;phonebook_writing_fp,
+                                                                                &quot;%s  =&gt; ,%sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n&quot;,
+                                                                                entry_number, entry_text, &quot;no&quot;,
+                                                                                tech_pvt-&gt;gsmopen_dir_entry_extension_prefix, &quot;2&quot;, gsmopen_dir_entry_extension, &quot;yes&quot;, &quot;not_specified&quot;);
+                                                                fprintf(tech_pvt-&gt;phonebook_writing_fp,
+                                                                                &quot;%s  =&gt; ,%sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n&quot;,
+                                                                                entry_number, entry_text, &quot;no&quot;,
+                                                                                tech_pvt-&gt;gsmopen_dir_entry_extension_prefix, &quot;3&quot;, gsmopen_dir_entry_extension, &quot;yes&quot;, &quot;not_specified&quot;);
+                                                        }
+                                                }
+
+                                        }
+
+                                        if (tech_pvt-&gt;phonebook_listing_received_calls) {
+                                                int err, entry_id, entry_type;
+
+                                                char entry_number[256] = &quot;&quot;;
+                                                char entry_text[256] = &quot;&quot;;
+
+                                                if (option_debug)
+                                                        DEBUGA_GSMOPEN(&quot;phonebook entry: |%s|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                                err =
+                                                        sscanf(&amp;tech_pvt-&gt;line_array.result[i][7], &quot;%d,\&quot;%255[0-9+]\&quot;,%d,\&quot;%255[^\&quot;]\&quot;&quot;, &amp;entry_id, entry_number, &amp;entry_type, entry_text);
+                                                if (err &lt; 1) {        //we match only on the progressive id, maybe the remote party has not sent its number, and/or there is no corresponding text entry in the phone directory
+                                                        ERRORA
+                                                                (&quot;err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\&quot;+39025458068\&quot;,145,\&quot;ciao a tutti\&quot;|\n&quot;,
+                                                                 GSMOPEN_P_LOG, err, tech_pvt-&gt;line_array.result[i]);
+                                                } else {
+                                                        //TODO: sanitize entry_text
+
+                                                        if (option_debug)
+                                                                DEBUGA_GSMOPEN(&quot;Number: %s, Text: %s, Type: %d\n&quot;, GSMOPEN_P_LOG, entry_number, entry_text, entry_type);
+                                                        memset(tech_pvt-&gt;callid_name, 0, sizeof(tech_pvt-&gt;callid_name));
+                                                        memset(tech_pvt-&gt;callid_number, 0, sizeof(tech_pvt-&gt;callid_number));
+                                                        strncpy(tech_pvt-&gt;callid_name, entry_text, sizeof(tech_pvt-&gt;callid_name));
+                                                        strncpy(tech_pvt-&gt;callid_number, entry_number, sizeof(tech_pvt-&gt;callid_number));
+                                                        if (option_debug)
+                                                                DEBUGA_GSMOPEN(&quot;incoming callid: Text: %s, Number: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;callid_name, tech_pvt-&gt;callid_number);
+
+                                                        DEBUGA_GSMOPEN(&quot;|%s| CPBR INCOMING CALLID: name is %s, number is %s\n&quot;,
+                                                                                   GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i],
+                                                                                   tech_pvt-&gt;callid_name[0] != 1 ? tech_pvt-&gt;callid_name : &quot;not available&quot;,
+                                                                                   tech_pvt-&gt;callid_number[0] ? tech_pvt-&gt;callid_number : &quot;not available&quot;);
+
+                                                        /* mark the time of RING */
+                                                        gettimeofday(&amp;(tech_pvt-&gt;ringtime), NULL);
+                                                        tech_pvt-&gt;interface_state = GSMOPEN_STATE_RING;
+                                                        tech_pvt-&gt;phone_callflow = CALLFLOW_INCOMING_RING;
+
+                                                }
+
+                                        }
+
+                                        else {
+                                                DEBUGA_GSMOPEN(&quot;phonebook entry: |%s|\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+
+                                        }
+                                }
+
+                        }
+
+                        if ((strncmp(tech_pvt-&gt;line_array.result[i], &quot;*ECAV&quot;, 5) == 0) || (strncmp(tech_pvt-&gt;line_array.result[i], &quot;*ECAM&quot;, 5) == 0)) {        /* sony-ericsson call processing unsolicited messages */
+                                int res, ccid, ccstatus, calltype, processid, exitcause, number, type;
+                                res = ccid = ccstatus = calltype = processid = exitcause = number = type = 0;
+                                res = sscanf(&amp;tech_pvt-&gt;line_array.result[i][6], &quot;%d,%d,%d,%d,%d,%d,%d&quot;, &amp;ccid, &amp;ccstatus, &amp;calltype, &amp;processid, &amp;exitcause, &amp;number, &amp;type);
+                                /* only changes the phone_callflow if enought parameters were parsed */
+                                if (res &gt;= 3) {
+                                        switch (ccstatus) {
+                                        case 0:
+                                                if (tech_pvt-&gt;owner) {
+                                                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_DOWN);
+                                                        tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_NORMAL;
+                                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                                }
+                                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+                                                tech_pvt-&gt;interface_state = GSMOPEN_STATE_DOWN;
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: IDLE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 1:
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: CALLING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 2:
+                                                if (tech_pvt-&gt;owner) {
+                                                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_DIALING);
+                                                }
+                                                tech_pvt-&gt;interface_state = CALLFLOW_CALL_DIALING;
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: CONNECTING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 3:
+                                                if (tech_pvt-&gt;owner) {
+                                                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_UP);
+                                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_ANSWER);
+                                                }
+                                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_ACTIVE;
+                                                tech_pvt-&gt;interface_state = GSMOPEN_STATE_UP;
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: ACTIVE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 4:
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN
+                                                                (&quot;|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle HOLD event\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 5:
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN
+                                                                (&quot;|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle WAITING event\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 6:
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN
+                                                                (&quot;|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle ALERTING event\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        case 7:
+                                                if (tech_pvt-&gt;owner) {
+                                                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_BUSY);
+                                                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_BUSY);
+                                                }
+                                                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_LINEBUSY;
+                                                tech_pvt-&gt;interface_state = GSMOPEN_STATE_BUSY;
+                                                if (option_debug &gt; 1)
+                                                        DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: BUSY\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                                break;
+                                        }
+                                } else {
+                                        if (option_debug &gt; 1)
+                                                DEBUGA_GSMOPEN(&quot;|%s| Sony-Ericsson *ECAM/*ECAV: could not parse parameters\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                }
+
+                        }
+
+                        /* at_indicator_* are unsolicited messages sent by the phone to signal us that some of its visual indicators on its screen has changed, based on CIND CMER ETSI docs */
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_noservice_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        ERRORA(&quot;|%s| at_indicator_noservice_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_nosignal_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        ERRORA(&quot;|%s| at_indicator_nosignal_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_lowsignal_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        WARNINGA(&quot;|%s| at_indicator_lowsignal_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_lowbattchg_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        WARNINGA(&quot;|%s| at_indicator_lowbattchg_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_nobattchg_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        ERRORA(&quot;|%s| at_indicator_nobattchg_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_callactive_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_callactive_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_nocallactive_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_nocallactive_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_nocallsetup_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_nocallsetup_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_callsetupincoming_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_callsetupincoming_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_callsetupoutgoing_string) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_callsetupoutgoing_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], tech_pvt-&gt;at_indicator_callsetupremoteringing_string)
+                                 == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;|%s| at_indicator_callsetupremoteringing_string\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                        }
+
+                }
+
+                /* let's look for OK, ERROR and EXPECTED_STRING in the complete lines read so far, without re-looking at the lines that has been yet looked at */
+                for (i = la_read; i &lt; la_counter; i++) {
+                        if (expected_string) {
+                                if ((strncmp(tech_pvt-&gt;line_array.result[i], expected_string, strlen(expected_string))
+                                         == 0)) {
+                                        if (option_debug &gt; 1)
+                                                DEBUGA_GSMOPEN(&quot;|%s| got what EXPECTED\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;line_array.result[i]);
+                                        at_ack = AT_OK;
+                                }
+                        } else {
+                                if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;OK&quot;) == 0)) {
+                                        if (option_debug &gt; 1)
+                                                DEBUGA_GSMOPEN(&quot;got OK\n&quot;, GSMOPEN_P_LOG);
+                                        at_ack = AT_OK;
+                                }
+                        }
+                        if ((strcmp(tech_pvt-&gt;line_array.result[i], &quot;ERROR&quot;) == 0)) {
+                                if (option_debug &gt; 1)
+                                        DEBUGA_GSMOPEN(&quot;got ERROR\n&quot;, GSMOPEN_P_LOG);
+                                at_ack = AT_ERROR;
+                        }
+
+                        /* if we are reading an sms message from memory, put the line into the sms buffer if the line is not &quot;OK&quot; or &quot;ERROR&quot; */
+                        if (tech_pvt-&gt;reading_sms_msg &gt; 1 &amp;&amp; at_ack == -1) {
+                                int c;
+                                char sms_body[16000];
+                                int err=0;
+
+                                if (strncmp(tech_pvt-&gt;line_array.result[i], &quot;+CMGR&quot;, 5) == 0) {        /* we are reading the &quot;header&quot; of an SMS */
+                                        char content[512];
+                                        char content2[512];
+
+                                        memset(content, '\0', sizeof(content));
+
+                                        int inside_comma = 0;
+                                        int inside_quote = 0;
+                                        int which_field = 0;
+                                        int d = 0;
+
+                                        for (c = 0; c &lt; strlen(tech_pvt-&gt;line_array.result[i]); c++) {
+                                                if (tech_pvt-&gt;line_array.result[i][c] == ',' &amp;&amp; tech_pvt-&gt;line_array.result[i][c - 1] != '\\' &amp;&amp; inside_quote == 0) {
+                                                        if (inside_comma) {
+                                                                inside_comma = 0;
+                                                                //NOTICA(&quot;inside_comma=%d, inside_quote=%d, we're at=%s\n&quot;, GSMOPEN_P_LOG, inside_comma, inside_quote, &amp;tech_pvt-&gt;line_array.result[i][c]);
+                                                        } else {
+                                                                inside_comma = 1;
+                                                                //NOTICA(&quot;inside_comma=%d, inside_quote=%d, we're at=%s\n&quot;, GSMOPEN_P_LOG, inside_comma, inside_quote, &amp;tech_pvt-&gt;line_array.result[i][c]);
+                                                        }
+                                                }
+                                                if (tech_pvt-&gt;line_array.result[i][c] == '&quot;' &amp;&amp; tech_pvt-&gt;line_array.result[i][c - 1] != '\\') {
+                                                        if (inside_quote) {
+                                                                inside_quote = 0;
+                                                                //ERRORA(&quot;END_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n&quot;, GSMOPEN_P_LOG, inside_comma, inside_quote, &amp;tech_pvt-&gt;line_array.result[i][c]);
+                                                                DEBUGA_GSMOPEN(&quot;%d content=%s\n&quot;, GSMOPEN_P_LOG, which_field, content);
+
+                                                                strncat(tech_pvt-&gt;sms_message, &quot;---&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                                                strncat(tech_pvt-&gt;sms_message, content, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                                                strncat(tech_pvt-&gt;sms_message, &quot;|||&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+
+                                                                memset(content2, '\0', sizeof(content2));
+                                                                if(which_field==1){
+                                                                        err = ucs2_to_utf8(tech_pvt, content, content2, sizeof(content2));
+                                                                } else {
+                                                                        err=0;
+                                                                        strncpy(content2, content, sizeof(content2));
+                                                                }
+
+                                                                strncat(tech_pvt-&gt;sms_message, &quot;---&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                                                if (!err)
+                                                                        strncat(tech_pvt-&gt;sms_message, content2, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                                                strncat(tech_pvt-&gt;sms_message, &quot;|||&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                                                memset(content, '\0', sizeof(content));
+                                                                d = 0;
+                                                                if(which_field==1){
+                                                                        strncpy(tech_pvt-&gt;sms_sender, content2, sizeof(tech_pvt-&gt;sms_sender));
+
+                                                                } else if(which_field==2){
+                                                                        strncpy(tech_pvt-&gt;sms_date, content2, sizeof(tech_pvt-&gt;sms_date));
+                                                                } else if(which_field &gt; 2){
+                                                                WARNINGA(&quot;WHY which_field is &gt; 2 ? (which_field is %d)\n&quot;, GSMOPEN_P_LOG, which_field);
+                                                                }
+                                                                which_field++;
+                                                        } else {
+                                                                inside_quote = 1;
+                                                                //WARNINGA(&quot;START_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n&quot;, GSMOPEN_P_LOG, inside_comma, inside_quote, &amp;tech_pvt-&gt;line_array.result[i][c]);
+                                                        }
+                                                }
+                                                if (inside_quote &amp;&amp; tech_pvt-&gt;line_array.result[i][c] != '&quot;') {
+
+                                                        content[d] = tech_pvt-&gt;line_array.result[i][c];
+                                                        d++;
+
+                                                }
+
+                                        }
+                                }                                //it was the +CMGR answer from the cellphone
+                                else {
+                                        DEBUGA_GSMOPEN(&quot;body=%s\n&quot;, GSMOPEN_P_LOG, sms_body);
+                                        strncat(tech_pvt-&gt;sms_message, &quot;---&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                        strncat(tech_pvt-&gt;sms_message, tech_pvt-&gt;line_array.result[i], ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                        strncat(tech_pvt-&gt;sms_message, &quot;|||&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+
+                                        memset(sms_body, '\0', sizeof(sms_body));
+                                        err = ucs2_to_utf8(tech_pvt, tech_pvt-&gt;line_array.result[i], sms_body, sizeof(sms_body));
+                                        DEBUGA_GSMOPEN(&quot;body=%s\n&quot;, GSMOPEN_P_LOG, sms_body);
+                                        strncpy(tech_pvt-&gt;sms_body, sms_body, sizeof(tech_pvt-&gt;sms_body));
+
+                                        strncat(tech_pvt-&gt;sms_message, &quot;---&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                        if (!err)
+                                                strncat(tech_pvt-&gt;sms_message, sms_body, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+                                        strncat(tech_pvt-&gt;sms_message, &quot;|||&quot;, ((sizeof(tech_pvt-&gt;sms_message) - strlen(tech_pvt-&gt;sms_message)) - 1));
+
+                                        DEBUGA_GSMOPEN(&quot;sms_message=%s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;sms_message);
+                                }                                //it was the UCS2 from cellphone
+
+                        }                                        //we were reading the SMS
+
+                }
+
+                la_read = la_counter;
+
+                if (look_for_ack &amp;&amp; at_ack &gt; -1)
+                        break;
+
+                if (la_counter &gt; AT_MESG_MAX_LINES) {
+                        ERRORA(&quot;Too many lines in result (&gt;%d). Stopping reader.\n&quot;, GSMOPEN_P_LOG, AT_MESG_MAX_LINES);
+                        at_ack = AT_ERROR;
+                        break;
+                }
+        }
+
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        if (select_err == -1) {
+                ERRORA(&quot;select returned -1 on %s, setting controldev_dead, error was: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;controldevice_name, strerror(errno));
+                tech_pvt-&gt;controldev_dead = 1;
+                close(tech_pvt-&gt;controldevfd);
+                if (tech_pvt-&gt;owner)
+                        gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                return -1;
+        }
+
+        if (tech_pvt-&gt;phone_callflow == CALLFLOW_CALL_INCOMING &amp;&amp; tech_pvt-&gt;call_incoming_time.tv_sec) {        //after three sec of CALLFLOW_CALL_INCOMING, we assume the phone is incapable of notifying RING (eg: motorola c350), so we try to answer
+                char list_command[64];
+                struct timeval call_incoming_timeout;
+                gettimeofday(&amp;call_incoming_timeout, NULL);
+                call_incoming_timeout.tv_sec -= 3;
+                DEBUGA_GSMOPEN
+                        (&quot;CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n&quot;,
+                         GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
+                if (call_incoming_timeout.tv_sec &gt; tech_pvt-&gt;call_incoming_time.tv_sec) {
+
+                        tech_pvt-&gt;call_incoming_time.tv_sec = 0;
+                        tech_pvt-&gt;call_incoming_time.tv_usec = 0;
+                        DEBUGA_GSMOPEN
+                                (&quot;CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
+                        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CPBS=RC&quot;);
+                        if (res) {
+                                ERRORA(&quot;AT+CPBS=RC (select memory of received calls) was not answered by the phone\n&quot;, GSMOPEN_P_LOG);
+                        }
+                        tech_pvt-&gt;phonebook_querying = 1;
+                        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CPBR=?&quot;);
+                        if (res) {
+                                ERRORA(&quot;AT+CPBS=RC (select memory of received calls) was not answered by the phone\n&quot;, GSMOPEN_P_LOG);
+                        }
+                        tech_pvt-&gt;phonebook_querying = 0;
+                        sprintf(list_command, &quot;AT+CPBR=%d,%d&quot;, tech_pvt-&gt;phonebook_first_entry, tech_pvt-&gt;phonebook_last_entry);
+                        tech_pvt-&gt;phonebook_listing_received_calls = 1;
+                        res = gsmopen_serial_write_AT_expect_longtime(tech_pvt, list_command, &quot;OK&quot;);
+                        if (res) {
+                                WARNINGA(&quot;AT+CPBR=%d,%d failed, continue\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;phonebook_first_entry, tech_pvt-&gt;phonebook_last_entry);
+                        }
+                        tech_pvt-&gt;phonebook_listing_received_calls = 0;
+                }
+        }
+
+        if (tech_pvt-&gt;phone_callflow == CALLFLOW_INCOMING_RING) {
+                struct timeval call_incoming_timeout;
+                gettimeofday(&amp;call_incoming_timeout, NULL);
+                call_incoming_timeout.tv_sec -= 10;
+                DEBUGA_GSMOPEN
+                        (&quot;CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n&quot;,
+                         GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
+                if (call_incoming_timeout.tv_sec &gt; tech_pvt-&gt;ringtime.tv_sec) {
+                        ERRORA(&quot;Ringing stopped and I have not answered. Why?\n&quot;, GSMOPEN_P_LOG);
+                        DEBUGA_GSMOPEN
+                                (&quot;CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
+                        if (tech_pvt-&gt;owner) {
+                                gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_HANGUP);
+                                tech_pvt-&gt;owner-&gt;hangupcause = GSMOPEN_CAUSE_FAILURE;
+                        }
+                }
+        }
+        tech_pvt-&gt;line_array.elemcount = la_counter;
+        //NOTICA (&quot; OUTSIDE this gsmopen_serial_device %s \n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;controldevice_name);
+        if (look_for_ack)
+                return at_ack;
+        else
+                return 0;
+}
+
+int gsmopen_serial_write_AT(private_t * tech_pvt, const char *data)
+{
+        int howmany;
+        int i;
+        int res;
+        int count;
+
+        howmany = strlen(data);
+
+        for (i = 0; i &lt; howmany; i++) {
+                res = write(tech_pvt-&gt;controldevfd, &amp;data[i], 1);
+
+                if (res != 1) {
+                        DEBUGA_GSMOPEN(&quot;Error sending (%.1s): %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], res, strerror(errno));
+                        usleep(100000);
+                        for (count = 0; count &lt; 10; count++) {
+                                res = write(tech_pvt-&gt;controldevfd, &amp;data[i], 1);
+                                if (res == 1) {
+                                        DEBUGA_GSMOPEN(&quot;Successfully RE-sent (%.1s): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], count, res, strerror(errno));
+                                        break;
+                                } else
+                                        DEBUGA_GSMOPEN(&quot;Error RE-sending (%.1s): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], count, res, strerror(errno));
+                                usleep(100000);
+
+                        }
+                        if (res != 1) {
+                                ERRORA(&quot;Error RE-sending (%.1s): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], count, res, strerror(errno));
+                                return -1;
+                        }
+                }
+                if (option_debug &gt; 1)
+                        DEBUGA_GSMOPEN(&quot;sent data... (%.1s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i]);
+                usleep(1000);                        /* release the cpu */
+        }
+
+        res = write(tech_pvt-&gt;controldevfd, &quot;\r&quot;, 1);
+
+        if (res != 1) {
+                DEBUGA_GSMOPEN(&quot;Error sending (carriage return): %d (%s)\n&quot;, GSMOPEN_P_LOG, res, strerror(errno));
+                usleep(100000);
+                for (count = 0; count &lt; 10; count++) {
+                        res = write(tech_pvt-&gt;controldevfd, &quot;\r&quot;, 1);
+
+                        if (res == 1) {
+                                DEBUGA_GSMOPEN(&quot;Successfully RE-sent carriage return: %d %d (%s)\n&quot;, GSMOPEN_P_LOG, count, res, strerror(errno));
+                                break;
+                        } else
+                                DEBUGA_GSMOPEN(&quot;Error RE-sending (carriage return): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, count, res, strerror(errno));
+                        usleep(100000);
+
+                }
+                if (res != 1) {
+                        ERRORA(&quot;Error RE-sending (carriage return): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, count, res, strerror(errno));
+                        return -1;
+                }
+        }
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;sent (carriage return)\n&quot;, GSMOPEN_P_LOG);
+        usleep(1000);                                /* release the cpu */
+
+        return howmany;
+}
+
+int gsmopen_serial_write_AT_nocr(private_t * tech_pvt, const char *data)
+{
+        int howmany;
+        int i;
+        int res;
+        int count;
+
+        howmany = strlen(data);
+
+        for (i = 0; i &lt; howmany; i++) {
+                res = write(tech_pvt-&gt;controldevfd, &amp;data[i], 1);
+
+                if (res != 1) {
+                        DEBUGA_GSMOPEN(&quot;Error sending (%.1s): %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], res, strerror(errno));
+                        usleep(100000);
+                        for (count = 0; count &lt; 10; count++) {
+                                res = write(tech_pvt-&gt;controldevfd, &amp;data[i], 1);
+                                if (res == 1)
+                                        break;
+                                else
+                                        DEBUGA_GSMOPEN(&quot;Error RE-sending (%.1s): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], count, res, strerror(errno));
+                                usleep(100000);
+
+                        }
+                        if (res != 1) {
+                                ERRORA(&quot;Error RE-sending (%.1s): %d %d (%s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i], count, res, strerror(errno));
+                                return -1;
+                        }
+                }
+                if (option_debug &gt; 1)
+                        DEBUGA_GSMOPEN(&quot;sent data... (%.1s)\n&quot;, GSMOPEN_P_LOG, &amp;data[i]);
+                usleep(1000);                        /* release the cpu */
+        }
+
+        usleep(1000);                                /* release the cpu */
+
+        return howmany;
+}
+
+int gsmopen_serial_write_AT_noack(private_t * tech_pvt, const char *data)
+{
+
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;gsmopen_serial_write_AT_noack: %s\n&quot;, GSMOPEN_P_LOG, data);
+
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+        if (gsmopen_serial_write_AT(tech_pvt, data) != strlen(data)) {
+
+                ERRORA(&quot;Error sending data... (%s)\n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                UNLOCKA(tech_pvt-&gt;controldev_lock);
+                return -1;
+        }
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+
+        return 0;
+}
+
+int gsmopen_serial_write_AT_ack(private_t * tech_pvt, const char *data)
+{
+        int at_result = AT_ERROR;
+
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;sending: %s\n&quot;, GSMOPEN_P_LOG, data);
+        if (gsmopen_serial_write_AT(tech_pvt, data) != strlen(data)) {
+                ERRORA(&quot;Error sending data... (%s) \n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                UNLOCKA(tech_pvt-&gt;controldev_lock);
+                return -1;
+        }
+
+        at_result = gsmopen_serial_read_AT(tech_pvt, 1, 500000, 2, NULL, 1);        // 2.5 sec timeout
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+
+        return at_result;
+
+}
+
+int gsmopen_serial_write_AT_ack_nocr_longtime(private_t * tech_pvt, const char *data)
+{
+        int at_result = AT_ERROR;
+
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;sending: %s\n&quot;, GSMOPEN_P_LOG, data);
+        if (gsmopen_serial_write_AT_nocr(tech_pvt, data) != strlen(data)) {
+                ERRORA(&quot;Error sending data... (%s) \n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                UNLOCKA(tech_pvt-&gt;controldev_lock);
+                return -1;
+        }
+
+        at_result = gsmopen_serial_read_AT(tech_pvt, 1, 500000, 20, NULL, 1);        // 20.5 sec timeout
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+
+        return at_result;
+
+}
+
+int gsmopen_serial_write_AT_expect1(private_t * tech_pvt, const char *data, const char *expected_string, int expect_crlf, int seconds)
+{
+        int at_result = AT_ERROR;
+
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;sending: %s, expecting: %s\n&quot;, GSMOPEN_P_LOG, data, expected_string);
+        if (gsmopen_serial_write_AT(tech_pvt, data) != strlen(data)) {
+                ERRORA(&quot;Error sending data... (%s) \n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                UNLOCKA(tech_pvt-&gt;controldev_lock);
+                return -1;
+        }
+
+        at_result = gsmopen_serial_read_AT(tech_pvt, 1, 500000, seconds, expected_string, expect_crlf);        // 20.5 sec timeout, used for querying the SIM and sending SMSs
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+
+        return at_result;
+
+}
+
+int gsmopen_serial_AT_expect(private_t * tech_pvt, const char *expected_string, int expect_crlf, int seconds)
+{
+        int at_result = AT_ERROR;
+
+        PUSHA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+        LOKKA(tech_pvt-&gt;controldev_lock);
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;expecting: %s\n&quot;, GSMOPEN_P_LOG, expected_string);
+
+        at_result = gsmopen_serial_read_AT(tech_pvt, 1, 500000, seconds, expected_string, expect_crlf);        // 20.5 sec timeout, used for querying the SIM and sending SMSs
+        UNLOCKA(tech_pvt-&gt;controldev_lock);
+        POPPA_UNLOCKA(tech_pvt-&gt;controldev_lock);
+
+        return at_result;
+
+}
+
+int gsmopen_serial_answer(private_t * tech_pvt)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_answer_AT(tech_pvt);
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_answer_FBUS2(tech_pvt);
+#endif /* GSMOPEN_FBUS2 */
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_answer_CVM_BUSMAIL(tech_pvt);
+#endif /* GSMOPEN_CVM */
+        return -1;
+}
+
+
+int gsmopen_serial_answer_AT(private_t * tech_pvt)
+{
+        int res;
+
+        res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_answer, tech_pvt-&gt;at_answer_expect);
+        if (res) {
+                DEBUGA_GSMOPEN
+                        (&quot;at_answer command failed, command used: %s, expecting: %s, trying with AT+CKPD=\&quot;S\&quot;\n&quot;,
+                         GSMOPEN_P_LOG, tech_pvt-&gt;at_answer, tech_pvt-&gt;at_answer_expect);
+
+                res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CKPD=\&quot;S\&quot;&quot;);
+                if (res) {
+                        ERRORA(&quot;at_answer command failed, command used: 'AT+CKPD=\&quot;S\&quot;', giving up\n&quot;, GSMOPEN_P_LOG);
+                        return -1;
+                }
+        }
+        //tech_pvt-&gt;interface_state = GSMOPEN_STATE_UP;
+        //tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_ACTIVE;
+        DEBUGA_GSMOPEN(&quot;AT: call answered\n&quot;, GSMOPEN_P_LOG);
+        return 0;
+}
+
+int gsmopen_serial_hangup(private_t * tech_pvt)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_hangup_AT(tech_pvt);
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_hangup_FBUS2(tech_pvt);
+#endif /* GSMOPEN_FBUS2 */
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_hangup_CVM_BUSMAIL(tech_pvt);
+#endif /* GSMOPEN_CVM */
+        return -1;
+}
+
+
+int gsmopen_serial_hangup_AT(private_t * tech_pvt)
+{
+        int res;
+
+        if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN) {
+                res = gsmopen_serial_write_AT_expect(tech_pvt, tech_pvt-&gt;at_hangup, tech_pvt-&gt;at_hangup_expect);
+                if (res) {
+                        DEBUGA_GSMOPEN(&quot;at_hangup command failed, command used: %s, trying to use AT+CKPD=\&quot;EEE\&quot;\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_hangup);
+                        res = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CKPD=\&quot;EEE\&quot;&quot;);
+                        if (res) {
+                                ERRORA(&quot;at_hangup command failed, command used: 'AT+CKPD=\&quot;EEE\&quot;'\n&quot;, GSMOPEN_P_LOG);
+                                return -1;
+                        }
+                }
+        }
+        tech_pvt-&gt;interface_state = GSMOPEN_STATE_DOWN;
+        tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+        return 0;
+}
+
+
+int gsmopen_serial_call(private_t * tech_pvt, char *dstr)
+{
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT)
+                return gsmopen_serial_call_AT(tech_pvt, dstr);
+#ifdef GSMOPEN_FBUS2
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_FBUS2)
+                return gsmopen_serial_call_FBUS2(tech_pvt, dstr);
+#endif /* GSMOPEN_FBUS2 */
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_NO_SERIAL)
+                return 0;
+#ifdef GSMOPEN_CVM
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_CVM_BUSMAIL)
+                return gsmopen_serial_call_CVM_BUSMAIL(tech_pvt, dstr);
+#endif /* GSMOPEN_CVM */
+        return -1;
+}
+
+int gsmopen_serial_call_AT(private_t * tech_pvt, char *dstr)
+{
+        int res;
+        char at_command[256];
+
+        if (option_debug)
+                DEBUGA_PBX(&quot;Dialing %s\n&quot;, GSMOPEN_P_LOG, dstr);
+        memset(at_command, 0, sizeof(at_command));
+        tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_DIALING;
+        tech_pvt-&gt;interface_state = GSMOPEN_STATE_DIALING;
+        //ast_uri_decode(dstr);
+/*
+  size_t fixdstr = strspn(dstr, AST_DIGIT_ANYDIG);
+  if (fixdstr == 0) {
+    ERRORA(&quot;dial command failed because of invalid dial number. dial string was: %s\n&quot;,
+           GSMOPEN_P_LOG, dstr);
+    return -1;
+  }
+*/
+        //dstr[fixdstr] = '\0';
+        sprintf(at_command, &quot;%s%s%s&quot;, tech_pvt-&gt;at_dial_pre_number, dstr, tech_pvt-&gt;at_dial_post_number);
+        DEBUGA_PBX(&quot;Dialstring %s\n&quot;, GSMOPEN_P_LOG, at_command);
+        res = gsmopen_serial_write_AT_expect(tech_pvt, at_command, tech_pvt-&gt;at_dial_expect);
+        if (res) {
+                ERRORA(&quot;dial command failed, dial string was: %s\n&quot;, GSMOPEN_P_LOG, at_command);
+                return -1;
+        }
+        // jet - early audio
+        //if (tech_pvt-&gt;at_early_audio) {
+        //ast_queue_control(tech_pvt-&gt;owner, AST_CONTROL_ANSWER);
+        //}
+
+        return 0;
+}
+
+int ucs2_to_utf8(private_t * tech_pvt, char *ucs2_in, char *utf8_out, size_t outbytesleft)
+{
+        char converted[16000];
+        iconv_t iconv_format;
+        int iconv_res;
+        char *outbuf;
+        char *inbuf;
+        size_t inbytesleft;
+        int c;
+        char stringa[5];
+        double hexnum;
+        int i = 0;
+
+        memset(converted, '\0', sizeof(converted));
+
+        DEBUGA_GSMOPEN(&quot;ucs2_in=%s\n&quot;, GSMOPEN_P_LOG, ucs2_in);
+        /* cicopet */
+        for (c = 0; c &lt; strlen(ucs2_in); c++) {
+                sprintf(stringa, &quot;0x%c%c&quot;, ucs2_in[c], ucs2_in[c + 1]);
+                c++;
+                hexnum = strtod(stringa, NULL);
+                converted[i] = hexnum;
+                i++;
+        }
+
+        outbuf = utf8_out;
+        inbuf = converted;
+
+        iconv_format = iconv_open(&quot;UTF8&quot;, &quot;UCS-2BE&quot;);
+        if (iconv_format == (iconv_t) - 1) {
+                ERRORA(&quot;error: %s\n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                return -1;
+        }
+
+        inbytesleft = i;
+        iconv_res = iconv(iconv_format, &amp;inbuf, &amp;inbytesleft, &amp;outbuf, &amp;outbytesleft);
+        if (iconv_res == (size_t) -1) {
+                DEBUGA_GSMOPEN(&quot;ciao in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n&quot;,
+                                           GSMOPEN_P_LOG, inbuf, (int) inbytesleft, outbuf, (int) outbytesleft, converted, utf8_out);
+                DEBUGA_GSMOPEN(&quot;error: %s %d\n&quot;, GSMOPEN_P_LOG, strerror(errno), errno);
+                return -1;
+        }
+        DEBUGA_GSMOPEN
+                (&quot;iconv_res=%d,  in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n&quot;,
+                 GSMOPEN_P_LOG, iconv_res, inbuf, (int) inbytesleft, outbuf, (int) outbytesleft, converted, utf8_out);
+        iconv_close(iconv_format);
+
+        return 0;
+}
+
+int utf_to_ucs2(private_t * tech_pvt, char *utf_in, size_t inbytesleft, char *ucs2_out, size_t outbytesleft)
+{
+        /* cicopet */
+        iconv_t iconv_format;
+        int iconv_res;
+        char *outbuf;
+        char *inbuf;
+        char converted[16000];
+        int i;
+        char stringa[16];
+        char stringa2[16];
+
+        memset(converted, '\0', sizeof(converted));
+
+        outbuf = converted;
+        inbuf = utf_in;
+
+        iconv_format = iconv_open(&quot;UCS-2BE&quot;, &quot;UTF8&quot;);
+        if (iconv_format == (iconv_t) - 1) {
+                ERRORA(&quot;error: %s\n&quot;, GSMOPEN_P_LOG, strerror(errno));
+                return -1;
+        }
+        outbytesleft = 16000;
+
+        DEBUGA_GSMOPEN(&quot;in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n&quot;,
+                                   GSMOPEN_P_LOG, inbuf, (int) inbytesleft, outbuf, (int) outbytesleft, utf_in, converted);
+        iconv_res = iconv(iconv_format, &amp;inbuf, &amp;inbytesleft, &amp;outbuf, &amp;outbytesleft);
+        if (iconv_res == (size_t) -1) {
+                ERRORA(&quot;error: %s %d\n&quot;, GSMOPEN_P_LOG, strerror(errno), errno);
+                return -1;
+        }
+        DEBUGA_GSMOPEN
+                (&quot;iconv_res=%d,  in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n&quot;,
+                 GSMOPEN_P_LOG, iconv_res, inbuf, (int) inbytesleft, outbuf, (int) outbytesleft, utf_in, converted);
+        iconv_close(iconv_format);
+
+        for (i = 0; i &lt; 16000 - outbytesleft; i++) {
+                memset(stringa, '\0', sizeof(stringa));
+                memset(stringa2, '\0', sizeof(stringa2));
+                sprintf(stringa, &quot;%02X&quot;, converted[i]);
+                DEBUGA_GSMOPEN(&quot;character is |%02X|\n&quot;, GSMOPEN_P_LOG, converted[i]);
+                stringa2[0] = stringa[strlen(stringa) - 2];
+                stringa2[1] = stringa[strlen(stringa) - 1];
+                strncat(ucs2_out, stringa2, ((outbytesleft - strlen(ucs2_out)) - 1));        //add the received line to the buffer
+                DEBUGA_GSMOPEN(&quot;stringa=%s, stringa2=%s, ucs2_out=%s\n&quot;, GSMOPEN_P_LOG, stringa, stringa2, ucs2_out);
+        }
+        return 0;
+}
+
+
+/*! \brief  Answer incoming call,
+ * Part of PBX interface */
+int gsmopen_answer(private_t * tech_pvt)
+{
+        int res;
+
+        if (option_debug) {
+                DEBUGA_PBX(&quot;ENTERING FUNC\n&quot;, GSMOPEN_P_LOG);
+        }
+        /* do something to actually answer the call, if needed (eg. pick up the phone) */
+        if (tech_pvt-&gt;controldevprotocol != PROTOCOL_NO_SERIAL) {
+                if (gsmopen_serial_answer(tech_pvt)) {
+                        ERRORA(&quot;gsmopen_answer FAILED\n&quot;, GSMOPEN_P_LOG);
+                        if (option_debug) {
+                                DEBUGA_PBX(&quot;EXITING FUNC\n&quot;, GSMOPEN_P_LOG);
+                        }
+                        return -1;
+                }
+        }
+        tech_pvt-&gt;interface_state = GSMOPEN_STATE_UP;
+        tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_ACTIVE;
+
+        while (tech_pvt-&gt;interface_state == GSMOPEN_STATE_RING) {
+                usleep(10000);                        //10msec
+        }
+        if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_UP) {
+                ERRORA(&quot;call answering failed\n&quot;, GSMOPEN_P_LOG);
+                res = -1;
+        } else {
+                if (option_debug)
+                        DEBUGA_PBX(&quot;call answered\n&quot;, GSMOPEN_P_LOG);
+                res = 0;
+#ifdef GSMOPEN_PORTAUDIO
+                speex_echo_state_reset(tech_pvt-&gt;stream-&gt;echo_state);
+#endif // GSMOPEN_PORTAUDIO
+
+                new_inbound_channel(tech_pvt);
+                if (tech_pvt-&gt;owner) {
+                        DEBUGA_PBX(&quot;going to send GSMOPEN_STATE_UP\n&quot;, GSMOPEN_P_LOG);
+                        ast_setstate(tech_pvt-&gt;owner, GSMOPEN_STATE_UP);
+                        //ast_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_ANSWER);
+                        //gsmopen_queue_control(tech_pvt-&gt;owner, GSMOPEN_CONTROL_ANSWER);
+                        DEBUGA_PBX(&quot;just sent GSMOPEN_STATE_UP\n&quot;, GSMOPEN_P_LOG);
+                }
+        }
+        if (option_debug) {
+                DEBUGA_PBX(&quot;EXITING FUNC\n&quot;, GSMOPEN_P_LOG);
+        }
+        return res;
+}
+int gsmopen_ring(private_t * tech_pvt)
+{
+        int res=0;
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        if (option_debug) {
+                DEBUGA_PBX(&quot;ENTERING FUNC\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        if(session){
+                switch_core_session_rwunlock(session);
+                return 0;
+        }
+
+        new_inbound_channel(tech_pvt);
+
+        usleep(10000);
+
+        session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        if(session){
+                channel = switch_core_session_get_channel(session);
+
+                switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
+                if(channel){
+                        switch_channel_mark_ring_ready(channel);
+                } else {
+                        ERRORA(&quot;no session\n&quot;, GSMOPEN_P_LOG);
+                }
+                switch_core_session_rwunlock(session);
+        } else {
+                ERRORA(&quot;no session\n&quot;, GSMOPEN_P_LOG);
+
+        }
+
+
+        if (option_debug) {
+                DEBUGA_PBX(&quot;EXITING FUNC\n&quot;, GSMOPEN_P_LOG);
+        }
+        return res;
+}
+
+
+/*! \brief  Hangup gsmopen call
+ * Part of PBX interface, called from ast_hangup */
+
+int gsmopen_hangup(private_t * tech_pvt)
+{
+
+        /* if there is not gsmopen pvt why we are here ? */
+        if (!tech_pvt) {
+                ERRORA(&quot;Asked to hangup channel not connected\n&quot;, GSMOPEN_P_LOG);
+                return 0;
+        }
+
+        DEBUGA_GSMOPEN(&quot;ENTERING FUNC\n&quot;, GSMOPEN_P_LOG);
+
+
+        if (tech_pvt-&gt;controldevprotocol != PROTOCOL_NO_SERIAL) {
+                if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN) {
+                        /* actually hangup through the serial port */
+                        if (tech_pvt-&gt;controldevprotocol != PROTOCOL_NO_SERIAL) {
+                                int res;
+                                res = gsmopen_serial_hangup(tech_pvt);
+                                if (res) {
+                                        ERRORA(&quot;gsmopen_serial_hangup error: %d\n&quot;, GSMOPEN_P_LOG, res);
+                                        if (option_debug) {
+                                                DEBUGA_PBX(&quot;EXITING FUNC\n&quot;, GSMOPEN_P_LOG);
+                                        }
+                                        return -1;
+                                }
+                        }
+
+                        while (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN) {
+                                usleep(10000);        //10msec
+                        }
+                        if (tech_pvt-&gt;interface_state != GSMOPEN_STATE_DOWN) {
+                                ERRORA(&quot;call hangup failed\n&quot;, GSMOPEN_P_LOG);
+                                return -1;
+                        } else {
+                                DEBUGA_GSMOPEN(&quot;call hungup\n&quot;, GSMOPEN_P_LOG);
+                        }
+                }
+        } else {
+                tech_pvt-&gt;interface_state = GSMOPEN_STATE_DOWN;
+                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+        }
+
+        switch_set_flag(tech_pvt, TFLAG_HANGUP);
+        if (option_debug) {
+                DEBUGA_PBX(&quot;EXITING FUNC\n&quot;, GSMOPEN_P_LOG);
+        }
+        return 0;
+}
+
+
+
+#define GSMOPEN_ALSA
+#ifdef GSMOPEN_ALSA
+/*! \brief ALSA pcm format, according to endianess  */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+snd_pcm_format_t gsmopen_format = SND_PCM_FORMAT_S16_LE;
+#else
+snd_pcm_format_t gsmopen_format = SND_PCM_FORMAT_S16_BE;
+#endif
+
+/*!
+ * \brief Initialize the ALSA soundcard channels (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces) 
+ * \param p the gsmopen_pvt of the interface
+ *
+ * This function call alsa_open_dev to initialize the ALSA soundcard for each channel (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
+ *
+ * \return zero on success, -1 on error.
+ */
+int alsa_init(private_t * tech_pvt)
+{
+        tech_pvt-&gt;alsac = alsa_open_dev(tech_pvt, SND_PCM_STREAM_CAPTURE);
+        if (!tech_pvt-&gt;alsac) {
+                ERRORA(&quot;Failed opening ALSA capture device: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsacname);
+                if (alsa_shutdown(tech_pvt)) {
+                        ERRORA(&quot;alsa_shutdown failed\n&quot;, GSMOPEN_P_LOG);
+                        return -1;
+                }
+                return -1;
+        }
+        tech_pvt-&gt;alsap = alsa_open_dev(tech_pvt, SND_PCM_STREAM_PLAYBACK);
+        if (!tech_pvt-&gt;alsap) {
+                ERRORA(&quot;Failed opening ALSA playback device: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsapname);
+                if (alsa_shutdown(tech_pvt)) {
+                        ERRORA(&quot;alsa_shutdown failed\n&quot;, GSMOPEN_P_LOG);
+                        return -1;
+                }
+                return -1;
+        }
+
+        /* make valgrind very happy */
+        snd_config_update_free_global();
+        return 0;
+}
+
+/*!
+ * \brief Shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces) 
+ * \param p the gsmopen_pvt of the interface
+ *
+ * This function shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
+ *
+ * \return zero on success, -1 on error.
+ */
+
+int alsa_shutdown(private_t * tech_pvt)
+{
+
+        int err;
+
+        if (tech_pvt-&gt;alsap) {
+                err = snd_pcm_drop(tech_pvt-&gt;alsap);
+                if (err &lt; 0) {
+                        ERRORA(&quot;device [%s], snd_pcm_drop failed with error '%s'\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsapname, snd_strerror(err));
+                        return -1;
+                }
+                err = snd_pcm_close(tech_pvt-&gt;alsap);
+                if (err &lt; 0) {
+                        ERRORA(&quot;device [%s], snd_pcm_close failed with error '%s'\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsapname, snd_strerror(err));
+                        return -1;
+                }
+                tech_pvt-&gt;alsap = NULL;
+        }
+        if (tech_pvt-&gt;alsac) {
+                err = snd_pcm_drop(tech_pvt-&gt;alsac);
+                if (err &lt; 0) {
+                        ERRORA(&quot;device [%s], snd_pcm_drop failed with error '%s'\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsacname, snd_strerror(err));
+                        return -1;
+                }
+                err = snd_pcm_close(tech_pvt-&gt;alsac);
+                if (err &lt; 0) {
+                        ERRORA(&quot;device [%s], snd_pcm_close failed with error '%s'\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;alsacname, snd_strerror(err));
+                        return -1;
+                }
+                tech_pvt-&gt;alsac = NULL;
+        }
+
+        return 0;
+}
+
+/*!
+ * \brief Setup and open the ALSA device (capture OR playback) 
+ * \param p the gsmopen_pvt of the interface
+ * \param stream the ALSA capture/playback definition
+ *
+ * This function setup and open the ALSA device (capture OR playback). Called by alsa_init
+ *
+ * \return zero on success, -1 on error.
+ */
+snd_pcm_t *alsa_open_dev(private_t * tech_pvt, snd_pcm_stream_t stream)
+{
+
+        snd_pcm_t *handle = NULL;
+        snd_pcm_hw_params_t *params;
+        snd_pcm_sw_params_t *swparams;
+        snd_pcm_uframes_t buffer_size;
+        int err;
+        size_t n;
+        //snd_pcm_uframes_t xfer_align;
+        unsigned int rate;
+        snd_pcm_uframes_t start_threshold, stop_threshold;
+        snd_pcm_uframes_t period_size = 0;
+        snd_pcm_uframes_t chunk_size = 0;
+        int start_delay = 0;
+        int stop_delay = 0;
+        snd_pcm_state_t state;
+        snd_pcm_info_t *info;
+
+        period_size = tech_pvt-&gt;alsa_period_size;
+
+        snd_pcm_hw_params_alloca(&amp;params);
+        snd_pcm_sw_params_alloca(&amp;swparams);
+
+        if (stream == SND_PCM_STREAM_CAPTURE) {
+                err = snd_pcm_open(&amp;handle, tech_pvt-&gt;alsacname, stream, 0 | SND_PCM_NONBLOCK);
+        } else {
+                err = snd_pcm_open(&amp;handle, tech_pvt-&gt;alsapname, stream, 0 | SND_PCM_NONBLOCK);
+        }
+        if (err &lt; 0) {
+                ERRORA
+                        (&quot;snd_pcm_open failed with error '%s' on device '%s', if you are using a plughw:n device please change it to be a default:n device (so to allow it to be shared with other concurrent programs), or maybe you are using an ALSA voicemodem and slmodemd&quot;
+                         &quot; is running?\n&quot;, GSMOPEN_P_LOG, snd_strerror(err), stream == SND_PCM_STREAM_CAPTURE ? tech_pvt-&gt;alsacname : tech_pvt-&gt;alsapname);
+                return NULL;
+        }
+
+        snd_pcm_info_alloca(&amp;info);
+
+        if ((err = snd_pcm_info(handle, info)) &lt; 0) {
+                ERRORA(&quot;info error: %s&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        err = snd_pcm_nonblock(handle, 1);
+        if (err &lt; 0) {
+                ERRORA(&quot;nonblock setting error: %s&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        err = snd_pcm_hw_params_any(handle, params);
+        if (err &lt; 0) {
+                ERRORA(&quot;Broken configuration for this PCM, no configurations available: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+        if (err &lt; 0) {
+                ERRORA(&quot;Access type not available: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+        err = snd_pcm_hw_params_set_format(handle, params, gsmopen_format);
+        if (err &lt; 0) {
+                ERRORA(&quot;Sample format non available: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+        err = snd_pcm_hw_params_set_channels(handle, params, 1);
+        if (err &lt; 0) {
+                DEBUGA_GSMOPEN(&quot;Channels count set failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+        }
+#if 1
+        unsigned int chan_num;
+        err = snd_pcm_hw_params_get_channels(params, &amp;chan_num);
+        if (err &lt; 0) {
+                ERRORA(&quot;Channels count non available: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+        if (chan_num &lt; 1 || chan_num &gt; 2) {
+                ERRORA(&quot;Channels count MUST BE 1 or 2, it is: %d\n&quot;, GSMOPEN_P_LOG, chan_num);
+                ERRORA(&quot;Channels count MUST BE 1 or 2, it is: %d on %s %s\n&quot;, GSMOPEN_P_LOG, chan_num, tech_pvt-&gt;alsapname, tech_pvt-&gt;alsacname);
+                return NULL;
+        } else {
+                if (chan_num == 1) {
+                        if (stream == SND_PCM_STREAM_CAPTURE)
+                                tech_pvt-&gt;alsa_capture_is_mono = 1;
+                        else
+                                tech_pvt-&gt;alsa_play_is_mono = 1;
+                } else {
+                        if (stream == SND_PCM_STREAM_CAPTURE)
+                                tech_pvt-&gt;alsa_capture_is_mono = 0;
+                        else
+                                tech_pvt-&gt;alsa_play_is_mono = 0;
+                }
+        }
+#else
+        tech_pvt-&gt;alsa_capture_is_mono = 1;
+        tech_pvt-&gt;alsa_play_is_mono = 1;
+#endif
+
+#if 1
+        rate = tech_pvt-&gt;gsmopen_sound_rate;
+        err = snd_pcm_hw_params_set_rate_near(handle, params, &amp;rate, 0);
+        if ((float) tech_pvt-&gt;gsmopen_sound_rate * 1.05 &lt; rate || (float) tech_pvt-&gt;gsmopen_sound_rate * 0.95 &gt; rate) {
+                WARNINGA(&quot;Rate is not accurate (requested = %iHz, got = %iHz)\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;gsmopen_sound_rate, rate);
+        }
+
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting rate: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+        tech_pvt-&gt;gsmopen_sound_rate = rate;
+
+        err = snd_pcm_hw_params_set_period_size_near(handle, params, &amp;period_size, 0);
+
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting period_size: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        tech_pvt-&gt;alsa_period_size = period_size;
+
+        tech_pvt-&gt;alsa_buffer_size = tech_pvt-&gt;alsa_period_size * tech_pvt-&gt;alsa_periods_in_buffer;
+
+        err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &amp;tech_pvt-&gt;alsa_buffer_size);
+
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting buffer_size: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+#endif
+
+        err = snd_pcm_hw_params(handle, params);
+        if (err &lt; 0) {
+                ERRORA(&quot;Unable to install hw params: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        snd_pcm_hw_params_get_period_size(params, &amp;chunk_size, 0);
+        snd_pcm_hw_params_get_buffer_size(params, &amp;buffer_size);
+        if (chunk_size == buffer_size) {
+                ERRORA(&quot;Can't use period equal to buffer size (%lu == %lu)\n&quot;, GSMOPEN_P_LOG, chunk_size, buffer_size);
+                return NULL;
+        }
+
+        snd_pcm_sw_params_current(handle, swparams);
+
+        /*
+           if (sleep_min)
+           xfer_align = 1;
+           err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
+           0);
+
+           if (err &lt; 0) {
+           ERRORA(&quot;Error setting slep_min: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+           }
+         */
+        n = chunk_size;
+        err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting avail_min: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+        }
+        if (stream == SND_PCM_STREAM_CAPTURE) {
+                start_delay = 1;
+        }
+        if (start_delay &lt;= 0) {
+                start_threshold = n + (double) rate *start_delay / 1000000;
+        } else {
+                start_threshold = (double) rate *start_delay / 1000000;
+        }
+        if (start_threshold &lt; 1)
+                start_threshold = 1;
+        if (start_threshold &gt; n)
+                start_threshold = n;
+        err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting start_threshold: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+        }
+
+        if (stop_delay &lt;= 0)
+                stop_threshold = buffer_size + (double) rate *stop_delay / 1000000;
+        else
+                stop_threshold = (double) rate *stop_delay / 1000000;
+
+        if (stream == SND_PCM_STREAM_CAPTURE) {
+                stop_threshold = -1;
+        }
+
+        err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
+
+        if (err &lt; 0) {
+                ERRORA(&quot;Error setting stop_threshold: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+        }
+
+        if (snd_pcm_sw_params(handle, swparams) &lt; 0) {
+                ERRORA(&quot;Error installing software parameters: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+        }
+
+        err = snd_pcm_poll_descriptors_count(handle);
+        if (err &lt;= 0) {
+                ERRORA(&quot;Unable to get a poll descriptors count, error is %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+
+        if (err != 1) {                                //number of poll descriptors
+                DEBUGA_GSMOPEN(&quot;Can't handle more than one device\n&quot;, GSMOPEN_P_LOG);
+                return NULL;
+        }
+
+        err = snd_pcm_poll_descriptors(handle, &amp;tech_pvt-&gt;pfd, err);
+        if (err != 1) {
+                ERRORA(&quot;snd_pcm_poll_descriptors failed, %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                return NULL;
+        }
+        DEBUGA_GSMOPEN(&quot;Acquired fd %d from the poll descriptor\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;pfd.fd);
+
+        if (stream == SND_PCM_STREAM_CAPTURE) {
+                tech_pvt-&gt;gsmopen_sound_capt_fd = tech_pvt-&gt;pfd.fd;
+        }
+
+        state = snd_pcm_state(handle);
+
+        if (state != SND_PCM_STATE_RUNNING) {
+                if (state != SND_PCM_STATE_PREPARED) {
+                        err = snd_pcm_prepare(handle);
+                        if (err) {
+                                ERRORA(&quot;snd_pcm_prepare failed, %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                                return NULL;
+                        }
+                        DEBUGA_GSMOPEN(&quot;prepared!\n&quot;, GSMOPEN_P_LOG);
+                }
+                if (stream == SND_PCM_STREAM_CAPTURE) {
+                        err = snd_pcm_start(handle);
+                        if (err) {
+                                ERRORA(&quot;snd_pcm_start failed, %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                                return NULL;
+                        }
+                        DEBUGA_GSMOPEN(&quot;started!\n&quot;, GSMOPEN_P_LOG);
+                }
+        }
+        if (option_debug &gt; 1) {
+                snd_output_t *output = NULL;
+                err = snd_output_stdio_attach(&amp;output, stdout, 0);
+                if (err &lt; 0) {
+                        ERRORA(&quot;snd_output_stdio_attach failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(err));
+                }
+                snd_pcm_dump(handle, output);
+        }
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;ALSA handle = %ld\n&quot;, GSMOPEN_P_LOG, (long int) handle);
+        return handle;
+
+}
+
+/*! \brief Write audio frames to interface */
+#endif /* GSMOPEN_ALSA */
+
+int gsmopen_call(private_t * tech_pvt, char *rdest, int timeout)
+{
+
+        //gsmopen_sleep(5000);
+        DEBUGA_GSMOPEN(&quot;Calling GSM, rdest is: %s\n&quot;, GSMOPEN_P_LOG, rdest);
+        //gsmopen_signaling_write(tech_pvt, &quot;SET AGC OFF&quot;);
+        //gsmopen_sleep(10000);
+        //gsmopen_signaling_write(tech_pvt, &quot;SET AEC OFF&quot;);
+        //gsmopen_sleep(10000);
+
+        gsmopen_serial_call(tech_pvt, rdest);
+        //ERRORA(&quot;failed to communicate with GSM client, now exit\n&quot;, GSMOPEN_P_LOG);
+        //return -1;
+        //}
+        return 0;
+}
+
+
+int gsmopen_senddigit(private_t * tech_pvt, char digit)
+{
+
+        DEBUGA_GSMOPEN(&quot;DIGIT received: %c\n&quot;, GSMOPEN_P_LOG, digit);
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT &amp;&amp; tech_pvt-&gt;at_send_dtmf[0]) {
+                int res = 0;
+                char at_command[256];
+
+                memset(at_command, '\0', 256);
+                sprintf(at_command, &quot;%s=\&quot;%c\&quot;&quot;, tech_pvt-&gt;at_send_dtmf, digit);
+                res = gsmopen_serial_write_AT_ack(tech_pvt, at_command);
+                if (res) {
+                        ERRORA(&quot;senddigit command failed, command used: '%s=\&quot;%c\&quot;', giving up\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;at_send_dtmf, digit);
+                }
+        }
+
+        return 0;
+}
+
+/*! \brief Write audio frames to interface */
+int alsa_write(private_t * tech_pvt, short *data, int datalen)
+{
+        static char sizbuf[8000];
+        static char sizbuf2[16000];
+        static char silencebuf[8000];
+        static int sizpos = 0;
+        int len = sizpos;
+        int pos;
+        int res = 0;
+        time_t now_timestamp;
+        /* size_t frames = 0; */
+        snd_pcm_state_t state;
+        snd_pcm_sframes_t delayp1;
+        snd_pcm_sframes_t delayp2;
+
+        //ERRORA(&quot;data=%p, datalen=%d\n&quot;, GSMOPEN_P_LOG, (void *)data, datalen);
+        /* We have to digest the frame in 160-byte portions */
+        if (datalen &gt; sizeof(sizbuf) - sizpos) {
+                ERRORA(&quot;Frame too large\n&quot;, GSMOPEN_P_LOG);
+                res = -1;
+        } else {
+                memcpy(sizbuf + sizpos, data, datalen);
+                len += datalen;
+                pos = 0;
+#ifdef ALSA_MONITOR
+                alsa_monitor_write(sizbuf, len);
+#endif
+                state = snd_pcm_state(tech_pvt-&gt;alsap);
+                if (state == SND_PCM_STATE_XRUN) {
+                        int i;
+
+                        DEBUGA_GSMOPEN
+                                (&quot;You've got an ALSA write XRUN in the past (gsmopen can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;alsa_periods_in_buffer);
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                ERRORA(&quot;audio play prepare failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        } else {
+                                res = snd_pcm_format_set_silence(gsmopen_format, silencebuf, len / 2);
+                                if (res &lt; 0) {
+                                        DEBUGA_GSMOPEN(&quot;Silence error %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                                        res = -1;
+                                }
+                                for (i = 0; i &lt; (tech_pvt-&gt;alsa_periods_in_buffer - 1); i++) {
+                                        res = snd_pcm_writei(tech_pvt-&gt;alsap, silencebuf, len / 2);
+                                        if (res != len / 2) {
+                                                DEBUGA_GSMOPEN(&quot;Write returned a different quantity: %d\n&quot;, GSMOPEN_P_LOG, res);
+                                                res = -1;
+                                        } else if (res &lt; 0) {
+                                                DEBUGA_GSMOPEN(&quot;Write error %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                                                res = -1;
+                                        }
+                                }
+                        }
+
+                }
+
+                res = snd_pcm_delay(tech_pvt-&gt;alsap, &amp;delayp1);
+                if (res &lt; 0) {
+                        DEBUGA_GSMOPEN(&quot;Error %d on snd_pcm_delay: \&quot;%s\&quot;\n&quot;, GSMOPEN_P_LOG, res, snd_strerror(res));
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;snd_pcm_prepare failed: '%s'\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        res = snd_pcm_delay(tech_pvt-&gt;alsap, &amp;delayp1);
+                }
+
+                delayp2 = snd_pcm_avail_update(tech_pvt-&gt;alsap);
+                if (delayp2 &lt; 0) {
+                        DEBUGA_GSMOPEN(&quot;Error %d on snd_pcm_avail_update: \&quot;%s\&quot;\n&quot;, GSMOPEN_P_LOG, (int) delayp2, snd_strerror(delayp2));
+
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                DEBUGA_GSMOPEN(&quot;snd_pcm_prepare failed: '%s'\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        delayp2 = snd_pcm_avail_update(tech_pvt-&gt;alsap);
+                }
+
+                if (                                        /* delayp1 != 0 &amp;&amp; delayp1 != 160 */
+                           delayp1 &lt; 160 || delayp2 &gt; tech_pvt-&gt;alsa_buffer_size) {
+
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                DEBUGA_GSMOPEN
+                                        (&quot;snd_pcm_prepare failed while trying to prevent an ALSA write XRUN: %s, delayp1=%d, delayp2=%d\n&quot;,
+                                         GSMOPEN_P_LOG, snd_strerror(res), (int) delayp1, (int) delayp2);
+                        } else {
+
+                                int i;
+                                for (i = 0; i &lt; (tech_pvt-&gt;alsa_periods_in_buffer - 1); i++) {
+                                        res = snd_pcm_format_set_silence(gsmopen_format, silencebuf, len / 2);
+                                        if (res &lt; 0) {
+                                                DEBUGA_GSMOPEN(&quot;Silence error %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                                                res = -1;
+                                        }
+                                        res = snd_pcm_writei(tech_pvt-&gt;alsap, silencebuf, len / 2);
+                                        if (res &lt; 0) {
+                                                DEBUGA_GSMOPEN(&quot;Write error %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                                                res = -1;
+                                        } else if (res != len / 2) {
+                                                DEBUGA_GSMOPEN(&quot;Write returned a different quantity: %d\n&quot;, GSMOPEN_P_LOG, res);
+                                                res = -1;
+                                        }
+                                }
+
+                                DEBUGA_GSMOPEN
+                                        (&quot;PREVENTING an ALSA write XRUN (gsmopen can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n&quot;,
+                                         GSMOPEN_P_LOG, tech_pvt-&gt;alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
+                        }
+
+                }
+
+                memset(sizbuf2, 0, sizeof(sizbuf2));
+                if (tech_pvt-&gt;alsa_play_is_mono) {
+                        res = snd_pcm_writei(tech_pvt-&gt;alsap, sizbuf, len / 2);
+                } else {
+                        int a = 0;
+                        int i = 0;
+                        for (i = 0; i &lt; 8000;) {
+                                sizbuf2[a] = sizbuf[i];
+                                a++;
+                                i++;
+                                sizbuf2[a] = sizbuf[i];
+                                a++;
+                                i--;
+                                sizbuf2[a] = sizbuf[i];        // comment out this line to use only left 
+                                a++;
+                                i++;
+                                sizbuf2[a] = sizbuf[i];        // comment out this line to use only left
+                                a++;
+                                i++;
+                        }
+                        res = snd_pcm_writei(tech_pvt-&gt;alsap, sizbuf2, len);
+                }
+                if (res == -EPIPE) {
+                        DEBUGA_GSMOPEN
+                                (&quot;ALSA write EPIPE (XRUN) (gsmopen can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                ERRORA(&quot;audio play prepare failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        } else {
+
+                                if (tech_pvt-&gt;alsa_play_is_mono) {
+                                        res = snd_pcm_writei(tech_pvt-&gt;alsap, sizbuf, len / 2);
+                                } else {
+                                        int a = 0;
+                                        int i = 0;
+                                        for (i = 0; i &lt; 8000;) {
+                                                sizbuf2[a] = sizbuf[i];
+                                                a++;
+                                                i++;
+                                                sizbuf2[a] = sizbuf[i];
+                                                a++;
+                                                i--;
+                                                sizbuf2[a] = sizbuf[i];
+                                                a++;
+                                                i++;
+                                                sizbuf2[a] = sizbuf[i];
+                                                a++;
+                                                i++;
+                                        }
+                                        res = snd_pcm_writei(tech_pvt-&gt;alsap, sizbuf2, len);
+                                }
+
+                        }
+
+                } else {
+                        if (res == -ESTRPIPE) {
+                                ERRORA(&quot;You've got some big problems\n&quot;, GSMOPEN_P_LOG);
+                        } else if (res == -EAGAIN) {
+                                res = 0;
+                        } else if (res &lt; 0) {
+                                ERRORA(&quot;Error %d on audio write: \&quot;%s\&quot;\n&quot;, GSMOPEN_P_LOG, res, snd_strerror(res));
+                        }
+                }
+        }
+
+        if (tech_pvt-&gt;audio_play_reset_period) {
+                time(&amp;now_timestamp);
+                if ((now_timestamp - tech_pvt-&gt;audio_play_reset_timestamp) &gt; tech_pvt-&gt;audio_play_reset_period) {
+                        if (option_debug)
+                                DEBUGA_GSMOPEN(&quot;reset audio play\n&quot;, GSMOPEN_P_LOG);
+                        res = snd_pcm_wait(tech_pvt-&gt;alsap, 1000);
+                        if (res &lt; 0) {
+                                ERRORA(&quot;audio play wait failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        res = snd_pcm_drop(tech_pvt-&gt;alsap);
+                        if (res) {
+                                ERRORA(&quot;audio play drop failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        res = snd_pcm_prepare(tech_pvt-&gt;alsap);
+                        if (res) {
+                                ERRORA(&quot;audio play prepare failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        res = snd_pcm_wait(tech_pvt-&gt;alsap, 1000);
+                        if (res &lt; 0) {
+                                ERRORA(&quot;audio play wait failed: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(res));
+                        }
+                        time(&amp;tech_pvt-&gt;audio_play_reset_timestamp);
+                }
+        }
+        //res = 0;
+        //if (res &gt; 0)
+        //res = 0;
+        return res;
+}
+
+#define AST_FRIENDLY_OFFSET 0
+int alsa_read(private_t * tech_pvt, short *data, int datalen)
+{
+        //static struct ast_frame f;
+        static short __buf[GSMOPEN_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
+        static short __buf2[(GSMOPEN_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2];
+        short *buf;
+        short *buf2;
+        static int readpos = 0;
+        //static int left = GSMOPEN_FRAME_SIZE;
+        static int left;
+        snd_pcm_state_t state;
+        int r = 0;
+        int off = 0;
+        int error = 0;
+        //time_t now_timestamp;
+
+        //DEBUGA_GSMOPEN(&quot;buf=%p, datalen=%d, left=%d\n&quot;, GSMOPEN_P_LOG, (void *)buf, datalen, left);
+        //memset(&amp;f, 0, sizeof(struct ast_frame)); //giova
+
+
+
+
+        left = datalen;
+
+
+        state = snd_pcm_state(tech_pvt-&gt;alsac);
+        if (state != SND_PCM_STATE_RUNNING) {
+                DEBUGA_GSMOPEN(&quot;ALSA read state is not SND_PCM_STATE_RUNNING\n&quot;, GSMOPEN_P_LOG);
+
+                if (state != SND_PCM_STATE_PREPARED) {
+                        error = snd_pcm_prepare(tech_pvt-&gt;alsac);
+                        if (error) {
+                                ERRORA(&quot;snd_pcm_prepare failed, %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(error));
+                                return r;
+                        }
+                        DEBUGA_GSMOPEN(&quot;prepared!\n&quot;, GSMOPEN_P_LOG);
+                }
+                usleep(1000);
+                error = snd_pcm_start(tech_pvt-&gt;alsac);
+                if (error) {
+                        ERRORA(&quot;snd_pcm_start failed, %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(error));
+                        return r;
+                }
+                DEBUGA_GSMOPEN(&quot;started!\n&quot;, GSMOPEN_P_LOG);
+                usleep(1000);
+        }
+
+        buf = __buf + AST_FRIENDLY_OFFSET / 2;
+        buf2 = __buf2 + ((AST_FRIENDLY_OFFSET / 2) * 2);
+
+        if (tech_pvt-&gt;alsa_capture_is_mono) {
+                r = snd_pcm_readi(tech_pvt-&gt;alsac, buf + readpos, left);
+                //DEBUGA_GSMOPEN(&quot;r=%d, buf=%p, buf+readpos=%p, datalen=%d, left=%d\n&quot;, GSMOPEN_P_LOG, r, (void *)buf, (void *)(buf + readpos), datalen, left);
+        } else {
+                r = snd_pcm_readi(tech_pvt-&gt;alsac, buf2 + (readpos * 2), left);
+
+                int a = 0;
+                int i = 0;
+                for (i = 0; i &lt; (GSMOPEN_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
+                        __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2;        //comment out this line to use only left
+                        //__buf[a] = __buf2[i]; // enable this line to use only left
+                        a++;
+                        i++;
+                        i++;
+                }
+        }
+
+        if (r == -EPIPE) {
+                DEBUGA_GSMOPEN(&quot;ALSA XRUN on read\n&quot;, GSMOPEN_P_LOG);
+                return r;
+        } else if (r == -ESTRPIPE) {
+                ERRORA(&quot;-ESTRPIPE\n&quot;, GSMOPEN_P_LOG);
+                return r;
+
+        } else if (r == -EAGAIN) {
+                DEBUGA_GSMOPEN(&quot;ALSA read -EAGAIN, the soundcard is not ready to be read by gsmopen\n&quot;, GSMOPEN_P_LOG);
+                while (r == -EAGAIN) {
+                        usleep(1000);
+
+                        if (tech_pvt-&gt;alsa_capture_is_mono) {
+                                r = snd_pcm_readi(tech_pvt-&gt;alsac, buf + readpos, left);
+                        } else {
+                                r = snd_pcm_readi(tech_pvt-&gt;alsac, buf2 + (readpos * 2), left);
+
+                                int a = 0;
+                                int i = 0;
+                                for (i = 0; i &lt; (GSMOPEN_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
+                                        __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2;
+                                        a++;
+                                        i++;
+                                        i++;
+                                }
+                        }
+
+                }
+        } else if (r &lt; 0) {
+                WARNINGA(&quot;ALSA Read error: %s\n&quot;, GSMOPEN_P_LOG, snd_strerror(r));
+        } else if (r &gt;= 0) {
+                //DEBUGA_GSMOPEN(&quot;read: r=%d, readpos=%d, left=%d, off=%d\n&quot;, GSMOPEN_P_LOG, r, readpos, left, off);
+                off -= r;                                //what is the meaning of this? a leftover, probably
+        }
+        /* Update positions */
+        readpos += r;
+        left -= r;
+
+        if (readpos &gt;= GSMOPEN_FRAME_SIZE) {
+                /* A real frame */
+                readpos = 0;
+                left = GSMOPEN_FRAME_SIZE;
+                int i;
+                for (i = 0; i &lt; r; i++)
+                        data[i] = buf[i];
+
+        }
+        return r;
+}
+
+
+
+
+
+
+int gsmopen_sendsms(private_t * tech_pvt, char *dest, char *text)
+{
+        //char *idest = data;
+        //char rdest[256];
+        //struct gsmopen_pvt *p = NULL;
+        //char *device;
+        //char *dest;
+        //char *text;
+        //char *stringp = NULL;
+        //int found = 0;
+        int failed = 0;
+
+        //strncpy(rdest, idest, sizeof(rdest) - 1);
+        DEBUGA_GSMOPEN(&quot;GSMopenSendsms: dest=%s text=%s\n&quot;, GSMOPEN_P_LOG, dest, text);
+        DEBUGA_GSMOPEN(&quot;START\n&quot;, GSMOPEN_P_LOG);
+        /* we can use gsmopen_request to get the channel, but gsmopen_request would look for onowned channels, and probably we can send SMSs while a call is ongoing
+         *
+         */
+
+        if (tech_pvt-&gt;controldevprotocol != PROTOCOL_AT) {
+                ERRORA(&quot;, GSMOPEN_P_LOGGSMopenSendsms supports only AT command cellphones at the moment :-( !\n&quot;, GSMOPEN_P_LOG);
+                return RESULT_FAILURE;
+        }
+
+        if (tech_pvt-&gt;controldevprotocol == PROTOCOL_AT) {
+                int err = 0;
+                char smscommand[16000];
+                memset(smscommand, '\0', sizeof(smscommand));
+
+                PUSHA_UNLOCKA(&amp;tech_pvt-&gt;controldev_lock);
+                LOKKA(tech_pvt-&gt;controldev_lock);
+
+                if (tech_pvt-&gt;no_ucs2) {
+                        sprintf(smscommand, &quot;AT+CMGS=\&quot;%s\&quot;&quot;, dest);        //TODO: support phones that only accept pdu mode
+                } else {
+                        char dest2[1048];
+
+                        err = gsmopen_serial_write_AT_ack(tech_pvt, &quot;AT+CSCS=\&quot;UCS2\&quot;&quot;);
+                        if (err) {
+                                ERRORA(&quot;AT+CSCS=\&quot;UCS2\&quot; (set TE messages to ucs2)  do not got OK from the phone\n&quot;, GSMOPEN_P_LOG);
+                        }
+
+                        memset(dest2, '\0', sizeof(dest2));
+                        utf_to_ucs2(tech_pvt, dest, strlen(dest), dest2, sizeof(dest2));
+                        sprintf(smscommand, &quot;AT+CMGS=\&quot;%s\&quot;&quot;, dest2);        //TODO: support phones that only accept pdu mode
+                }
+                //TODO: support phones that only accept pdu mode
+                //TODO would be better to lock controldev here
+                err = gsmopen_serial_write_AT_noack(tech_pvt, smscommand);
+                if (err) {
+                        ERRORA(&quot;Error sending SMS\n&quot;, GSMOPEN_P_LOG);
+                        failed = 1;
+                        goto uscita;
+                }
+                err = gsmopen_serial_AT_expect(tech_pvt, &quot;&gt; &quot;, 0, 1);        // wait 1.5s for the prompt, no  crlf
+#if 1
+                if (err) {
+                        DEBUGA_GSMOPEN
+                                (&quot;Error or timeout getting prompt '&gt; ' for sending sms directly to the remote party. BTW, seems that we cannot do that with Motorola c350, so we'll write to cellphone memory, then send from memory\n&quot;,
+                                 GSMOPEN_P_LOG);
+
+                        err = gsmopen_serial_write_AT_ack(tech_pvt, &quot;ATE1&quot;);        //motorola (at least c350) do not echo the '&gt;' prompt when in ATE0... go figure!!!!
+                        if (err) {
+                                ERRORA(&quot;Error activating echo from modem\n&quot;, GSMOPEN_P_LOG);
+                        }
+                        tech_pvt-&gt;at_cmgw[0] = '\0';
+                        sprintf(smscommand, &quot;AT+CMGW=\&quot;%s\&quot;&quot;, dest);        //TODO: support phones that only accept pdu mode
+                        err = gsmopen_serial_write_AT_noack(tech_pvt, smscommand);
+                        if (err) {
+                                ERRORA(&quot;Error writing SMS destination to the cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                                failed = 1;
+                                goto uscita;
+                        }
+                        err = gsmopen_serial_AT_expect(tech_pvt, &quot;&gt; &quot;, 0, 1);        // wait 1.5s for the prompt, no  crlf
+                        if (err) {
+                                ERRORA(&quot;Error or timeout getting prompt '&gt; ' for writing sms text in cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                                failed = 1;
+                                goto uscita;
+                        }
+                }
+#endif
+
+                //sprintf(text,&quot;ciao 123 belè новости לק ראת ﺎﻠﺠﻤﻋﺓ 人大&quot;); //let's test the beauty of utf
+                memset(smscommand, '\0', sizeof(smscommand));
+                if (tech_pvt-&gt;no_ucs2) {
+                        sprintf(smscommand, &quot;%s&quot;, text);
+                } else {
+                        utf_to_ucs2(tech_pvt, text, strlen(text), smscommand, sizeof(smscommand));
+                }
+
+                smscommand[strlen(smscommand)] = 0x1A;
+                DEBUGA_GSMOPEN(&quot;smscommand len is: %d, text is:|||%s|||\n&quot;, GSMOPEN_P_LOG, strlen(smscommand), smscommand);
+
+                err = gsmopen_serial_write_AT_ack_nocr_longtime(tech_pvt, smscommand);
+                //TODO would be better to unlock controldev here
+                if (err) {
+                        ERRORA(&quot;Error writing SMS text to the cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                        //return RESULT_FAILURE;
+                        failed = 1;
+                        goto uscita;
+                }
+                if (tech_pvt-&gt;at_cmgw[0]) {
+                        sprintf(smscommand, &quot;AT+CMSS=%s&quot;, tech_pvt-&gt;at_cmgw);
+                        err = gsmopen_serial_write_AT_expect_longtime(tech_pvt, smscommand, &quot;OK&quot;);
+                        if (err) {
+                                ERRORA(&quot;Error sending SMS from the cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                                //return RESULT_FAILURE;
+                                failed = 1;
+                                goto uscita;
+                        }
+
+                        err = gsmopen_serial_write_AT_ack(tech_pvt, &quot;ATE0&quot;);        //motorola (at least c350) do not echo the '&gt;' prompt when in ATE0... go figure!!!!
+                        if (err) {
+                                ERRORA(&quot;Error de-activating echo from modem\n&quot;, GSMOPEN_P_LOG);
+                        }
+                }
+          uscita:
+                usleep(1000);
+
+                if (tech_pvt-&gt;at_cmgw[0]) {
+
+                        /* let's see what we've sent, just for check TODO: Motorola it's not reliable! Motorola c350 tells that all was sent, but is not true! It just sends how much it fits into one SMS FIXME: need an algorithm to calculate how many ucs2 chars fits into an SMS. It make difference based, probably, on the GSM alphabet translation, or so */
+                        sprintf(smscommand, &quot;AT+CMGR=%s&quot;, tech_pvt-&gt;at_cmgw);
+                        err = gsmopen_serial_write_AT_ack(tech_pvt, smscommand);
+                        if (err) {
+                                ERRORA(&quot;Error reading SMS back from the cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                        }
+
+                        /* let's delete from cellphone memory what we've sent */
+                        sprintf(smscommand, &quot;AT+CMGD=%s&quot;, tech_pvt-&gt;at_cmgw);
+                        err = gsmopen_serial_write_AT_ack(tech_pvt, smscommand);
+                        if (err) {
+                                ERRORA(&quot;Error deleting SMS from the cellphone memory\n&quot;, GSMOPEN_P_LOG);
+                        }
+
+                        tech_pvt-&gt;at_cmgw[0] = '\0';
+                }
+                //usleep(500000);             //.5 secs
+                UNLOCKA(tech_pvt-&gt;controldev_lock);
+                POPPA_UNLOCKA(&amp;tech_pvt-&gt;controldev_lock);
+        }
+
+        DEBUGA_GSMOPEN(&quot;FINISH\n&quot;, GSMOPEN_P_LOG);
+        if (failed)
+                return -1;
+        else
+                return RESULT_SUCCESS;
+}
+
+/************************************************/
+
+/* LUIGI RIZZO's magic */
+/* boost support. BOOST_SCALE * 10 ^(BOOST_MAX/20) must
+ * be representable in 16 bits to avoid overflows.
+ */
+#define BOOST_SCALE     (1&lt;&lt;9)
+#define BOOST_MAX       40                /* slightly less than 7 bits */
+
+/*
+ * store the boost factor
+ */
+void gsmopen_store_boost(char *s, double *boost)
+{
+        private_t *tech_pvt = NULL;
+
+        if (sscanf(s, &quot;%lf&quot;, boost) != 1) {
+                ERRORA(&quot;invalid boost &lt;%s&gt;\n&quot;, GSMOPEN_P_LOG, s);
+                return;
+        }
+        if (*boost &lt; -BOOST_MAX) {
+                WARNINGA(&quot;boost %s too small, using %d\n&quot;, GSMOPEN_P_LOG, s, -BOOST_MAX);
+                *boost = -BOOST_MAX;
+        } else if (*boost &gt; BOOST_MAX) {
+                WARNINGA(&quot;boost %s too large, using %d\n&quot;, GSMOPEN_P_LOG, s, BOOST_MAX);
+                *boost = BOOST_MAX;
+        }
+        *boost = exp(log(10) * *boost / 20) * BOOST_SCALE;
+        if (option_debug &gt; 1)
+                DEBUGA_GSMOPEN(&quot;setting boost %s to %f\n&quot;, GSMOPEN_P_LOG, s, *boost);
+}
+
+
+int gsmopen_sound_boost(void *data, int samples_num, double boost)
+{
+/* LUIGI RIZZO's magic */
+        if (boost != 0) {                        /* scale and clip values */
+                int i, x;
+
+                int16_t *ptr = (int16_t *) data;
+
+                for (i = 0; i &lt; samples_num; i++) {
+                        x = (ptr[i] * boost) / BOOST_SCALE;
+                        if (x &gt; 32767) {
+                                x = 32767;
+                        } else if (x &lt; -32768) {
+                                x = -32768;
+                        }
+                        ptr[i] = x;
+                }
+        }
+        return 0;
+}
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenmod_celliaxc"></a>
<div class="delfile"><h4>Deleted: freeswitch/branches/gmaruzz/mod_gsmopen/mod_celliax.c</h4></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenmod_gsmopencfromrev15046freeswitchbranchesgmaruzzmod_gsmopenmod_celliaxc"></a>
<div class="copfile"><h4>Copied: freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.c (from rev 15046, freeswitch/branches/gmaruzz/mod_gsmopen/mod_celliax.c) (0 => 15047)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.c                                (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.c        2009-10-02 13:19:23 UTC (rev 15047)
</span><span class="lines">@@ -0,0 +1,2687 @@
</span><ins>+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II &lt;anthmct@yahoo.com&gt;
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II &lt;anthmct@yahoo.com&gt;
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This module (mod_gsmopen) has been contributed by:
+ *
+ * Giovanni Maruzzelli (gmaruzz@gmail.com)
+ *
+ *
+ * Further Contributors:
+ *
+ *
+ *
+ * mod_gsmopen.c -- GSM compatible Endpoint Module
+ *
+ */
+
+#include &quot;gsmopen.h&quot;
+#define MDL_CHAT_PROTO &quot;SMS&quot;
+
+#ifdef WIN32
+/***************/
+// from http://www.openasthra.com/c-tidbits/gettimeofday-function-for-windows/
+
+#include &lt;time.h&gt;
+
+#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
+#else /*  */
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
+#endif /*  */
+struct sk_timezone {
+        int tz_minuteswest;                        /* minutes W of Greenwich */
+        int tz_dsttime;                                /* type of dst correction */
+};
+int gettimeofday(struct timeval *tv, struct sk_timezone *tz)
+{
+        FILETIME ft;
+        unsigned __int64 tmpres = 0;
+        static int tzflag;
+        if (NULL != tv) {
+                GetSystemTimeAsFileTime(&amp;ft);
+                tmpres |= ft.dwHighDateTime;
+                tmpres &lt;&lt;= 32;
+                tmpres |= ft.dwLowDateTime;
+
+                /*converting file time to unix epoch */
+                tmpres /= 10;                        /*convert into microseconds */
+                tmpres -= DELTA_EPOCH_IN_MICROSECS;
+                tv-&gt;tv_sec = (long) (tmpres / 1000000UL);
+                tv-&gt;tv_usec = (long) (tmpres % 1000000UL);
+        }
+        if (NULL != tz) {
+                if (!tzflag) {
+                        _tzset();
+                        tzflag++;
+                }
+                tz-&gt;tz_minuteswest = _timezone / 60;
+                tz-&gt;tz_dsttime = _daylight;
+        }
+        return 0;
+}
+
+/***************/
+#endif /* WIN32 */
+SWITCH_MODULE_LOAD_FUNCTION(mod_gsmopen_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_gsmopen_shutdown);
+SWITCH_MODULE_DEFINITION(mod_gsmopen, mod_gsmopen_load, mod_gsmopen_shutdown, NULL);
+#if 0
+SWITCH_STANDARD_API(sk_function);
+/* BEGIN: Changes here */
+#define SK_SYNTAX &quot;list [full] || console || gsmopen_API_msg || remove &lt; gsmopenusername | #interface_name | #interface_id &gt; || reload&quot;
+/* END: Changes heres */
+SWITCH_STANDARD_API(gsmopen_function);
+#define GSMOPEN_SYNTAX &quot;interface_name gsmopen_API_msg&quot;
+#endif //0
+
+SWITCH_STANDARD_API(sendsms_function);
+#define SENDSMS_SYNTAX &quot;gsmopen_sendsms interface_name destination_number SMS_text&quot;
+/* BEGIN: Changes here */
+#define FULL_RELOAD 0
+#define SOFT_RELOAD 1
+/* END: Changes heres */
+
+char *interface_status[] = {        /* should match GSMOPEN_STATE_xxx in gsmopen.h */
+        &quot;IDLE&quot;,
+        &quot;DOWN&quot;,
+        &quot;RING&quot;,
+        &quot;DIALING&quot;,
+        &quot;BUSY&quot;,
+        &quot;UP&quot;,
+        &quot;RINGING&quot;,
+        &quot;PRERING&quot;,
+        &quot;DOUBLE&quot;,
+        &quot;SELECTD&quot;,
+        &quot;HANG_RQ&quot;,
+        &quot;PREANSW&quot;
+};
+char *phone_callflow[] = {                /* should match CALLFLOW_XXX in gsmopen.h */
+        &quot;CALL_IDLE&quot;,
+        &quot;CALL_DOWN&quot;,
+        &quot;INCOMING_RNG&quot;,
+        &quot;CALL_DIALING&quot;,
+        &quot;CALL_LINEBUSY&quot;,
+        &quot;CALL_ACTIVE&quot;,
+        &quot;INCOMING_HNG&quot;,
+        &quot;CALL_RLEASD&quot;,
+        &quot;CALL_NOCARR&quot;,
+        &quot;CALL_INFLUX&quot;,
+        &quot;CALL_INCOMING&quot;,
+        &quot;CALL_FAILED&quot;,
+        &quot;CALL_NOSRVC&quot;,
+        &quot;CALL_OUTRESTR&quot;,
+        &quot;CALL_SECFAIL&quot;,
+        &quot;CALL_NOANSWER&quot;,
+        &quot;STATUS_FNSHED&quot;,
+        &quot;STATUS_CANCLED&quot;,
+        &quot;STATUS_FAILED&quot;,
+        &quot;STATUS_REFUSED&quot;,
+        &quot;STATUS_RINGING&quot;,
+        &quot;STATUS_INPROGRS&quot;,
+        &quot;STATUS_UNPLACD&quot;,
+        &quot;STATUS_ROUTING&quot;,
+        &quot;STATUS_EARLYMD&quot;,
+        &quot;INCOMING_CLID&quot;,
+        &quot;STATUS_RMTEHOLD&quot;
+};
+
+
+static struct {
+        int debug;
+        char *ip;
+        int port;
+        char *dialplan;
+        char *destination;
+        char *context;
+        char *codec_string;
+        char *codec_order[SWITCH_MAX_CODECS];
+        int codec_order_last;
+        char *codec_rates_string;
+        char *codec_rates[SWITCH_MAX_CODECS];
+        int codec_rates_last;
+        unsigned int flags;
+        int fd;
+        int calls;
+        int real_interfaces;
+        int next_interface;
+        char hold_music[256];
+        private_t GSMOPEN_INTERFACES[GSMOPEN_MAX_INTERFACES];
+        switch_mutex_t *mutex;
+        private_t *sk_console;
+} globals;
+
+switch_endpoint_interface_t *gsmopen_endpoint_interface;
+switch_memory_pool_t *gsmopen_module_pool = NULL;
+int running = 0;
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, globals.context);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_destination, globals.destination);
+//SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string);
+//SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_rates_string, globals.codec_rates_string);
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface);
+#if 0
+static switch_status_t remove_interface(char *the_interface);
+#endif //0
+/* END: Changes here */
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_hangup(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_status_t channel_on_routing(switch_core_session_t *session);
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session);
+static switch_status_t channel_on_consume_media(switch_core_session_t *session);
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+                                                                                                        switch_event_t *var_event,
+                                                                                                        switch_caller_profile_t *outbound_profile,
+                                                                                                        switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
+static switch_status_t gsmopen_tech_init(private_t * tech_pvt, switch_core_session_t *session);
+
+static switch_status_t gsmopen_codec(private_t * tech_pvt, int sample_rate, int codec_ms)
+{
+        switch_core_session_t *session = NULL;
+
+        if (switch_core_codec_init
+                (&amp;tech_pvt-&gt;read_codec, &quot;L16&quot;, NULL, sample_rate, codec_ms, 1,
+                 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+                ERRORA(&quot;Can't load codec?\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        if (switch_core_codec_init
+                (&amp;tech_pvt-&gt;write_codec, &quot;L16&quot;, NULL, sample_rate, codec_ms, 1,
+                 SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+                ERRORA(&quot;Can't load codec?\n&quot;, GSMOPEN_P_LOG);
+                switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        tech_pvt-&gt;read_frame.rate = sample_rate;
+        tech_pvt-&gt;read_frame.codec = &amp;tech_pvt-&gt;read_codec;
+
+        session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+
+        if (session) {
+                switch_core_session_set_read_codec(session, &amp;tech_pvt-&gt;read_codec);
+                switch_core_session_set_write_codec(session, &amp;tech_pvt-&gt;write_codec);
+                switch_core_session_rwunlock(session);
+        } else {
+                ERRORA(&quot;no session\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        return SWITCH_STATUS_SUCCESS;
+
+}
+
+switch_status_t gsmopen_tech_init(private_t * tech_pvt, switch_core_session_t *session)
+{
+
+        switch_assert(tech_pvt != NULL);
+        switch_assert(session != NULL);
+        tech_pvt-&gt;read_frame.data = tech_pvt-&gt;databuf;
+        tech_pvt-&gt;read_frame.buflen = sizeof(tech_pvt-&gt;databuf);
+        switch_mutex_init(&amp;tech_pvt-&gt;mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+        switch_mutex_init(&amp;tech_pvt-&gt;flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+        switch_core_session_set_private(session, tech_pvt);
+        switch_copy_string(tech_pvt-&gt;session_uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt-&gt;session_uuid_str));
+        if (!strlen(tech_pvt-&gt;session_uuid_str)) {
+                ERRORA(&quot;no tech_pvt-&gt;session_uuid_str\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+        if (gsmopen_codec(tech_pvt, SAMPLERATE_GSMOPEN, 20) != SWITCH_STATUS_SUCCESS) {
+                ERRORA(&quot;gsmopen_codec FAILED\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+        //teletone_dtmf_detect_init(&amp;tech_pvt-&gt;dtmf_detect, tech_pvt-&gt;read_codec.implementation-&gt;actual_samples_per_second);
+        teletone_dtmf_detect_init(&amp;tech_pvt-&gt;dtmf_detect, 8000);
+
+        if (alsa_init(tech_pvt)) {
+                ERRORA(&quot;alsa_init failed\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+
+        }
+        if (switch_core_timer_init(&amp;tech_pvt-&gt;timer_read, &quot;soft&quot;, 20, tech_pvt-&gt;read_codec.implementation-&gt;samples_per_packet, gsmopen_module_pool) !=
+                SWITCH_STATUS_SUCCESS) {
+                ERRORA(&quot;setup timer failed\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_core_timer_sync(&amp;tech_pvt-&gt;timer_read);
+
+        if (switch_core_timer_init(&amp;tech_pvt-&gt;timer_write, &quot;soft&quot;, 20, tech_pvt-&gt;write_codec.implementation-&gt;samples_per_packet, gsmopen_module_pool) !=
+                SWITCH_STATUS_SUCCESS) {
+                ERRORA(&quot;setup timer failed\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_core_timer_sync(&amp;tech_pvt-&gt;timer_write);
+
+
+        switch_clear_flag(tech_pvt, TFLAG_HANGUP);
+        DEBUGA_GSMOPEN(&quot;gsmopen_codec SUCCESS\n&quot;, GSMOPEN_P_LOG);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* BEGIN: Changes here */
+static switch_status_t interface_exists(char *the_interface)
+{
+        int i;
+        int interface_id;
+
+        if (*the_interface == '#') {        /* look by interface id or interface name */
+                the_interface++;
+                switch_assert(the_interface);
+                interface_id = atoi(the_interface);
+
+                /* take a number as interface id */
+                if (interface_id &gt; 0 || (interface_id == 0 &amp;&amp; strcmp(the_interface, &quot;0&quot;) == 0)) {
+                        if (strlen(globals.GSMOPEN_INTERFACES[interface_id].name)) {
+                                return SWITCH_STATUS_SUCCESS;
+                        }
+                } else {
+                        /* interface name */
+                        for (interface_id = 0; interface_id &lt; GSMOPEN_MAX_INTERFACES; interface_id++) {
+                                if (strcmp(globals.GSMOPEN_INTERFACES[interface_id].name, the_interface) == 0) {
+                                        return SWITCH_STATUS_SUCCESS;
+                                        break;
+                                }
+                        }
+                }
+        } else {                                        /* look by gsmopen_user */
+
+
+                for (i = 0; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].gsmopen_user)) {
+                                if (strcmp(globals.GSMOPEN_INTERFACES[i].gsmopen_user, the_interface) == 0) {
+                                        return SWITCH_STATUS_SUCCESS;
+                                }
+                        }
+                }
+        }
+        return SWITCH_STATUS_FALSE;
+}
+
+#if 0
+static switch_status_t remove_interface(char *the_interface)
+{
+        int x = 10;
+        unsigned int howmany = 8;
+        int interface_id = -1;
+        private_t *tech_pvt = NULL;
+        switch_status_t status;
+
+        //running = 0;
+
+
+        if (*the_interface == '#') {        /* remove by interface id or interface name */
+                the_interface++;
+                switch_assert(the_interface);
+                interface_id = atoi(the_interface);
+
+                if (interface_id &gt; 0 || (interface_id == 0 &amp;&amp; strcmp(the_interface, &quot;0&quot;) == 0)) {
+                        /* take a number as interface id */
+                        tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+                } else {
+
+                        for (interface_id = 0; interface_id &lt; GSMOPEN_MAX_INTERFACES; interface_id++) {
+                                if (strcmp(globals.GSMOPEN_INTERFACES[interface_id].name, the_interface) == 0) {
+                                        tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+                                        break;
+                                }
+                        }
+                }
+        } else {                                        /* remove by gsmopen_user */
+                for (interface_id = 0; interface_id &lt; GSMOPEN_MAX_INTERFACES; interface_id++) {
+                        if (strcmp(globals.GSMOPEN_INTERFACES[interface_id].gsmopen_user, the_interface) == 0) {
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+                                break;
+                        }
+                }
+        }
+
+        if (!tech_pvt) {
+                DEBUGA_GSMOPEN(&quot;interface '%s' does not exist\n&quot;, GSMOPEN_P_LOG, the_interface);
+                goto end;
+        }
+
+        if (strlen(globals.GSMOPEN_INTERFACES[interface_id].session_uuid_str)) {
+                DEBUGA_GSMOPEN(&quot;interface '%s' is busy\n&quot;, GSMOPEN_P_LOG, the_interface);
+                goto end;
+        }
+
+        globals.GSMOPEN_INTERFACES[interface_id].running = 0;
+
+        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread) {
+#ifdef WIN32
+                switch_file_write(tech_pvt-&gt;GSMopenHandles.fdesc[1], &quot;sciutati&quot;, &amp;howmany);        // let's the controldev_thread die
+#else /* WIN32 */
+                howmany = write(tech_pvt-&gt;GSMopenHandles.fdesc[1], &quot;sciutati&quot;, howmany);
+#endif /* WIN32 */
+        }
+
+        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread) {
+#ifdef WIN32
+                if (SendMessage(tech_pvt-&gt;GSMopenHandles.win32_hInit_MainWindowHandle, WM_DESTROY, 0, 0) == FALSE) {        // let's the gsmopen_api_thread_func die
+                        DEBUGA_GSMOPEN(&quot;got FALSE here, thread probably was already dead. GetLastError returned: %d\n&quot;, GSMOPEN_P_LOG, GetLastError());
+                        globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread = NULL;
+                }
+#else
+                XEvent e;
+                Atom atom1 = XInternAtom(tech_pvt-&gt;GSMopenHandles.disp, &quot;GSMOPENCONTROLAPI_MESSAGE_BEGIN&quot;, False);
+                memset(&amp;e, 0, sizeof(e));
+                e.xclient.type = ClientMessage;
+                e.xclient.message_type = atom1;        /*  leading message */
+                e.xclient.display = tech_pvt-&gt;GSMopenHandles.disp;
+                e.xclient.window = tech_pvt-&gt;GSMopenHandles.gsmopen_win;
+                e.xclient.format = 8;
+
+                XSendEvent(tech_pvt-&gt;GSMopenHandles.disp, tech_pvt-&gt;GSMopenHandles.win, False, 0, &amp;e);
+                XSync(tech_pvt-&gt;GSMopenHandles.disp, False);
+#endif
+        }
+
+        while (x) {
+                x--;
+                switch_yield(50000);
+        }
+
+        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread) {
+                switch_thread_join(&amp;status, globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread);
+        }
+
+        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread) {
+                switch_thread_join(&amp;status, globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread);
+        }
+
+        switch_mutex_lock(globals.mutex);
+        if (globals.sk_console == &amp;globals.GSMOPEN_INTERFACES[interface_id]) {
+                DEBUGA_GSMOPEN(&quot;interface '%s' no more console\n&quot;, GSMOPEN_P_LOG, the_interface);
+                globals.sk_console = NULL;
+        } else {
+                DEBUGA_GSMOPEN(&quot;interface '%s' STILL console\n&quot;, GSMOPEN_P_LOG, the_interface);
+        }
+        memset(&amp;globals.GSMOPEN_INTERFACES[interface_id], '\0', sizeof(private_t));
+        globals.real_interfaces--;
+        switch_mutex_unlock(globals.mutex);
+
+        DEBUGA_GSMOPEN(&quot;interface '%s' deleted successfully\n&quot;, GSMOPEN_P_LOG, the_interface);
+        globals.GSMOPEN_INTERFACES[interface_id].running = 1;
+  end:
+        //running = 1;
+        return SWITCH_STATUS_SUCCESS;
+}
+#endif //0
+
+/* END: Changes here */
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+        switch_channel_t *channel;
+        private_t *tech_pvt = NULL;
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+        //ERRORA(&quot;%s CHANNEL INIT\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        switch_set_flag(tech_pvt, TFLAG_IO);
+
+        /* Move channel's state machine to ROUTING. This means the call is trying
+           to get from the initial start where the call because, to the point
+           where a destination has been identified. If the channel is simply
+           left in the initial state, nothing will happen. */
+        switch_channel_set_state(channel, CS_ROUTING);
+        switch_mutex_lock(globals.mutex);
+        globals.calls++;
+
+        switch_mutex_unlock(globals.mutex);
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL INIT %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, switch_core_session_get_uuid(session));
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+        private_t *tech_pvt = NULL;
+
+        tech_pvt = switch_core_session_get_private(session);
+
+
+        if (tech_pvt) {
+                DEBUGA_GSMOPEN(&quot;%s CHANNEL DESTROY %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, switch_core_session_get_uuid(session));
+
+                if (switch_core_codec_ready(&amp;tech_pvt-&gt;read_codec)) {
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;read_codec);
+                }
+
+                if (switch_core_codec_ready(&amp;tech_pvt-&gt;write_codec)) {
+                        switch_core_codec_destroy(&amp;tech_pvt-&gt;write_codec);
+                }
+
+                switch_core_timer_destroy(&amp;tech_pvt-&gt;timer_read);
+                switch_core_timer_destroy(&amp;tech_pvt-&gt;timer_write);
+
+                alsa_shutdown(tech_pvt);
+
+                *tech_pvt-&gt;session_uuid_str = '\0';
+                tech_pvt-&gt;interface_state = GSMOPEN_STATE_IDLE;
+                if (tech_pvt-&gt;phone_callflow == CALLFLOW_STATUS_FINISHED) {
+                        tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+                }
+                switch_core_session_set_private(session, NULL);
+        } else {
+                DEBUGA_GSMOPEN(&quot;!!!!!!NO tech_pvt!!!! CHANNEL DESTROY %s\n&quot;, GSMOPEN_P_LOG, switch_core_session_get_uuid(session));
+        }
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_hangup(switch_core_session_t *session)
+{
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_HANGUP_REQUESTED;
+
+        if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
+                if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+                        tech_pvt-&gt;ob_failed_calls++;
+                } else {
+                        tech_pvt-&gt;ib_failed_calls++;
+                }
+        }
+
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL HANGUP\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        switch_clear_flag(tech_pvt, TFLAG_IO);
+        switch_clear_flag(tech_pvt, TFLAG_VOICE);
+        switch_set_flag(tech_pvt, TFLAG_HANGUP);
+
+        gsmopen_hangup(tech_pvt);
+
+        //memset(tech_pvt-&gt;session_uuid_str, '\0', sizeof(tech_pvt-&gt;session_uuid_str));
+        //*tech_pvt-&gt;session_uuid_str = '\0';
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL HANGUP\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        switch_mutex_lock(globals.mutex);
+        globals.calls--;
+        if (globals.calls &lt; 0) {
+                globals.calls = 0;
+        }
+
+        tech_pvt-&gt;interface_state = GSMOPEN_STATE_IDLE;
+        if (tech_pvt-&gt;phone_callflow == CALLFLOW_STATUS_FINISHED) {
+                tech_pvt-&gt;phone_callflow = CALLFLOW_CALL_IDLE;
+        }
+        switch_mutex_unlock(globals.mutex);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_routing(switch_core_session_t *session)
+{
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL ROUTING\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_execute(switch_core_session_t *session)
+{
+
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL EXECUTE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig)
+{
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL KILL_CHANNEL\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        switch (sig) {
+        case SWITCH_SIG_KILL:
+                DEBUGA_GSMOPEN(&quot;%s CHANNEL got SWITCH_SIG_KILL\n&quot;, GSMOPEN_P_LOG, switch_channel_get_name(channel));
+                //switch_mutex_lock(tech_pvt-&gt;flag_mutex);
+                switch_clear_flag(tech_pvt, TFLAG_IO);
+                switch_clear_flag(tech_pvt, TFLAG_VOICE);
+                switch_set_flag(tech_pvt, TFLAG_HANGUP);
+                //switch_mutex_unlock(tech_pvt-&gt;flag_mutex);
+                break;
+        case SWITCH_SIG_BREAK:
+                DEBUGA_GSMOPEN(&quot;%s CHANNEL got SWITCH_SIG_BREAK\n&quot;, GSMOPEN_P_LOG, switch_channel_get_name(channel));
+                //switch_set_flag(tech_pvt, TFLAG_BREAK);
+                //switch_mutex_lock(tech_pvt-&gt;flag_mutex);
+                switch_set_flag(tech_pvt, TFLAG_BREAK);
+                //switch_mutex_unlock(tech_pvt-&gt;flag_mutex);
+                break;
+        default:
+                break;
+        }
+
+        return SWITCH_STATUS_SUCCESS;
+}
+static switch_status_t channel_on_consume_media(switch_core_session_t *session)
+{
+        private_t *tech_pvt = NULL;
+
+        tech_pvt = switch_core_session_get_private(session);
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL CONSUME_MEDIA\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t channel_on_exchange_media(switch_core_session_t *session)
+{
+        private_t *tech_pvt = NULL;
+        tech_pvt = switch_core_session_get_private(session);
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL EXCHANGE_MEDIA\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_on_soft_execute(switch_core_session_t *session)
+{
+        private_t *tech_pvt = NULL;
+        tech_pvt = switch_core_session_get_private(session);
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL SOFT_EXECUTE\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t * dtmf)
+{
+        private_t *tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL SEND_DTMF\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        DEBUGA_GSMOPEN(&quot;DTMF: %c\n&quot;, GSMOPEN_P_LOG, dtmf-&gt;digit);
+
+        gsmopen_senddigit(tech_pvt, dtmf-&gt;digit);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+        switch_byte_t *data;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+                ERRORA(&quot;channel not ready \n&quot;, GSMOPEN_P_LOG);
+                //TODO: kill the bastard
+                return SWITCH_STATUS_FALSE;
+        }
+
+
+        tech_pvt-&gt;read_frame.flags = SFF_NONE;
+        *frame = NULL;
+
+        if (switch_test_flag(tech_pvt, TFLAG_HANGUP)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+
+        switch_core_timer_next(&amp;tech_pvt-&gt;timer_read);
+
+        int samples;
+
+        //if ((samples = snd_pcm_readi(tech_pvt-&gt;alsac, tech_pvt-&gt;read_frame.data, tech_pvt-&gt;read_codec.implementation-&gt;samples_per_packet)) &gt; 0) 
+        if ((samples = alsa_read(tech_pvt, tech_pvt-&gt;read_frame.data, tech_pvt-&gt;read_codec.implementation-&gt;samples_per_packet)) &gt; 0) {
+
+                tech_pvt-&gt;read_frame.datalen = samples * 2;
+                tech_pvt-&gt;read_frame.samples = samples;
+
+                //switch_core_timer_check(&amp;tech_pvt-&gt;timer, SWITCH_TRUE);
+                tech_pvt-&gt;read_frame.timestamp = tech_pvt-&gt;timer_read.samplecount;
+
+                gsmopen_sound_boost(tech_pvt-&gt;read_frame.data, tech_pvt-&gt;read_frame.samples, tech_pvt-&gt;capture_boost);
+
+
+
+
+                *frame = &amp;tech_pvt-&gt;read_frame;
+
+                //status = SWITCH_STATUS_SUCCESS;
+                switch_set_flag(tech_pvt, TFLAG_VOICE);
+        }
+
+        if (samples != 160) {
+                ERRORA(&quot;samples=%d\n&quot;, GSMOPEN_P_LOG, samples);
+                goto cng;
+        }
+//DEBUGA_GSMOPEN(&quot;samples=%d tech_pvt-&gt;read_frame.timestamp=%d\n&quot;, GSMOPEN_P_LOG, samples, tech_pvt-&gt;read_frame.timestamp);
+
+//usleep(17000);
+//usleep(17000);
+
+
+
+        char digit_str[256];
+
+
+        memset(digit_str, 0, sizeof(digit_str));
+        teletone_dtmf_detect(&amp;tech_pvt-&gt;dtmf_detect, tech_pvt-&gt;read_frame.data, tech_pvt-&gt;read_frame.samples);
+        teletone_dtmf_get(&amp;tech_pvt-&gt;dtmf_detect, digit_str, sizeof(digit_str));
+
+        if (digit_str[0]) {
+                switch_time_t new_dtmf_timestamp = switch_time_now();
+                if ((new_dtmf_timestamp - tech_pvt-&gt;old_dtmf_timestamp) &gt; 350000) {        //FIXME: make it configurable
+                        char *p = digit_str;
+                        switch_channel_t *channel = switch_core_session_get_channel(session);
+
+                        while (p &amp;&amp; *p) {
+                                switch_dtmf_t dtmf;
+                                dtmf.digit = *p;
+                                dtmf.duration = SWITCH_DEFAULT_DTMF_DURATION;
+                                switch_channel_queue_dtmf(channel, &amp;dtmf);
+                                p++;
+                        }
+                        NOTICA(&quot;DTMF DETECTED: [%s] new_dtmf_timestamp: %u, delta_t: %u\n&quot;, GSMOPEN_P_LOG, digit_str, (unsigned int) new_dtmf_timestamp,
+                                   (unsigned int) (new_dtmf_timestamp - tech_pvt-&gt;old_dtmf_timestamp));
+                        tech_pvt-&gt;old_dtmf_timestamp = new_dtmf_timestamp;
+                }
+        }
+        while (switch_test_flag(tech_pvt, TFLAG_IO)) {
+                if (switch_test_flag(tech_pvt, TFLAG_BREAK)) {
+                        switch_clear_flag(tech_pvt, TFLAG_BREAK);
+                        DEBUGA_GSMOPEN(&quot;CHANNEL READ FRAME goto CNG\n&quot;, GSMOPEN_P_LOG);
+                        goto cng;
+                }
+
+                if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+                        DEBUGA_GSMOPEN(&quot;CHANNEL READ FRAME not IO\n&quot;, GSMOPEN_P_LOG);
+                        return SWITCH_STATUS_FALSE;
+                }
+
+                if (switch_test_flag(tech_pvt, TFLAG_IO) &amp;&amp; switch_test_flag(tech_pvt, TFLAG_VOICE)) {
+                        switch_clear_flag(tech_pvt, TFLAG_VOICE);
+                        if (!tech_pvt-&gt;read_frame.datalen) {
+                                DEBUGA_GSMOPEN(&quot;CHANNEL READ CONTINUE\n&quot;, GSMOPEN_P_LOG);
+                                continue;
+                        }
+                        *frame = &amp;tech_pvt-&gt;read_frame;
+#ifdef BIGENDIAN
+                        if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+                                switch_swap_linear((*frame)-&gt;data, (int) (*frame)-&gt;datalen / 2);
+                        }
+#endif
+                        //WARNINGA(&quot;HERE\n&quot;, GSMOPEN_P_LOG);
+                        return SWITCH_STATUS_SUCCESS;
+                }
+
+                WARNINGA(&quot;HERE\n&quot;, GSMOPEN_P_LOG);
+                DEBUGA_GSMOPEN(&quot;CHANNEL READ no TFLAG_VOICE\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_FALSE;
+
+        }
+
+        DEBUGA_GSMOPEN(&quot;CHANNEL READ FALSE\n&quot;, GSMOPEN_P_LOG);
+        return SWITCH_STATUS_FALSE;
+
+  cng:
+        data = (switch_byte_t *) tech_pvt-&gt;read_frame.data;
+        data[0] = 65;
+        data[1] = 0;
+        tech_pvt-&gt;read_frame.datalen = 2;
+        tech_pvt-&gt;read_frame.flags = SFF_CNG;
+        *frame = &amp;tech_pvt-&gt;read_frame;
+        return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+        switch_channel_t *channel = NULL;
+        private_t *tech_pvt = NULL;
+        unsigned int sent;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        if (!switch_channel_ready(channel) || !switch_test_flag(tech_pvt, TFLAG_IO)) {
+                ERRORA(&quot;channel not ready \n&quot;, GSMOPEN_P_LOG);
+                //TODO: kill the bastard
+                return SWITCH_STATUS_FALSE;
+        }
+#ifdef BIGENDIAN
+        if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+                switch_swap_linear(frame-&gt;data, (int) frame-&gt;datalen / 2);
+        }
+#endif
+
+        switch_core_timer_next(&amp;tech_pvt-&gt;timer_write);
+        //sent = frame-&gt;datalen;
+
+        //ERRORA(&quot;PLAY \n&quot;, GSMOPEN_P_LOG);
+        //snd_pcm_writei(tech_pvt-&gt;alsap, (short *) frame-&gt;data, (int) (frame-&gt;datalen / 2));
+
+        gsmopen_sound_boost(frame-&gt;data, frame-&gt;samples, tech_pvt-&gt;playback_boost);
+        sent = alsa_write(tech_pvt, frame-&gt;data, (int) (frame-&gt;datalen));
+//DEBUGA_GSMOPEN(&quot;sent=%d \n&quot;, GSMOPEN_P_LOG, sent);
+
+        if (sent &amp;&amp; sent != frame-&gt;datalen / 2 &amp;&amp; sent != -1) {
+                DEBUGA_GSMOPEN(&quot;sent %d\n&quot;, GSMOPEN_P_LOG, sent);
+        }
+        //NOTICA(&quot;sent=%d\n&quot;, GSMOPEN_P_LOG, sent);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_answer_channel(switch_core_session_t *session)
+{
+        private_t *tech_pvt;
+        switch_channel_t *channel = NULL;
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        //ERRORA(&quot;%s CHANNEL INIT\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        switch_set_flag(tech_pvt, TFLAG_IO);
+gsmopen_serial_answer(tech_pvt);
+
+        /* Move channel's state machine to ROUTING. This means the call is trying
+           to get from the initial start where the call because, to the point
+           where a destination has been identified. If the channel is simply
+           left in the initial state, nothing will happen. */
+        switch_channel_set_state(channel, CS_ROUTING);
+        switch_mutex_lock(globals.mutex);
+        globals.calls++;
+
+        switch_mutex_unlock(globals.mutex);
+        DEBUGA_GSMOPEN(&quot;%s CHANNEL ANSWER %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, switch_core_session_get_uuid(session));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        DEBUGA_GSMOPEN(&quot;ANSWERED! \n&quot;, GSMOPEN_P_LOG);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+        switch_channel_t *channel;
+        private_t *tech_pvt;
+        int samples;
+        short tmp_buffer[1280];
+
+        channel = switch_core_session_get_channel(session);
+        switch_assert(channel != NULL);
+
+        tech_pvt = (private_t *) switch_core_session_get_private(session);
+        switch_assert(tech_pvt != NULL);
+
+        switch (msg-&gt;message_id) {
+        case SWITCH_MESSAGE_INDICATE_ANSWER:
+                {
+                        DEBUGA_GSMOPEN(&quot;MSG_ID=%d, TO BE ANSWERED!\n&quot;, GSMOPEN_P_LOG, msg-&gt;message_id);
+                        channel_answer_channel(session);
+                }
+                break;
+        case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+
+                WARNINGA(&quot;%s CHANNEL got SWITCH_MESSAGE_INDICATE_AUDIO_SYNC\n&quot;, GSMOPEN_P_LOG, switch_channel_get_name(channel));
+                while ((samples = alsa_read(tech_pvt, tmp_buffer, tech_pvt-&gt;read_codec.implementation-&gt;samples_per_packet * 4)) &gt; 160) {
+                        WARNINGA(&quot;read %d samples\n&quot;, GSMOPEN_P_LOG, samples);
+                }
+                switch_core_timer_sync(&amp;tech_pvt-&gt;timer_read);
+                switch_core_timer_sync(&amp;tech_pvt-&gt;timer_write);
+
+                break;
+
+
+        default:
+                {
+                        DEBUGA_GSMOPEN(&quot;MSG_ID=%d\n&quot;, GSMOPEN_P_LOG, msg-&gt;message_id);
+                }
+                break;
+        }
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event)
+{
+        struct private_object *tech_pvt = switch_core_session_get_private(session);
+        char *body = switch_event_get_body(event);
+        switch_assert(tech_pvt != NULL);
+
+        if (!body) {
+                body = &quot;&quot;;
+        }
+
+        WARNINGA(&quot;event: |||%s|||\n&quot;, GSMOPEN_P_LOG, body);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+switch_state_handler_table_t gsmopen_state_handlers = {
+        /*.on_init */ channel_on_init,
+        /*.on_routing */ channel_on_routing,
+        /*.on_execute */ channel_on_execute,
+        /*.on_hangup */ channel_on_hangup,
+        /*.on_exchange_media */ channel_on_exchange_media,
+        /*.on_soft_execute */ channel_on_soft_execute,
+        /*.on_consume_media */ channel_on_consume_media,
+        /*.on_hibernate */ NULL,
+        /*.on_reset */ NULL,
+        /*.on_park */ NULL,
+        /*.on_reporting */ NULL,
+        /*.on_destroy */ channel_on_destroy
+};
+
+switch_io_routines_t gsmopen_io_routines = {
+        /*.outgoing_channel */ channel_outgoing_channel,
+        /*.read_frame */ channel_read_frame,
+        /*.write_frame */ channel_write_frame,
+        /*.kill_channel */ channel_kill_channel,
+        /*.send_dtmf */ channel_send_dtmf,
+        /*.receive_message */ channel_receive_message,
+        /*.receive_event */ channel_receive_event
+};
+
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session,
+                                                                                                        switch_event_t *var_event,
+                                                                                                        switch_caller_profile_t *outbound_profile,
+                                                                                                        switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags)
+{
+        private_t *tech_pvt = NULL;
+        if ((*new_session = switch_core_session_request(gsmopen_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, pool)) != 0) {
+                switch_channel_t *channel = NULL;
+                switch_caller_profile_t *caller_profile;
+                char *rdest;
+                int found = 0;
+                char interface_name[256];
+
+                DEBUGA_GSMOPEN(&quot;1 SESSION_REQUEST %s\n&quot;, GSMOPEN_P_LOG, switch_core_session_get_uuid(*new_session));
+                switch_core_session_add_stream(*new_session, NULL);
+
+
+                if (!switch_strlen_zero(outbound_profile-&gt;destination_number)) {
+                        int i;
+                        char *slash;
+
+                        switch_copy_string(interface_name, outbound_profile-&gt;destination_number, 255);
+                        slash = strrchr(interface_name, '/');
+                        *slash = '\0';
+
+                        switch_mutex_lock(globals.mutex);
+                        if (strncmp(&quot;ANY&quot;, interface_name, strlen(interface_name)) == 0 || strncmp(&quot;RR&quot;, interface_name, strlen(interface_name)) == 0) {
+                                /* we've been asked for the &quot;ANY&quot; interface, let's find the first idle interface */
+                                //DEBUGA_GSMOPEN(&quot;Finding one available gsmopen interface\n&quot;, GSMOPEN_P_LOG);
+                                //tech_pvt = find_available_gsmopen_interface(NULL);
+                                //if (tech_pvt)
+                                //found = 1;
+                                //} else if (strncmp(&quot;RR&quot;, interface_name, strlen(interface_name)) == 0) {
+                                /* Find the first idle interface using Round Robin */
+                                DEBUGA_GSMOPEN(&quot;Finding one available gsmopen interface RR\n&quot;, GSMOPEN_P_LOG);
+                                tech_pvt = find_available_gsmopen_interface_rr(NULL);
+                                if (tech_pvt)
+                                        found = 1;
+                                DEBUGA_GSMOPEN(&quot;FOUND one available gsmopen interface RR\n&quot;, GSMOPEN_P_LOG);
+                        }
+
+                        for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                                /* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the &quot;ANY&quot; interface */
+                                if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                        &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, interface_name, strlen(interface_name)) == 0)) {
+                                        if (strlen(globals.GSMOPEN_INTERFACES[i].session_uuid_str)) {
+                                                DEBUGA_GSMOPEN
+                                                        (&quot;globals.GSMOPEN_INTERFACES[%d].name=|||%s||| session_uuid_str=|||%s||| is BUSY\n&quot;,
+                                                         GSMOPEN_P_LOG, i, globals.GSMOPEN_INTERFACES[i].name, globals.GSMOPEN_INTERFACES[i].session_uuid_str);
+                                                DEBUGA_GSMOPEN(&quot;1 SESSION_DESTROY %s\n&quot;, GSMOPEN_P_LOG, switch_core_session_get_uuid(*new_session));
+                                                switch_core_session_destroy(new_session);
+                                                switch_mutex_unlock(globals.mutex);
+                                                return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                                        }
+
+                                        DEBUGA_GSMOPEN(&quot;globals.GSMOPEN_INTERFACES[%d].name=|||%s|||?\n&quot;, GSMOPEN_P_LOG, i, globals.GSMOPEN_INTERFACES[i].name);
+                                        tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                                        found = 1;
+                                        break;
+                                }
+
+                        }
+
+                } else {
+                        ERRORA(&quot;Doh! no destination number?\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(new_session);
+                        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                }
+
+                if (!found) {
+                        DEBUGA_GSMOPEN(&quot;Doh! no available interface for |||%s|||?\n&quot;, GSMOPEN_P_LOG, interface_name);
+                        DEBUGA_GSMOPEN(&quot;2 SESSION_DESTROY %s\n&quot;, GSMOPEN_P_LOG, switch_core_session_get_uuid(*new_session));
+                        switch_core_session_destroy(new_session);
+                        switch_mutex_unlock(globals.mutex);
+                        //return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                        return SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION;
+                }
+
+                channel = switch_core_session_get_channel(*new_session);
+                if (!channel) {
+                        ERRORA(&quot;Doh! no channel?\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(new_session);
+                        switch_mutex_unlock(globals.mutex);
+                        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                }
+                if (gsmopen_tech_init(tech_pvt, *new_session) != SWITCH_STATUS_SUCCESS) {
+                        ERRORA(&quot;Doh! no tech_init?\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(new_session);
+                        switch_mutex_unlock(globals.mutex);
+                        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                }
+
+
+                if (outbound_profile) {
+                        char name[128];
+
+                        snprintf(name, sizeof(name), &quot;gsmopen/%s&quot;, outbound_profile-&gt;destination_number);
+                        //snprintf(name, sizeof(name), &quot;gsmopen/%s&quot;, tech_pvt-&gt;name);
+                        switch_channel_set_name(channel, name);
+                        caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+                        switch_channel_set_caller_profile(channel, caller_profile);
+                        tech_pvt-&gt;caller_profile = caller_profile;
+                } else {
+                        ERRORA(&quot;Doh! no caller profile\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(new_session);
+                        switch_mutex_unlock(globals.mutex);
+                        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+                }
+
+                tech_pvt-&gt;ob_calls++;
+
+                rdest = strchr(caller_profile-&gt;destination_number, '/');
+                *rdest++ = '\0';
+
+                //gsmopen_call(tech_pvt, rdest, 30);
+
+                switch_copy_string(tech_pvt-&gt;session_uuid_str, switch_core_session_get_uuid(*new_session), sizeof(tech_pvt-&gt;session_uuid_str));
+                caller_profile = tech_pvt-&gt;caller_profile;
+                caller_profile-&gt;destination_number = rdest;
+
+                switch_channel_set_flag(channel, CF_OUTBOUND);
+                switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+                switch_channel_set_state(channel, CS_INIT);
+                gsmopen_call(tech_pvt, rdest, 30);
+                switch_mutex_unlock(globals.mutex);
+                return SWITCH_CAUSE_SUCCESS;
+        }
+
+        ERRORA(&quot;Doh! no new_session\n&quot;, GSMOPEN_P_LOG);
+        return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+/*!
+ * \brief This thread runs during a call, and monitor the interface for signaling, like hangup, caller id, etc most of signaling is handled inside the gsmopen_signaling_read function
+ *
+ */
+/* BEGIN: Changes heres */
+
+
+static switch_status_t load_config(int reload_type)
+/* END: Changes heres */
+{
+        char *cf = &quot;gsmopen.conf&quot;;
+        switch_xml_t cfg, xml, global_settings, param, interfaces, myinterface;
+        private_t *tech_pvt = NULL;
+
+        switch_mutex_init(&amp;globals.mutex, SWITCH_MUTEX_NESTED, gsmopen_module_pool);
+        if (!(xml = switch_xml_open_cfg(cf, &amp;cfg, NULL))) {
+                ERRORA(&quot;open of %s failed\n&quot;, GSMOPEN_P_LOG, cf);
+                running = 0;
+                switch_xml_free(xml);
+                return SWITCH_STATUS_TERM;
+        }
+
+        switch_mutex_lock(globals.mutex);
+        if ((global_settings = switch_xml_child(cfg, &quot;global_settings&quot;))) {
+                for (param = switch_xml_child(global_settings, &quot;param&quot;); param; param = param-&gt;next) {
+                        char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
+                        char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
+
+                        if (!strcasecmp(var, &quot;debug&quot;)) {
+                                DEBUGA_GSMOPEN(&quot;globals.debug=%d\n&quot;, GSMOPEN_P_LOG, globals.debug);
+                                globals.debug = atoi(val);
+                                DEBUGA_GSMOPEN(&quot;globals.debug=%d\n&quot;, GSMOPEN_P_LOG, globals.debug);
+                        } else if (!strcasecmp(var, &quot;hold-music&quot;)) {
+                                switch_set_string(globals.hold_music, val);
+                                DEBUGA_GSMOPEN(&quot;globals.hold_music=%s\n&quot;, GSMOPEN_P_LOG, globals.hold_music);
+                        } else if (!strcmp(var, &quot;dialplan&quot;)) {
+                                set_global_dialplan(val);
+                                DEBUGA_GSMOPEN(&quot;globals.dialplan=%s\n&quot;, GSMOPEN_P_LOG, globals.dialplan);
+                        } else if (!strcmp(var, &quot;destination&quot;)) {
+                                set_global_destination(val);
+                                DEBUGA_GSMOPEN(&quot;globals.destination=%s\n&quot;, GSMOPEN_P_LOG, globals.destination);
+                        } else if (!strcmp(var, &quot;context&quot;)) {
+                                set_global_context(val);
+                                DEBUGA_GSMOPEN(&quot;globals.context=%s\n&quot;, GSMOPEN_P_LOG, globals.context);
+
+                        }
+
+                }
+        }
+
+        if ((interfaces = switch_xml_child(cfg, &quot;per_interface_settings&quot;))) {
+                int i = 0;
+
+                for (myinterface = switch_xml_child(interfaces, &quot;interface&quot;); myinterface; myinterface = myinterface-&gt;next) {
+                        char *id = (char *) switch_xml_attr(myinterface, &quot;id&quot;);
+                        char *name = (char *) switch_xml_attr(myinterface, &quot;name&quot;);
+                        char *context = &quot;default&quot;;
+                        char *dialplan = &quot;XML&quot;;
+                        char *destination = &quot;5000&quot;;
+                        char *controldevice_name = &quot;/dev/ttyACM0&quot;;
+                        char *digit_timeout = NULL;
+                        char *max_digits = NULL;
+                        char *hotline = NULL;
+                        char *dial_regex = NULL;
+                        char *hold_music = NULL;
+                        char *fail_dial_regex = NULL;
+                        char *enable_callerid = &quot;true&quot;;
+
+
+                        char *at_dial_pre_number= &quot;ATD&quot;;
+                        char *at_dial_post_number= &quot;;&quot;;
+                        char *at_dial_expect= &quot;OK&quot;;
+                        char *at_hangup= &quot;ATH&quot;;
+                        char *at_hangup_expect= &quot;OK&quot;;
+                        char *at_answer= &quot;ATA&quot;;
+                        char *at_answer_expect= &quot;OK&quot;;
+                        char *at_send_dtmf= &quot;AT+VTS&quot;;
+                        char *at_preinit_1= &quot;&quot;;
+                        char *at_preinit_1_expect= &quot;&quot;;
+                        char *at_preinit_2= &quot;&quot;;
+                        char *at_preinit_2_expect= &quot;&quot;;
+                        char *at_preinit_3= &quot;&quot;;
+                        char *at_preinit_3_expect= &quot;&quot;;
+                        char *at_preinit_4= &quot;&quot;;
+                        char *at_preinit_4_expect= &quot;&quot;;
+                        char *at_preinit_5= &quot;&quot;;
+                        char *at_preinit_5_expect= &quot;&quot;;
+                        char *at_postinit_1= &quot;at+cmic=0,9&quot;;
+                        char *at_postinit_1_expect= &quot;OK&quot;;
+                        char *at_postinit_2= &quot;AT+CKPD=\&quot;EEE\&quot;&quot;;
+                        char *at_postinit_2_expect= &quot;OK&quot;;
+                        char *at_postinit_3= &quot;AT+CSSN=1,0&quot;;
+                        char *at_postinit_3_expect= &quot;OK&quot;;
+                        char *at_postinit_4= &quot;at+sidet=0&quot;;
+                        char *at_postinit_4_expect= &quot;OK&quot;;
+                        char *at_postinit_5= &quot;at+clvl=99&quot;;
+                        char *at_postinit_5_expect= &quot;OK&quot;;
+                        char *at_query_battchg= &quot;AT+CBC&quot;;
+                        char *at_query_battchg_expect= &quot;OK&quot;;
+                        char *at_query_signal= &quot;AT+CSQ&quot;;
+                        char *at_query_signal_expect= &quot;OK&quot;;
+                        char *at_call_idle= &quot;+MCST: 1&quot;;
+                        char *at_call_incoming= &quot;+MCST: 2&quot;;
+                        char *at_call_active= &quot;+CSSI: 7&quot;;
+                        char *at_call_failed= &quot;+MCST: 65&quot;;
+                        char *at_call_calling= &quot;+CSSI: 1&quot;;
+                        char *at_indicator_noservice_string= &quot;CIEV: 2;0&quot;;
+                        char *at_indicator_nosignal_string= &quot;CIEV: 5;0&quot;;
+                        char *at_indicator_lowsignal_string= &quot;CIEV: 5;1&quot;;
+                        char *at_indicator_lowbattchg_string= &quot;CIEV: 0;1&quot;;
+                        char *at_indicator_nobattchg_string= &quot;CIEV: 0;0&quot;;
+                        char *at_indicator_callactive_string= &quot;CIEV: 3;1&quot;;
+                        char *at_indicator_nocallactive_string= &quot;CIEV: 3;0&quot;;
+                        char *at_indicator_nocallsetup_string= &quot;CIEV: 6;0&quot;;
+                        char *at_indicator_callsetupincoming_string= &quot;CIEV: 6;1&quot;;
+                        char *at_indicator_callsetupoutgoing_string= &quot;CIEV: 6;2&quot;;
+                        char *at_indicator_callsetupremoteringing_string= &quot;CIEV: 6;3&quot;;
+                        char *sms_receiving_program= &quot;/usr/local/bin/ciapalo&quot;;
+                        char *alsacname= &quot;plughw:1&quot;;
+                        char *alsapname= &quot;plughw:1&quot;;
+                        char *at_early_audio =&quot;0&quot;;
+                        char *at_after_preinit_pause=&quot;500000&quot;;
+                        char *at_initial_pause=&quot;500000&quot;;
+                        char *at_has_clcc=&quot;0&quot;;
+                        char *at_has_ecam=&quot;0&quot;;
+                        char *alsa_period_size=&quot;160&quot;;
+                        char *alsa_periods_in_buffer=&quot;4&quot;;
+                        char *gsmopen_sound_rate=&quot;8000&quot;;
+                        char *alsa_play_is_mono=&quot;1&quot;;
+                        char *alsa_capture_is_mono=&quot;1&quot;;
+                        char *capture_boost=&quot;5&quot;;
+                        char *playback_boost=&quot;10&quot;;
+
+                        uint32_t interface_id = 0;
+                        //uint32_t to=0;
+                        //uint32_t max=0;
+                        uint32_t controldevice_speed = B115200; //FIXME TODO
+                        uint32_t controldevprotocol = PROTOCOL_AT; //FIXME TODO
+                        uint32_t running =1; //FIXME TODO
+
+
+
+                        tech_pvt = NULL;
+
+                        for (param = switch_xml_child(myinterface, &quot;param&quot;); param; param = param-&gt;next) {
+                                char *var = (char *) switch_xml_attr_soft(param, &quot;name&quot;);
+                                char *val = (char *) switch_xml_attr_soft(param, &quot;value&quot;);
+
+                                if (!strcasecmp(var, &quot;id&quot;)) {
+                                        id = val;
+                                } else if (!strcasecmp(var, &quot;name&quot;)) {
+                                        name = val;
+                                } else if (!strcasecmp(var, &quot;context&quot;)) {
+                                        context = val;
+                                } else if (!strcasecmp(var, &quot;dialplan&quot;)) {
+                                        dialplan = val;
+                                } else if (!strcasecmp(var, &quot;destination&quot;)) {
+                                        destination = val;
+                                } else if (!strcasecmp(var, &quot;controldevice_name&quot;)) {
+                                        controldevice_name = val;
+                                } else if (!strcasecmp(var, &quot;digit_timeout&quot;)) {
+                                        digit_timeout = val;
+                                } else if (!strcasecmp(var, &quot;max_digits&quot;)) {
+                                        max_digits = val;
+                                } else if (!strcasecmp(var, &quot;hotline&quot;)) {
+                                        hotline = val;
+                                } else if (!strcasecmp(var, &quot;dial_regex&quot;)) {
+                                        dial_regex = val;
+                                } else if (!strcasecmp(var, &quot;hold_music&quot;)) {
+                                        hold_music = val;
+                                } else if (!strcasecmp(var, &quot;fail_dial_regex&quot;)) {
+                                        fail_dial_regex = val;
+                                } else if (!strcasecmp(var, &quot;enable_callerid&quot;)) {
+                                        enable_callerid = val;
+                                } else if (!strcasecmp(var, &quot;at_dial_pre_number&quot;)) {
+                                        at_dial_pre_number = val;
+                                } else if (!strcasecmp(var, &quot;at_dial_post_number&quot;)) {
+                                        at_dial_post_number = val;
+                                } else if (!strcasecmp(var, &quot;at_dial_expect&quot;)) {
+                                        at_dial_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_hangup&quot;)) {
+                                        at_hangup = val;
+                                } else if (!strcasecmp(var, &quot;at_hangup_expect&quot;)) {
+                                        at_hangup_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_answer&quot;)) {
+                                        at_answer = val;
+                                } else if (!strcasecmp(var, &quot;at_answer_expect&quot;)) {
+                                        at_answer_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_send_dtmf&quot;)) {
+                                        at_send_dtmf = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_1&quot;)) {
+                                        at_preinit_1 = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_1_expect&quot;)) {
+                                        at_preinit_1_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_2&quot;)) {
+                                        at_preinit_2 = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_2_expect&quot;)) {
+                                        at_preinit_2_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_3&quot;)) {
+                                        at_preinit_3 = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_3_expect&quot;)) {
+                                        at_preinit_3_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_4&quot;)) {
+                                        at_preinit_4 = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_4_expect&quot;)) {
+                                        at_preinit_4_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_5&quot;)) {
+                                        at_preinit_5 = val;
+                                } else if (!strcasecmp(var, &quot;at_preinit_5_expect&quot;)) {
+                                        at_preinit_5_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_1&quot;)) {
+                                        at_postinit_1 = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_1_expect&quot;)) {
+                                        at_postinit_1_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_2&quot;)) {
+                                        at_postinit_2 = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_2_expect&quot;)) {
+                                        at_postinit_2_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_3&quot;)) {
+                                        at_postinit_3 = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_3_expect&quot;)) {
+                                        at_postinit_3_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_4&quot;)) {
+                                        at_postinit_4 = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_4_expect&quot;)) {
+                                        at_postinit_4_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_5&quot;)) {
+                                        at_postinit_5 = val;
+                                } else if (!strcasecmp(var, &quot;at_postinit_5_expect&quot;)) {
+                                        at_postinit_5_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_query_battchg&quot;)) {
+                                        at_query_battchg = val;
+                                } else if (!strcasecmp(var, &quot;at_query_battchg_expect&quot;)) {
+                                        at_query_battchg_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_query_signal&quot;)) {
+                                        at_query_signal = val;
+                                } else if (!strcasecmp(var, &quot;at_query_signal_expect&quot;)) {
+                                        at_query_signal_expect = val;
+                                } else if (!strcasecmp(var, &quot;at_call_idle&quot;)) {
+                                        at_call_idle = val;
+                                } else if (!strcasecmp(var, &quot;at_call_incoming&quot;)) {
+                                        at_call_incoming = val;
+                                } else if (!strcasecmp(var, &quot;at_call_active&quot;)) {
+                                        at_call_active = val;
+                                } else if (!strcasecmp(var, &quot;at_call_failed&quot;)) {
+                                        at_call_failed = val;
+                                } else if (!strcasecmp(var, &quot;at_call_calling&quot;)) {
+                                        at_call_calling = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_noservice_string&quot;)) {
+                                        at_indicator_noservice_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_nosignal_string&quot;)) {
+                                        at_indicator_nosignal_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_lowsignal_string&quot;)) {
+                                        at_indicator_lowsignal_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_lowbattchg_string&quot;)) {
+                                        at_indicator_lowbattchg_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_nobattchg_string&quot;)) {
+                                        at_indicator_nobattchg_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_callactive_string&quot;)) {
+                                        at_indicator_callactive_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_nocallactive_string&quot;)) {
+                                        at_indicator_nocallactive_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_nocallsetup_string&quot;)) {
+                                        at_indicator_nocallsetup_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_callsetupincoming_string&quot;)) {
+                                        at_indicator_callsetupincoming_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_callsetupoutgoing_string&quot;)) {
+                                        at_indicator_callsetupoutgoing_string = val;
+                                } else if (!strcasecmp(var, &quot;at_indicator_callsetupremoteringing_string&quot;)) {
+                                        at_indicator_callsetupremoteringing_string = val;
+                                } else if (!strcasecmp(var, &quot;sms_receiving_program&quot;)) {
+                                        sms_receiving_program = val;
+                                } else if (!strcasecmp(var, &quot;alsacname&quot;)) {
+                                        alsacname = val;
+                                } else if (!strcasecmp(var, &quot;alsapname&quot;)) {
+                                        alsapname = val;
+
+
+                                } else if (!strcasecmp(var, &quot;at_early_audio&quot;)) {
+                                        at_early_audio = val;
+                                } else if (!strcasecmp(var, &quot;at_after_preinit_pause&quot;)) {
+                                        at_after_preinit_pause = val;
+                                } else if (!strcasecmp(var, &quot;at_initial_pause&quot;)) {
+                                        at_initial_pause = val;
+                                } else if (!strcasecmp(var, &quot;at_has_clcc&quot;)) {
+                                        at_has_clcc = val;
+                                } else if (!strcasecmp(var, &quot;at_has_ecam&quot;)) {
+                                        at_has_ecam = val;
+                                } else if (!strcasecmp(var, &quot;alsa_period_size&quot;)) {
+                                        alsa_period_size = val;
+                                } else if (!strcasecmp(var, &quot;alsa_periods_in_buffer&quot;)) {
+                                        alsa_periods_in_buffer = val;
+                                } else if (!strcasecmp(var, &quot;gsmopen_sound_rate&quot;)) {
+                                        gsmopen_sound_rate = val;
+                                } else if (!strcasecmp(var, &quot;alsa_play_is_mono&quot;)) {
+                                        alsa_play_is_mono = val;
+                                } else if (!strcasecmp(var, &quot;alsa_capture_is_mono&quot;)) {
+                                        alsa_capture_is_mono = val;
+                                } else if (!strcasecmp(var, &quot;capture_boost&quot;)) {
+                                        capture_boost = val;
+                                } else if (!strcasecmp(var, &quot;playback_boost&quot;)) {
+                                        playback_boost = val;
+
+
+                                }
+
+                        }
+
+                        /* BEGIN: Changes here */
+                        if (reload_type == SOFT_RELOAD) {
+                                char the_interface[256];
+                                sprintf(the_interface, &quot;#%s&quot;, name);
+
+                                if (interface_exists(the_interface) == SWITCH_STATUS_SUCCESS) {
+                                        continue;
+                                }
+                        }
+                        /* END: Changes here */
+
+                        if (!id) {
+                                ERRORA(&quot;interface missing REQUIRED param 'id'\n&quot;, GSMOPEN_P_LOG);
+                                continue;
+                        }
+
+                        if (switch_is_number(id)) {
+                                interface_id = atoi(id);
+                        } else {
+                                ERRORA(&quot;interface param 'id' MUST be a number, now id='%s'\n&quot;, GSMOPEN_P_LOG, id);
+                                continue;
+                        }
+
+                        if(!switch_is_number(at_early_audio)) {
+                                ERRORA(&quot;interface param 'at_early_audio' MUST be a number, now at_early_audio='%s'\n&quot;, GSMOPEN_P_LOG, at_early_audio);
+                                continue;
+                        }
+                        if(!switch_is_number(at_after_preinit_pause)) {
+                                ERRORA(&quot;interface param 'at_after_preinit_pause' MUST be a number, now at_after_preinit_pause='%s'\n&quot;, GSMOPEN_P_LOG, at_after_preinit_pause);
+                                continue;
+                        }
+                        if(!switch_is_number(at_initial_pause)) {
+                                ERRORA(&quot;interface param 'at_initial_pause' MUST be a number, now at_initial_pause='%s'\n&quot;, GSMOPEN_P_LOG, at_initial_pause);
+                                continue;
+                        }
+                        if(!switch_is_number(at_has_clcc)) {
+                                ERRORA(&quot;interface param 'at_has_clcc' MUST be a number, now at_has_clcc='%s'\n&quot;, GSMOPEN_P_LOG, at_has_clcc);
+                                continue;
+                        }
+                        if(!switch_is_number(at_has_ecam)) {
+                                ERRORA(&quot;interface param 'at_has_ecam' MUST be a number, now at_has_ecam='%s'\n&quot;, GSMOPEN_P_LOG, at_has_ecam);
+                                continue;
+                        }
+                        if(!switch_is_number(alsa_period_size)) {
+                                ERRORA(&quot;interface param 'alsa_period_size' MUST be a number, now alsa_period_size='%s'\n&quot;, GSMOPEN_P_LOG, alsa_period_size);
+                                continue;
+                        }
+                        if(!switch_is_number(alsa_periods_in_buffer)) {
+                                ERRORA(&quot;interface param 'alsa_periods_in_buffer' MUST be a number, now alsa_periods_in_buffer='%s'\n&quot;, GSMOPEN_P_LOG, alsa_periods_in_buffer);
+                                continue;
+                        }
+                        if(!switch_is_number(gsmopen_sound_rate)) {
+                                ERRORA(&quot;interface param 'gsmopen_sound_rate' MUST be a number, now gsmopen_sound_rate='%s'\n&quot;, GSMOPEN_P_LOG, gsmopen_sound_rate);
+                                continue;
+                        }
+                        if(!switch_is_number(alsa_play_is_mono)) {
+                                ERRORA(&quot;interface param 'alsa_play_is_mono' MUST be a number, now alsa_play_is_mono='%s'\n&quot;, GSMOPEN_P_LOG, alsa_play_is_mono);
+                                continue;
+                        }
+                        if(!switch_is_number(alsa_capture_is_mono)) {
+                                ERRORA(&quot;interface param 'alsa_capture_is_mono' MUST be a number, now alsa_capture_is_mono='%s'\n&quot;, GSMOPEN_P_LOG, alsa_capture_is_mono);
+                                continue;
+                        }
+                        if(!switch_is_number(capture_boost)) {
+                                ERRORA(&quot;interface param 'capture_boost' MUST be a number, now capture_boost='%s'\n&quot;, GSMOPEN_P_LOG, capture_boost);
+                                continue;
+                        }
+                        if(!switch_is_number(playback_boost)) {
+                                ERRORA(&quot;interface param 'playback_boost' MUST be a number, now playback_boost='%s'\n&quot;, GSMOPEN_P_LOG, playback_boost);
+                                continue;
+                        }
+
+
+
+
+
+
+
+
+                        if (name) {
+                                DEBUGA_GSMOPEN(&quot;name=%s\n&quot;, GSMOPEN_P_LOG, name);
+                        }
+                        if (interface_id &amp;&amp; interface_id &lt; GSMOPEN_MAX_INTERFACES) {
+                                private_t newconf;
+                                switch_threadattr_t *gsmopen_api_thread_attr = NULL;
+
+                                memset(&amp;newconf, '\0', sizeof(newconf));
+                                globals.GSMOPEN_INTERFACES[interface_id] = newconf;
+
+
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+
+                                switch_mutex_init(&amp;globals.GSMOPEN_INTERFACES[interface_id].controldev_lock, SWITCH_MUTEX_NESTED, gsmopen_module_pool);
+
+
+                                //FIXME switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].id , id );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].name , name );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].context , context );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].dialplan , dialplan );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].destination , destination );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].controldevice_name , controldevice_name );
+                                //FIXME switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].digit_timeout , digit_timeout );
+                                //FIXME switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].max_digits , max_digits );
+                                //FIXME switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].hotline , hotline );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].dial_regex , dial_regex );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].hold_music , hold_music );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].fail_dial_regex , fail_dial_regex );
+                                //FIXME switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].enable_callerid , enable_callerid );
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_dial_pre_number, at_dial_pre_number);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_dial_post_number, at_dial_post_number);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_dial_expect, at_dial_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_hangup, at_hangup);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_hangup_expect, at_hangup_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_answer, at_answer);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_answer_expect, at_answer_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_send_dtmf, at_send_dtmf);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_1, at_preinit_1);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_1_expect, at_preinit_1_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_2, at_preinit_2);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_2_expect, at_preinit_2_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_3, at_preinit_3);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_3_expect, at_preinit_3_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_4, at_preinit_4);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_4_expect, at_preinit_4_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_5, at_preinit_5);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_preinit_5_expect, at_preinit_5_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_1, at_postinit_1);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_1_expect, at_postinit_1_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_2, at_postinit_2);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_2_expect, at_postinit_2_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_3, at_postinit_3);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_3_expect, at_postinit_3_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_4, at_postinit_4);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_4_expect, at_postinit_4_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_5, at_postinit_5);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_postinit_5_expect, at_postinit_5_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_query_battchg, at_query_battchg);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_query_battchg_expect, at_query_battchg_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_query_signal, at_query_signal);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_query_signal_expect, at_query_signal_expect);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_call_idle, at_call_idle);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_call_incoming, at_call_incoming);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_call_active, at_call_active);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_call_failed, at_call_failed);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_call_calling, at_call_calling);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_noservice_string, at_indicator_noservice_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_nosignal_string, at_indicator_nosignal_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_lowsignal_string, at_indicator_lowsignal_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_lowbattchg_string, at_indicator_lowbattchg_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_nobattchg_string, at_indicator_nobattchg_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_callactive_string, at_indicator_callactive_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_nocallactive_string, at_indicator_nocallactive_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_nocallsetup_string, at_indicator_nocallsetup_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_callsetupincoming_string, at_indicator_callsetupincoming_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_callsetupoutgoing_string, at_indicator_callsetupoutgoing_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].at_indicator_callsetupremoteringing_string, at_indicator_callsetupremoteringing_string);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].sms_receiving_program, sms_receiving_program);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].alsacname, alsacname);
+                                switch_set_string(globals.GSMOPEN_INTERFACES[interface_id].alsapname, alsapname);
+
+                                globals.GSMOPEN_INTERFACES[interface_id].at_early_audio = atoi(at_early_audio);
+                                globals.GSMOPEN_INTERFACES[interface_id].at_after_preinit_pause = atoi(at_after_preinit_pause);
+                                globals.GSMOPEN_INTERFACES[interface_id].at_initial_pause = atoi(at_initial_pause);
+                                globals.GSMOPEN_INTERFACES[interface_id].at_has_clcc = atoi(at_has_clcc);
+                                globals.GSMOPEN_INTERFACES[interface_id].at_has_ecam = atoi(at_has_ecam);
+                                globals.GSMOPEN_INTERFACES[interface_id].alsa_period_size = atoi(alsa_period_size);
+                                globals.GSMOPEN_INTERFACES[interface_id].alsa_periods_in_buffer = atoi(alsa_periods_in_buffer);
+                                globals.GSMOPEN_INTERFACES[interface_id].gsmopen_sound_rate = atoi(gsmopen_sound_rate);
+                                globals.GSMOPEN_INTERFACES[interface_id].alsa_play_is_mono = atoi(alsa_play_is_mono);
+                                globals.GSMOPEN_INTERFACES[interface_id].alsa_capture_is_mono = atoi(alsa_capture_is_mono);
+                                globals.GSMOPEN_INTERFACES[interface_id].capture_boost = atoi(capture_boost);
+                                globals.GSMOPEN_INTERFACES[interface_id].playback_boost = atoi(playback_boost);
+
+
+
+                                globals.GSMOPEN_INTERFACES[interface_id].controldevice_speed = controldevice_speed;
+                                globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol = controldevprotocol;
+                                //globals.GSMOPEN_INTERFACES[interface_id].at_early_audio = at_early_audio;
+                                //globals.GSMOPEN_INTERFACES[interface_id].at_after_preinit_pause = at_after_preinit_pause;
+                                //globals.GSMOPEN_INTERFACES[interface_id].at_initial_pause = at_initial_pause;
+                                //globals.GSMOPEN_INTERFACES[interface_id].at_has_clcc = at_has_clcc;
+                                //globals.GSMOPEN_INTERFACES[interface_id].at_has_ecam = at_has_ecam;
+                                //globals.GSMOPEN_INTERFACES[interface_id].alsa_period_size = alsa_period_size;
+                                //globals.GSMOPEN_INTERFACES[interface_id].alsa_periods_in_buffer = alsa_periods_in_buffer;
+                                //globals.GSMOPEN_INTERFACES[interface_id].gsmopen_sound_rate = gsmopen_sound_rate;
+                                //globals.GSMOPEN_INTERFACES[interface_id].alsa_play_is_mono = alsa_play_is_mono;
+                                //globals.GSMOPEN_INTERFACES[interface_id].alsa_capture_is_mono = alsa_capture_is_mono;
+                                //globals.GSMOPEN_INTERFACES[interface_id].capture_boost = capture_boost;
+                                //globals.GSMOPEN_INTERFACES[interface_id].playback_boost = playback_boost;
+                                globals.GSMOPEN_INTERFACES[interface_id].running = running; //FIXME
+
+                                gsmopen_store_boost(&quot;5&quot;, &amp;globals.GSMOPEN_INTERFACES[interface_id].capture_boost); //FIXME
+                                gsmopen_store_boost(&quot;10&quot;, &amp;globals.GSMOPEN_INTERFACES[interface_id].playback_boost); //FIXME
+
+
+                                DEBUGA_GSMOPEN(&quot;interface_id=%d globals.GSMOPEN_INTERFACES[interface_id].name=%s\n&quot;,
+                                                GSMOPEN_P_LOG, interface_id, globals.GSMOPEN_INTERFACES[interface_id].name);
+                                DEBUGA_GSMOPEN
+                                        (&quot;interface_id=%d globals.GSMOPEN_INTERFACES[interface_id].dialplan=%s\n&quot;,
+                                         GSMOPEN_P_LOG, interface_id, globals.GSMOPEN_INTERFACES[interface_id].dialplan);
+                                DEBUGA_GSMOPEN
+                                        (&quot;interface_id=%d globals.GSMOPEN_INTERFACES[interface_id].destination=%s\n&quot;,
+                                         GSMOPEN_P_LOG, interface_id, globals.GSMOPEN_INTERFACES[interface_id].destination);
+                                DEBUGA_GSMOPEN
+                                        (&quot;interface_id=%d globals.GSMOPEN_INTERFACES[interface_id].context=%s\n&quot;,
+                                         GSMOPEN_P_LOG, interface_id, globals.GSMOPEN_INTERFACES[interface_id].context);
+                                WARNINGA(&quot;STARTING interface_id=%d\n&quot;, GSMOPEN_P_LOG, interface_id);
+
+                                int res = 0;
+
+                                /* init the serial port */
+                                if (globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol != PROTOCOL_NO_SERIAL) {
+                                        globals.GSMOPEN_INTERFACES[interface_id].controldevfd =
+                                                gsmopen_serial_init(&amp;globals.GSMOPEN_INTERFACES[interface_id], globals.GSMOPEN_INTERFACES[interface_id].controldevice_speed);
+                                        if (globals.GSMOPEN_INTERFACES[interface_id].controldevfd &lt; 1) {
+                                                ERRORA(&quot;gsmopen_serial_init failed\n&quot;, GSMOPEN_P_LOG);
+                                                return SWITCH_STATUS_FALSE;
+                                                //gsmopen_sound_shutdown(tmp);
+                                                //if (tmp)
+                                                //free(tmp);
+                                                //return NULL;
+                                        }
+                                }
+
+                                /* config the phone/modem on the serial port */
+                                if (globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol != PROTOCOL_NO_SERIAL) {
+                                        //int res;
+                                        res = gsmopen_serial_config(&amp;globals.GSMOPEN_INTERFACES[interface_id]);
+                                        if (res) {
+                                                ERRORA(&quot;gsmopen_serial_config failed\n&quot;, GSMOPEN_P_LOG);
+                                                return SWITCH_STATUS_FALSE;
+                                                //gsmopen_sound_shutdown(tmp);
+                                                //if (tmp)
+                                                //free(tmp);
+                                                //return NULL;
+                                        }
+                                }
+
+
+                                switch_sleep(100000);
+                                switch_threadattr_create(&amp;gsmopen_api_thread_attr, gsmopen_module_pool);
+                                switch_threadattr_stacksize_set(gsmopen_api_thread_attr, SWITCH_THREAD_STACKSIZE);
+                                switch_thread_create(&amp;globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread, gsmopen_api_thread_attr, gsmopen_do_gsmopenapi_thread,
+                                                &amp;globals.GSMOPEN_INTERFACES[interface_id], gsmopen_module_pool);
+
+                                switch_sleep(100000);
+
+                        } else {
+                                ERRORA(&quot;interface id %d is higher than GSMOPEN_MAX_INTERFACES (%d)\n&quot;, GSMOPEN_P_LOG, interface_id, GSMOPEN_MAX_INTERFACES);
+                                continue;
+                        }
+
+                }
+
+                for (i = 0; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)) {
+                                /* How many real intterfaces */
+                                globals.real_interfaces = i + 1;
+
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+
+                                DEBUGA_GSMOPEN(&quot;i=%d globals.GSMOPEN_INTERFACES[%d].interface_id=%s\n&quot;, GSMOPEN_P_LOG, i, i, globals.GSMOPEN_INTERFACES[i].interface_id);
+                                DEBUGA_GSMOPEN(&quot;i=%d globals.GSMOPEN_INTERFACES[%d].name=%s\n&quot;, GSMOPEN_P_LOG, i, i, globals.GSMOPEN_INTERFACES[i].name);
+                                DEBUGA_GSMOPEN(&quot;i=%d globals.GSMOPEN_INTERFACES[%d].context=%s\n&quot;, GSMOPEN_P_LOG, i, i, globals.GSMOPEN_INTERFACES[i].context);
+                                DEBUGA_GSMOPEN(&quot;i=%d globals.GSMOPEN_INTERFACES[%d].dialplan=%s\n&quot;, GSMOPEN_P_LOG, i, i, globals.GSMOPEN_INTERFACES[i].dialplan);
+                                DEBUGA_GSMOPEN(&quot;i=%d globals.GSMOPEN_INTERFACES[%d].destination=%s\n&quot;, GSMOPEN_P_LOG, i, i, globals.GSMOPEN_INTERFACES[i].destination);
+                        }
+                }
+        }
+
+        switch_mutex_unlock(globals.mutex);
+        switch_xml_free(xml);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t chat_send(const char *proto, const char *from, const char *to, const char *subject, const char *body, const char *type, const char *hint)
+{
+        char *user, *host, *f_user = NULL, *f_host = NULL, *f_resource = NULL;
+        private_t * tech_pvt=NULL;
+        int i=0, found=0;
+
+        switch_assert(proto != NULL);
+
+        DEBUGA_GSMOPEN(&quot;chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n&quot;, GSMOPEN_P_LOG, proto, from, to, subject, body, type, hint?hint:&quot;NULL&quot;);
+
+        if (!to || !strlen(to)) {
+                ERRORA(&quot;Missing To: header.\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+        if ((!from &amp;&amp; !hint) || (!strlen(from) &amp;&amp; !strlen(hint)) ) {
+                ERRORA(&quot;Missing From: AND Hint: headers.\n&quot;, GSMOPEN_P_LOG);
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+        if (from &amp;&amp; (f_user = strdup(from))) {
+                if ((f_host = strchr(f_user, '@'))) {
+                        *f_host++ = '\0';
+                        if ((f_resource = strchr(f_host, '/'))) {
+                                *f_resource++ = '\0';
+                        }
+                }
+        }
+
+if(!strlen(hint)){ //FIXME FIXME FIXME
+        hint=from;
+}
+        if (to &amp;&amp; (user = strdup(to))) {
+                if ((host = strchr(user, '@'))) {
+                        *host++ = '\0';
+                }
+
+                DEBUGA_GSMOPEN(&quot;chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=%s, hint=%s)\n&quot;, GSMOPEN_P_LOG, proto, from, to, subject, body, type, hint?hint:&quot;NULL&quot;);
+                if (hint &amp;&amp; strlen(hint)) {
+                        //in hint we receive the interface name to use
+                        for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                                if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                                &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, hint, strlen(hint)) == 0)) {
+                                        tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                                        DEBUGA_GSMOPEN(&quot;Using interface: globals.GSMOPEN_INTERFACES[%d].name=|||%s|||\n&quot;, GSMOPEN_P_LOG, i, globals.GSMOPEN_INTERFACES[i].name);
+                                        found = 1;
+                                        break;
+                                }
+                        }
+                } /* FIXME add a tech_pvt member for the SIM telephone number //else {
+                //we have no a predefined interface name to use (hint is NULL), so let's choose an interface from the username (from)
+                for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].skype_user, from, strlen(from)) == 0)) {
+                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                DEBUGA_GSMOPEN(&quot;Using interface: globals.GSMOPEN_INTERFACES[%d].name=|||%s|||\n&quot;, GSMOPEN_P_LOG, i, globals.GSMOPEN_INTERFACES[i].name);
+                found = 1;
+                break;
+                }
+                }
+                }
+                */
+                if (!found) {
+                        ERRORA(&quot;ERROR: A GSMopen interface with name='%s' or one with SIM_number='%s' was not found\n&quot;, GSMOPEN_P_LOG, hint?hint:&quot;NULL&quot;, from?from:&quot;NULL&quot;);
+                        goto end;
+                } else {
+                        gsmopen_sendsms(tech_pvt, (char *)to, (char *)body);
+                }
+        }
+end:
+        switch_safe_free(user);
+        switch_safe_free(f_user);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_gsmopen_load)
+{
+        switch_api_interface_t *commands_api_interface;
+        switch_chat_interface_t *chat_interface;
+
+        gsmopen_module_pool = pool;
+        memset(&amp;globals, '\0', sizeof(globals));
+
+        running = 1;
+
+        if (load_config(FULL_RELOAD) != SWITCH_STATUS_SUCCESS) {
+                running = 0;
+                return SWITCH_STATUS_FALSE;
+        }
+
+        if (switch_event_reserve_subclass(MY_EVENT_INCOMING_SMS) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Couldn't register subclass!\n&quot;);
+                return SWITCH_STATUS_GENERR;
+        }
+
+        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+        gsmopen_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+        gsmopen_endpoint_interface-&gt;interface_name = &quot;gsmopen&quot;;
+        gsmopen_endpoint_interface-&gt;io_routines = &amp;gsmopen_io_routines;
+        gsmopen_endpoint_interface-&gt;state_handler = &amp;gsmopen_state_handlers;
+
+        if (running) {
+
+#if 0
+                SWITCH_ADD_API(commands_api_interface, &quot;sk&quot;, &quot;GSMopen console commands&quot;, sk_function, SK_SYNTAX);
+                SWITCH_ADD_API(commands_api_interface, &quot;gsmopen&quot;, &quot;GSMopen interface commands&quot;, gsmopen_function, GSMOPEN_SYNTAX);
+#endif //0
+                SWITCH_ADD_API(commands_api_interface, &quot;gsmopen_sendsms&quot;, &quot;gsmopen_sendsms interface destination_number SMS_text&quot;, sendsms_function, SENDSMS_SYNTAX);
+                SWITCH_ADD_CHAT(chat_interface, MDL_CHAT_PROTO, chat_send);
+
+                /* indicate that the module should continue to be loaded */
+                return SWITCH_STATUS_SUCCESS;
+        } else
+                return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_gsmopen_shutdown)
+{
+        int x;
+        private_t *tech_pvt = NULL;
+        switch_status_t status;
+        unsigned int howmany = 8;
+        int interface_id;
+
+        running = 0;
+
+        for (interface_id = 0; interface_id &lt; GSMOPEN_MAX_INTERFACES; interface_id++) {
+                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+
+                if (strlen(globals.GSMOPEN_INTERFACES[interface_id].name)) {
+
+
+
+                        //alsa_shutdown(&amp;globals.GSMOPEN_INTERFACES[interface_id]);
+                        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread) {
+#ifdef WIN32
+                                switch_file_write(tech_pvt-&gt;GSMopenHandles.fdesc[1], &quot;sciutati&quot;, &amp;howmany);        // let's the controldev_thread die
+#else /* WIN32 */
+                                howmany = write(tech_pvt-&gt;GSMopenHandles.fdesc[1], &quot;sciutati&quot;, howmany);
+#endif /* WIN32 */
+                        }
+                        x = 10;
+                        while (x) {                        //FIXME 0.5 seconds?
+                                x--;
+                                switch_yield(50000);
+                        }
+                        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread) {
+                                switch_thread_join(&amp;status, globals.GSMOPEN_INTERFACES[interface_id].gsmopen_signaling_thread);
+                        }
+                        if (globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread) {
+                                switch_thread_join(&amp;status, globals.GSMOPEN_INTERFACES[interface_id].gsmopen_api_thread);
+                        }
+#ifndef WIN32
+                        WARNINGA(&quot;SHUTDOWN interface_id=%d\n&quot;, GSMOPEN_P_LOG, interface_id);
+                        shutdown(tech_pvt-&gt;audiogsmopenpipe[0], 2);
+                        close(tech_pvt-&gt;audiogsmopenpipe[0]);
+                        shutdown(tech_pvt-&gt;audiogsmopenpipe[1], 2);
+                        close(tech_pvt-&gt;audiogsmopenpipe[1]);
+                        shutdown(tech_pvt-&gt;audiopipe[0], 2);
+                        close(tech_pvt-&gt;audiopipe[0]);
+                        shutdown(tech_pvt-&gt;audiopipe[1], 2);
+                        close(tech_pvt-&gt;audiopipe[1]);
+                        shutdown(tech_pvt-&gt;GSMopenHandles.fdesc[0], 2);
+                        close(tech_pvt-&gt;GSMopenHandles.fdesc[0]);
+                        shutdown(tech_pvt-&gt;GSMopenHandles.fdesc[1], 2);
+                        close(tech_pvt-&gt;GSMopenHandles.fdesc[1]);
+#endif /* WIN32 */
+                }
+
+        }
+
+        switch_event_free_subclass(MY_EVENT_INCOMING_SMS);
+
+        switch_safe_free(globals.dialplan);
+        switch_safe_free(globals.context);
+        switch_safe_free(globals.destination);
+        switch_safe_free(globals.codec_string);
+        switch_safe_free(globals.codec_rates_string);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+void *SWITCH_THREAD_FUNC gsmopen_do_gsmopenapi_thread(switch_thread_t *thread, void *obj)
+{
+        return gsmopen_do_gsmopenapi_thread_func(obj);
+}
+
+int dtmf_received(private_t * tech_pvt, char *value)
+{
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        channel = switch_core_session_get_channel(session);
+
+        if (channel) {
+
+                if (!switch_channel_test_flag(channel, CF_BRIDGED)) {
+
+                        switch_dtmf_t dtmf = { (char) value[0], switch_core_default_dtmf_duration(0) };
+                        DEBUGA_GSMOPEN(&quot;received DTMF %c on channel %s\n&quot;, GSMOPEN_P_LOG, dtmf.digit, switch_channel_get_name(channel));
+                        switch_mutex_lock(tech_pvt-&gt;flag_mutex);
+                        //FIXME: why sometimes DTMFs from here do not seems to be get by FS?
+                        switch_channel_queue_dtmf(channel, &amp;dtmf);
+                        switch_set_flag(tech_pvt, TFLAG_DTMF);
+                        switch_mutex_unlock(tech_pvt-&gt;flag_mutex);
+                } else {
+                        DEBUGA_GSMOPEN
+                                (&quot;received a DTMF on channel %s, but we're BRIDGED, so let's NOT relay it out of band\n&quot;, GSMOPEN_P_LOG, switch_channel_get_name(channel));
+                }
+        } else {
+                WARNINGA(&quot;received %c DTMF, but no channel?\n&quot;, GSMOPEN_P_LOG, value[0]);
+        }
+        switch_core_session_rwunlock(session);
+
+        return 0;
+}
+
+int new_inbound_channel(private_t * tech_pvt)
+{
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        if ((session = switch_core_session_request(gsmopen_endpoint_interface, SWITCH_CALL_DIRECTION_INBOUND, NULL)) != 0) {
+                DEBUGA_GSMOPEN(&quot;2 SESSION_REQUEST %s\n&quot;, GSMOPEN_P_LOG, switch_core_session_get_uuid(session));
+                switch_core_session_add_stream(session, NULL);
+                channel = switch_core_session_get_channel(session);
+                if (!channel) {
+                        ERRORA(&quot;Doh! no channel?\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(&amp;session);
+                        return 0;
+                }
+                if (gsmopen_tech_init(tech_pvt, session) != SWITCH_STATUS_SUCCESS) {
+                        ERRORA(&quot;Doh! no tech_init?\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(&amp;session);
+                        return 0;
+                }
+
+                if ((tech_pvt-&gt;caller_profile =
+                         switch_caller_profile_new(switch_core_session_get_pool(session), &quot;gsmopen&quot;,
+                                                                           tech_pvt-&gt;dialplan, tech_pvt-&gt;callid_name,
+                                                                           tech_pvt-&gt;callid_number, NULL, NULL, NULL, NULL, &quot;mod_gsmopen&quot;, tech_pvt-&gt;context, tech_pvt-&gt;destination)) != 0) {
+                        char name[128];
+                        //switch_snprintf(name, sizeof(name), &quot;gsmopen/%s/%s&quot;, tech_pvt-&gt;name, tech_pvt-&gt;caller_profile-&gt;destination_number);
+                        switch_snprintf(name, sizeof(name), &quot;gsmopen/%s&quot;, tech_pvt-&gt;name);
+                        switch_channel_set_name(channel, name);
+                        switch_channel_set_caller_profile(channel, tech_pvt-&gt;caller_profile);
+                }
+                switch_channel_set_state(channel, CS_INIT);
+                if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
+                        ERRORA(&quot;Error spawning thread\n&quot;, GSMOPEN_P_LOG);
+                        switch_core_session_destroy(&amp;session);
+                        return 0;
+                }
+        }
+        if (channel) {
+                //switch_channel_mark_answered(channel);
+        }
+
+        DEBUGA_GSMOPEN(&quot;new_inbound_channel\n&quot;, GSMOPEN_P_LOG);
+
+        return 0;
+}
+
+int remote_party_is_ringing(private_t * tech_pvt)
+{
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        if (!switch_strlen_zero(tech_pvt-&gt;session_uuid_str)) {
+                session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        } else {
+                ERRORA(&quot;No session???\n&quot;, GSMOPEN_P_LOG);
+                goto done;
+        }
+        if (session) {
+                channel = switch_core_session_get_channel(session);
+        } else {
+                ERRORA(&quot;No session???\n&quot;, GSMOPEN_P_LOG);
+                goto done;
+        }
+        if (channel) {
+                switch_channel_mark_ring_ready(channel);
+                DEBUGA_GSMOPEN(&quot;gsmopen_call: REMOTE PARTY RINGING\n&quot;, GSMOPEN_P_LOG);
+        } else {
+                ERRORA(&quot;No channel???\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        switch_core_session_rwunlock(session);
+
+  done:
+        return 0;
+}
+
+int remote_party_is_early_media(private_t * tech_pvt)
+{
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        if (!switch_strlen_zero(tech_pvt-&gt;session_uuid_str)) {
+                session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        } else {
+                ERRORA(&quot;No session???\n\n\n&quot;, GSMOPEN_P_LOG);
+                //TODO: kill the bastard
+                goto done;
+        }
+        if (session) {
+                channel = switch_core_session_get_channel(session);
+                switch_core_session_add_stream(session, NULL);
+        } else {
+                ERRORA(&quot;No session???\n&quot;, GSMOPEN_P_LOG);
+                //TODO: kill the bastard
+                goto done;
+        }
+        if (channel) {
+                switch_channel_mark_pre_answered(channel);
+                DEBUGA_GSMOPEN(&quot;gsmopen_call: REMOTE PARTY EARLY MEDIA\n&quot;, GSMOPEN_P_LOG);
+        } else {
+                ERRORA(&quot;No channel???\n&quot;, GSMOPEN_P_LOG);
+                //TODO: kill the bastard
+        }
+
+        switch_core_session_rwunlock(session);
+
+  done:
+        return 0;
+}
+
+int outbound_channel_answered(private_t * tech_pvt)
+{
+        switch_core_session_t *session = NULL;
+        switch_channel_t *channel = NULL;
+
+        if (!switch_strlen_zero(tech_pvt-&gt;session_uuid_str)) {
+                session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        } else {
+                ERRORA(&quot;No session???\n&quot;, GSMOPEN_P_LOG);
+                goto done;
+        }
+        if (session) {
+                channel = switch_core_session_get_channel(session);
+        } else {
+                ERRORA(&quot;No channel???\n&quot;, GSMOPEN_P_LOG);
+                goto done;
+        }
+        if (channel) {
+                switch_channel_mark_answered(channel);
+                tech_pvt-&gt;phone_callflow = GSMOPEN_STATE_UP;
+                tech_pvt-&gt;interface_state = GSMOPEN_STATE_UP;
+                //DEBUGA_GSMOPEN(&quot;gsmopen_call: %s, answered\n&quot;, GSMOPEN_P_LOG, id);
+        } else {
+                ERRORA(&quot;No channel???\n&quot;, GSMOPEN_P_LOG);
+        }
+
+        switch_core_session_rwunlock(session);
+
+  done:
+        DEBUGA_GSMOPEN(&quot;outbound_channel_answered!\n&quot;, GSMOPEN_P_LOG);
+
+        return 0;
+}
+
+private_t *find_available_gsmopen_interface_rr(private_t * tech_pvt_calling)
+{
+        private_t *tech_pvt = NULL;
+        int i;
+        //int num_interfaces = GSMOPEN_MAX_INTERFACES; 
+        //int num_interfaces = globals.real_interfaces;
+
+        switch_mutex_lock(globals.mutex);
+
+        /* Fact is the real interface start from 1 */
+        //XXX no, is just a convention, but you can have it start from 0. I do not, for aestetic reasons :-)  
+        //if (globals.next_interface == 0) globals.next_interface = 1;
+
+        for (i = 0; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                int interface_id;
+
+                interface_id = globals.next_interface;
+                //interface_id = interface_id &lt; GSMOPEN_MAX_INTERFACES ? interface_id : interface_id - GSMOPEN_MAX_INTERFACES + 1;
+                globals.next_interface = interface_id + 1 &lt; GSMOPEN_MAX_INTERFACES ? interface_id + 1 : 0;
+
+                if (strlen(globals.GSMOPEN_INTERFACES[interface_id].name)) {
+                        int gsmopen_state = 0;
+
+                        tech_pvt = &amp;globals.GSMOPEN_INTERFACES[interface_id];
+                        gsmopen_state = tech_pvt-&gt;interface_state;
+                        //DEBUGA_GSMOPEN(&quot;gsmopen interface: %d, name: %s, state: %d\n&quot;, GSMOPEN_P_LOG, interface_id, globals.GSMOPEN_INTERFACES[interface_id].name, gsmopen_state);
+                        if ((tech_pvt_calling ? strcmp(tech_pvt-&gt;gsmopen_user, tech_pvt_calling-&gt;gsmopen_user) : 1)
+                                &amp;&amp; (GSMOPEN_STATE_DOWN == gsmopen_state || 0 == gsmopen_state) &amp;&amp; (tech_pvt-&gt;phone_callflow == CALLFLOW_STATUS_FINISHED
+                                                                                                                                                                   || 0 == tech_pvt-&gt;phone_callflow)) {
+                                DEBUGA_GSMOPEN(&quot;returning as available gsmopen interface name: %s, state: %d callflow: %d\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, gsmopen_state,
+                                                           tech_pvt-&gt;phone_callflow);
+                                /*set to Dialing state to avoid other thread fint it, don't know if it is safe */
+                                //XXX no, it's not safe 
+                                if (tech_pvt_calling == NULL) {
+                                        tech_pvt-&gt;interface_state = GSMOPEN_STATE_SELECTED;
+                                }
+
+                                switch_mutex_unlock(globals.mutex);
+                                return tech_pvt;
+                        }
+                }                                                // else {
+                //DEBUGA_GSMOPEN(&quot;GSM interface: %d blank!! A hole here means we cannot hunt the last interface.\n&quot;, GSMOPEN_P_LOG, interface_id);
+                //}
+        }
+
+        switch_mutex_unlock(globals.mutex);
+        return NULL;
+}
+
+#if 0
+SWITCH_STANDARD_API(sk_function)
+{
+        char *mycmd = NULL, *argv[10] = { 0 };
+        int argc = 0;
+
+        if (globals.sk_console)
+                stream-&gt;write_function(stream, &quot;sk console is: |||%s|||\n&quot;, globals.sk_console-&gt;name);
+        else
+                stream-&gt;write_function(stream, &quot;sk console is NOT yet assigned\n&quot;);
+
+        if (!switch_strlen_zero(cmd) &amp;&amp; (mycmd = strdup(cmd))) {
+                argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (!argc || !argv[0]) {
+                stream-&gt;write_function(stream, &quot;%s&quot;, SK_SYNTAX);
+                goto end;
+        }
+
+        if (!strcasecmp(argv[0], &quot;list&quot;)) {
+                int i;
+                char next_flag_char = ' ';
+
+                stream-&gt;write_function(stream, &quot;F ID\t    Name    \tIB (F/T)    OB (F/T)\tState\tCallFlw\t\tUUID\n&quot;);
+                stream-&gt;write_function(stream, &quot;= ====\t  ========  \t=======     =======\t======\t============\t======\n&quot;);
+
+                for (i = 0; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        next_flag_char = i == globals.next_interface ? '*' : ' ';
+
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)) {
+                                stream-&gt;write_function(stream,
+                                                                           &quot;%c %d\t[%s]\t%3ld/%ld\t%6ld/%ld\t%s\t%s\t%s\n&quot;,
+                                                                           next_flag_char,
+                                                                           i, globals.GSMOPEN_INTERFACES[i].name,
+                                                                           globals.GSMOPEN_INTERFACES[i].ib_failed_calls,
+                                                                           globals.GSMOPEN_INTERFACES[i].ib_calls,
+                                                                           globals.GSMOPEN_INTERFACES[i].ob_failed_calls,
+                                                                           globals.GSMOPEN_INTERFACES[i].ob_calls,
+                                                                           interface_status[globals.GSMOPEN_INTERFACES[i].interface_state],
+                                                                           phone_callflow[globals.GSMOPEN_INTERFACES[i].phone_callflow], globals.GSMOPEN_INTERFACES[i].session_uuid_str);
+                        } else if (argc &gt; 1 &amp;&amp; !strcasecmp(argv[1], &quot;full&quot;)) {
+                                stream-&gt;write_function(stream, &quot;%c\t%d\n&quot;, next_flag_char, i);
+                        }
+
+                }
+                stream-&gt;write_function(stream, &quot;\nTotal: %d\n&quot;, globals.real_interfaces - 1);
+
+        } else if (!strcasecmp(argv[0], &quot;console&quot;)) {
+                int i;
+                int found = 0;
+
+                if (argc == 2) {
+                        for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                                /* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the &quot;ANY&quot; interface */
+                                if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                        &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, argv[1], strlen(argv[1])) == 0)) {
+                                        globals.sk_console = &amp;globals.GSMOPEN_INTERFACES[i];
+                                        stream-&gt;write_function(stream, &quot;sk console is now: globals.GSMOPEN_INTERFACES[%d].name=|||%s|||\n&quot;, i, globals.GSMOPEN_INTERFACES[i].name);
+                                        stream-&gt;write_function(stream, &quot;sk console is: |||%s|||\n&quot;, globals.sk_console-&gt;name);
+                                        found = 1;
+                                        break;
+                                }
+
+                        }
+                        if (!found)
+                                stream-&gt;write_function(stream, &quot;ERROR: A GSMopen interface with name='%s' was not found\n&quot;, argv[1]);
+                } else {
+
+                        stream-&gt;write_function(stream, &quot;-ERR Usage: sk console interface_name\n&quot;);
+                        goto end;
+                }
+
+        } else if (!strcasecmp(argv[0], &quot;ciapalino&quot;)) {
+
+/* BEGIN: Changes heres */
+        } else if (!strcasecmp(argv[0], &quot;reload&quot;)) {
+                if (load_config(SOFT_RELOAD) != SWITCH_STATUS_SUCCESS) {
+                        stream-&gt;write_function(stream, &quot;sk reload failed\n&quot;);
+                } else {
+                        stream-&gt;write_function(stream, &quot;sk reload success\n&quot;);
+                }
+        } else if (!strcasecmp(argv[0], &quot;remove&quot;)) {
+                if (argc == 2) {
+                        if (remove_interface(argv[1]) == SWITCH_STATUS_SUCCESS) {
+                                if (interface_exists(argv[1]) == SWITCH_STATUS_SUCCESS) {
+                                        stream-&gt;write_function(stream, &quot;sk remove '%s' failed\n&quot;, argv[1]);
+                                } else {
+                                        stream-&gt;write_function(stream, &quot;sk remove '%s' success\n&quot;, argv[1]);
+                                }
+                        }
+                } else {
+                        stream-&gt;write_function(stream, &quot;-ERR Usage: sk remove interface_name\n&quot;);
+                        goto end;
+                }
+/* END: Changes heres */
+
+        } else {
+        }
+  end:
+        switch_safe_free(mycmd);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_API(gsmopen_function)
+{
+        char *mycmd = NULL, *argv[10] = { 0 };
+        int argc = 0;
+        private_t *tech_pvt = NULL;
+
+        if (!switch_strlen_zero(cmd) &amp;&amp; (mycmd = strdup(cmd))) {
+                argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (!argc) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_SYNTAX);
+                goto end;
+        }
+
+        if (argc &lt; 2) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_SYNTAX);
+                goto end;
+        }
+
+        if (argv[0]) {
+                int i;
+                int found = 0;
+
+                for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        /* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the &quot;ANY&quot; interface */
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                                stream-&gt;write_function(stream, &quot;Using interface: globals.GSMOPEN_INTERFACES[%d].name=|||%s|||\n&quot;, i, globals.GSMOPEN_INTERFACES[i].name);
+                                found = 1;
+                                break;
+                        }
+
+                }
+                if (!found) {
+                        stream-&gt;write_function(stream, &quot;ERROR: A GSMopen interface with name='%s' was not found\n&quot;, argv[0]);
+                        switch_safe_free(mycmd);
+
+                        return SWITCH_STATUS_SUCCESS;
+                } else {
+                        //gsmopen_signaling_write(tech_pvt, (char *) &amp;cmd[strlen(argv[0]) + 1]);
+                }
+        } else {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_SYNTAX);
+        }
+  end:
+        switch_safe_free(mycmd);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+#endif //0
+
+int gsmopen_transfer(private_t * tech_pvt, char *id, char *value)
+{
+        char msg_to_gsmopen[1024];
+        int i;
+        int found = 0;
+        private_t *giovatech;
+        struct timeval timenow;
+
+        switch_mutex_lock(globals.mutex);
+
+        gettimeofday(&amp;timenow, NULL);
+        for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                if (strlen(globals.GSMOPEN_INTERFACES[i].name)) {
+
+                        giovatech = &amp;globals.GSMOPEN_INTERFACES[i];
+                        //NOTICA(&quot;gsmopen interface: %d, name: %s, state: %d, value=%s, giovatech-&gt;callid_number=%s, giovatech-&gt;gsmopen_user=%s\n&quot;, GSMOPEN_P_LOG, i, giovatech-&gt;name, giovatech-&gt;interface_state, value, giovatech-&gt;callid_number, giovatech-&gt;gsmopen_user);
+                        //FIXME check a timestamp here
+                        if (strlen(giovatech-&gt;gsmopen_call_id) &amp;&amp; (giovatech-&gt;interface_state != GSMOPEN_STATE_DOWN) &amp;&amp; (!strcmp(giovatech-&gt;gsmopen_user, tech_pvt-&gt;gsmopen_user)) &amp;&amp; (!strcmp(giovatech-&gt;callid_number, value)) &amp;&amp; ((((timenow.tv_sec - giovatech-&gt;answer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech-&gt;answer_time.tv_usec)) &lt; 500000)) {        //0.5sec
+                                found = 1;
+                                DEBUGA_GSMOPEN
+                                        (&quot;FOUND  (name=%s, giovatech-&gt;interface_state=%d != GSMOPEN_STATE_DOWN) &amp;&amp; (giovatech-&gt;gsmopen_user=%s == tech_pvt-&gt;gsmopen_user=%s) &amp;&amp; (giovatech-&gt;callid_number=%s == value=%s)\n&quot;,
+                                         GSMOPEN_P_LOG, giovatech-&gt;name, giovatech-&gt;interface_state, giovatech-&gt;gsmopen_user, tech_pvt-&gt;gsmopen_user, giovatech-&gt;callid_number,
+                                         value)
+                                        break;
+                        }
+                }
+        }
+
+        if (found) {
+                //tech_pvt-&gt;callid_number[0]='\0';
+                //sprintf(msg_to_gsmopen, &quot;ALTER CALL %s END HANGUP&quot;, id);
+                //gsmopen_signaling_write(tech_pvt, msg_to_gsmopen);
+                switch_mutex_unlock(globals.mutex);
+                return 0;
+        }
+        DEBUGA_GSMOPEN(&quot;NOT FOUND\n&quot;, GSMOPEN_P_LOG);
+
+        if (!tech_pvt || !tech_pvt-&gt;gsmopen_call_id || !strlen(tech_pvt-&gt;gsmopen_call_id)) {
+                /* we are not inside an active call */
+                DEBUGA_GSMOPEN(&quot;We're NO MORE in a call now %s\n&quot;, GSMOPEN_P_LOG, (tech_pvt &amp;&amp; tech_pvt-&gt;gsmopen_call_id) ? tech_pvt-&gt;gsmopen_call_id : &quot;&quot;);
+                switch_mutex_unlock(globals.mutex);
+
+        } else {
+
+                /* we're owned, we're in a call, let's try to transfer */
+                /************************** TODO
+                  Checking here if it is possible to transfer this call to Test2
+                  -&gt; GET CALL 288 CAN_TRANSFER Test2
+                  &lt;- CALL 288 CAN_TRANSFER test2 TRUE
+                 **********************************/
+
+                private_t *available_gsmopen_interface = NULL;
+
+                gettimeofday(&amp;timenow, NULL);
+                for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)) {
+
+                                giovatech = &amp;globals.GSMOPEN_INTERFACES[i];
+                                //NOTICA(&quot;gsmopen interface: %d, name: %s, state: %d, value=%s, giovatech-&gt;callid_number=%s, giovatech-&gt;gsmopen_user=%s\n&quot;, GSMOPEN_P_LOG, i, giovatech-&gt;name, giovatech-&gt;interface_state, value, giovatech-&gt;callid_number, giovatech-&gt;gsmopen_user);
+                                //FIXME check a timestamp here
+                                if (strlen(giovatech-&gt;gsmopen_transfer_call_id) &amp;&amp; (giovatech-&gt;interface_state != GSMOPEN_STATE_DOWN) &amp;&amp; (!strcmp(giovatech-&gt;gsmopen_user, tech_pvt-&gt;gsmopen_user)) &amp;&amp; (!strcmp(giovatech-&gt;transfer_callid_number, value)) &amp;&amp; ((((timenow.tv_sec - giovatech-&gt;transfer_time.tv_sec) * 1000000) + (timenow.tv_usec - giovatech-&gt;transfer_time.tv_usec)) &lt; 1000000)) {        //1.0 sec
+                                        found = 1;
+                                        DEBUGA_GSMOPEN
+                                                (&quot;FOUND  (name=%s, giovatech-&gt;interface_state=%d != GSMOPEN_STATE_DOWN) &amp;&amp; (giovatech-&gt;gsmopen_user=%s == tech_pvt-&gt;gsmopen_user=%s) &amp;&amp; (giovatech-&gt;transfer_callid_number=%s == value=%s)\n&quot;,
+                                                 GSMOPEN_P_LOG, giovatech-&gt;name, giovatech-&gt;interface_state,
+                                                 giovatech-&gt;gsmopen_user, tech_pvt-&gt;gsmopen_user, giovatech-&gt;transfer_callid_number, value)
+                                                break;
+                                }
+                        }
+                }
+
+                if (found) {
+                        //tech_pvt-&gt;callid_number[0]='\0';
+                        //sprintf(msg_to_gsmopen, &quot;ALTER CALL %s END HANGUP&quot;, id);
+                        //gsmopen_signaling_write(tech_pvt, msg_to_gsmopen);
+                        switch_mutex_unlock(globals.mutex);
+                        return 0;
+                }
+                DEBUGA_GSMOPEN(&quot;NOT FOUND\n&quot;, GSMOPEN_P_LOG);
+
+                available_gsmopen_interface = find_available_gsmopen_interface_rr(tech_pvt);
+                if (available_gsmopen_interface) {
+                        /* there is a gsmopen interface idle, let's transfer the call to it */
+
+                        //FIXME write a timestamp here
+                        gettimeofday(&amp;tech_pvt-&gt;transfer_time, NULL);
+                        switch_copy_string(tech_pvt-&gt;gsmopen_transfer_call_id, id, sizeof(tech_pvt-&gt;gsmopen_transfer_call_id) - 1);
+
+                        switch_copy_string(tech_pvt-&gt;transfer_callid_number, value, sizeof(tech_pvt-&gt;transfer_callid_number) - 1);
+
+                        DEBUGA_GSMOPEN
+                                (&quot;Let's transfer the gsmopen_call %s to %s interface (with gsmopen_user: %s), because we are already in a gsmopen call(%s)\n&quot;,
+                                 GSMOPEN_P_LOG, tech_pvt-&gt;gsmopen_call_id, available_gsmopen_interface-&gt;name, available_gsmopen_interface-&gt;gsmopen_user, id);
+
+                        //FIXME why this? the inbound call will come, eventually, on that other interface
+                        //available_gsmopen_interface-&gt;ib_calls++;
+
+                        sprintf(msg_to_gsmopen, &quot;ALTER CALL %s TRANSFER %s&quot;, id, available_gsmopen_interface-&gt;gsmopen_user);
+                        //gsmopen_signaling_write(tech_pvt, msg_to_gsmopen);
+                        if (tech_pvt-&gt;interface_state == GSMOPEN_STATE_SELECTED) {
+                                tech_pvt-&gt;interface_state = GSMOPEN_STATE_IDLE;        //we marked it GSMOPEN_STATE_SELECTED just in case it has to make an outbound call
+                        }
+                } else {
+                        /* no gsmopen interfaces idle, do nothing */
+                        DEBUGA_GSMOPEN
+                                (&quot;Not answering the gsmopen_call %s, because we are already in a gsmopen call(%s) and not transferring, because no other gsmopen interfaces are available\n&quot;,
+                                 GSMOPEN_P_LOG, id, tech_pvt-&gt;gsmopen_call_id);
+                        sprintf(msg_to_gsmopen, &quot;ALTER CALL %s END HANGUP&quot;, id);
+                        //gsmopen_signaling_write(tech_pvt, msg_to_gsmopen);
+                }
+                switch_sleep(10000);
+                DEBUGA_GSMOPEN
+                        (&quot;We have NOT answered a GSM RING from gsmopen_call %s, because we are already in a gsmopen call (%s)\n&quot;,
+                         GSMOPEN_P_LOG, id, tech_pvt-&gt;gsmopen_call_id);
+
+                switch_mutex_unlock(globals.mutex);
+        }
+        return 0;
+}
+
+void *gsmopen_do_gsmopenapi_thread_func(void *obj)
+{
+
+        private_t *tech_pvt = obj;
+        //if (gsmopen_present(GSMopenHandles)) 
+        if (1) {
+                while (running) {
+                        int res;
+                        //gsmopen_sleep(1000000); //1 sec
+                        //DEBUGA_GSMOPEN(&quot;ciao!\n&quot;, GSMOPEN_P_LOG);
+                        res = gsmopen_serial_read(tech_pvt);
+                        if (res == -1) {        //manage the graceful interface shutdown
+                                tech_pvt-&gt;controldev_dead = 1;
+                                close(tech_pvt-&gt;controldevfd);
+                                ERRORA(&quot;gsmopen_serial_monitor failed, declaring %s dead\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;controldevice_name);
+                                switch_sleep(1000000);
+                        } else if (tech_pvt-&gt;controldevprotocol != PROTOCOL_NO_SERIAL &amp;&amp; tech_pvt-&gt;interface_state == GSMOPEN_STATE_RING &amp;&amp; tech_pvt-&gt;phone_callflow != CALLFLOW_CALL_HANGUP_REQUESTED ) {
+                                WARNINGA(&quot;INCOMING RING\n&quot;, GSMOPEN_P_LOG);
+
+                                gsmopen_ring(tech_pvt);
+
+                                //FIXME gsmopen_answer(tech_pvt);
+                                //new_inbound_channel(tech_pvt);
+                                //FIXME if (!gsmopen_new(p, AST_STATE_RING, tech_pvt-&gt;context)) {
+                                //FIXME ERRORA(&quot;gsmopen_new failed! BAD BAD BAD\n&quot;, GSMOPEN_P_LOG);
+                                //FIXME }
+
+
+                        } else if (tech_pvt-&gt;controldevprotocol != PROTOCOL_NO_SERIAL &amp;&amp; tech_pvt-&gt;interface_state == GSMOPEN_STATE_DIALING) {
+                                WARNINGA(&quot;WE'RE DIALING, let's take the earlymedia\n&quot;, GSMOPEN_P_LOG);
+                                tech_pvt-&gt;interface_state = CALLFLOW_STATUS_EARLYMEDIA;
+                                remote_party_is_early_media(tech_pvt);
+                                //new_inbound_channel(tech_pvt);
+                                //FIXME if (!gsmopen_new(p, AST_STATE_RING, tech_pvt-&gt;context)) {
+                                //FIXME ERRORA(&quot;gsmopen_new failed! BAD BAD BAD\n&quot;, GSMOPEN_P_LOG);
+                                //FIXME }
+
+
+
+
+                        } else if (tech_pvt-&gt;interface_state == CALLFLOW_CALL_REMOTEANSWER) {
+                                WARNINGA(&quot;REMOTE PARTY ANSWERED\n&quot;, GSMOPEN_P_LOG);
+                                outbound_channel_answered(tech_pvt);
+                                //new_inbound_channel(tech_pvt);
+                                //FIXME if (!gsmopen_new(p, AST_STATE_RING, tech_pvt-&gt;context)) {
+                                //FIXME ERRORA(&quot;gsmopen_new failed! BAD BAD BAD\n&quot;, GSMOPEN_P_LOG);
+                                //FIXME }
+                        }
+                        usleep(100);                //give other threads a chance
+                }
+        } else {
+                ERRORA(&quot;GSM is not running, maybe crashed. Please run/restart GSM and relaunch GSMopen\n&quot;, GSMOPEN_P_LOG);
+                running = 0;
+                return NULL;
+        }
+        //running = 0;
+        return NULL;
+
+}
+#ifdef NOTDEF
+int sms_incoming(private_t * tech_pvt, char *value)
+{
+        char sms_buf[512];
+        switch_event_t *event;
+
+        DEBUGA_GSMOPEN(&quot;received SMS &gt;&gt;&gt;%s&lt;&lt;&lt; on interface %s\n&quot;, GSMOPEN_P_LOG, value, tech_pvt-&gt;name);
+
+        switch_snprintf(sms_buf, sizeof(sms_buf), &quot;incoming SMS on %s\n&quot;, tech_pvt-&gt;name);
+
+        if (switch_event_create_subclass(&amp;event, SWITCH_EVENT_CUSTOM, MY_EVENT_INCOMING_SMS) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;event_info&quot;, sms_buf);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;interface_name&quot;, tech_pvt-&gt;name);
+                switch_event_add_body(event, &quot;%s\n\n&quot;, tech_pvt-&gt;sms_message);
+                switch_event_fire(&amp;event);
+        }
+
+        return 0;
+}
+#endif// NOTDEF
+
+
+SWITCH_STANDARD_API(sendsms_function)
+{
+        char *mycmd = NULL, *argv[3] = { 0 };
+        int argc = 0;
+        private_t *tech_pvt = NULL;
+
+        if (!switch_strlen_zero(cmd) &amp;&amp; (mycmd = strdup(cmd))) {
+                argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (!argc) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, SENDSMS_SYNTAX);
+                goto end;
+        }
+
+        if (argc &lt; 3) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, SENDSMS_SYNTAX);
+                goto end;
+        }
+
+        if (argv[0]) {
+                int i;
+                int found = 0;
+
+                for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        /* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the &quot;ANY&quot; interface */
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                                stream-&gt;write_function(stream, &quot;Trying to send your SMS: interface=%s, dest=%s, text=%s\n&quot;, argv[0], argv[1], argv[2]);
+                                found = 1;
+                                break;
+                        }
+
+                }
+                if (!found) {
+                        stream-&gt;write_function(stream, &quot;ERROR: A GSMopen interface with name='%s' was not found\n&quot;, argv[0]);
+                        switch_safe_free(mycmd);
+
+                        return SWITCH_STATUS_SUCCESS;
+                } else {
+                        //gsmopen_sendsms(tech_pvt, (char *) argv[1], (char *) argv[2]);
+                        NOTICA(&quot;chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=NULL, hint=%s)\n&quot;, GSMOPEN_P_LOG, MDL_CHAT_PROTO, tech_pvt-&gt;name, argv[1], &quot;SIMPLE MESSAGE&quot;, switch_str_nil(argv[2]), tech_pvt-&gt;name);
+
+                        chat_send(MDL_CHAT_PROTO, tech_pvt-&gt;name, argv[1], &quot;SIMPLE MESSAGE&quot;, switch_str_nil(argv[2]), NULL, tech_pvt-&gt;name);
+                }
+        } else {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, SENDSMS_SYNTAX);
+        }
+  end:
+        switch_safe_free(mycmd);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+int sms_incoming(private_t * tech_pvt, char *value)
+{
+        switch_event_t *event;
+        switch_core_session_t *session = NULL;
+        int event_sent_to_esl = 0;
+
+        DEBUGA_GSMOPEN(&quot;received SMS on interface %s: %s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, tech_pvt-&gt;sms_message);
+        DEBUGA_GSMOPEN(&quot;received SMS on interface %s: DATE=%s, SENDER=%s, BODY=%s\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name, tech_pvt-&gt;sms_date, tech_pvt-&gt;sms_sender, tech_pvt-&gt;sms_body);
+
+        if (!switch_strlen_zero(tech_pvt-&gt;session_uuid_str)) {
+                session = switch_core_session_locate(tech_pvt-&gt;session_uuid_str);
+        }
+        if (switch_event_create(&amp;event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, MDL_CHAT_PROTO);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, tech_pvt-&gt;name);
+                //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;hint&quot;, tech_pvt-&gt;chatmessages[which].from_dispname);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, tech_pvt-&gt;sms_sender);
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;date&quot;, tech_pvt-&gt;sms_date); 
+                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;subject&quot;, &quot;SIMPLE MESSAGE&quot;);
+                //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;chatname&quot;, tech_pvt-&gt;chatmessages[which].chatname);
+                //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;id&quot;, tech_pvt-&gt;chatmessages[which].id);
+                switch_event_add_body(event, &quot;%s&quot;, tech_pvt-&gt;sms_body);
+                if(session){
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;during-call&quot;, &quot;true&quot;);
+                        if (switch_core_session_queue_event(session, &amp;event) != SWITCH_STATUS_SUCCESS) {
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;delivery-failure&quot;, &quot;true&quot;);
+                                switch_event_fire(&amp;event);
+                        }
+                } else { //no session
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;during-call&quot;, &quot;false&quot;);
+                        switch_event_fire(&amp;event);
+                        event_sent_to_esl=1;
+                }
+
+        }else{
+                ERRORA(&quot;cannot create event on interface %s. WHY?????\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+        }
+
+        if(!event_sent_to_esl){
+
+                if (switch_event_create(&amp;event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;proto&quot;, MDL_CHAT_PROTO);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;login&quot;, tech_pvt-&gt;name);
+                        //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;hint&quot;, tech_pvt-&gt;chatmessages[which].from_dispname);
+                        //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, tech_pvt-&gt;chatmessages[which].from_handle);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;from&quot;, tech_pvt-&gt;sms_sender);
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;date&quot;, tech_pvt-&gt;sms_date); 
+                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;subject&quot;, &quot;SIMPLE MESSAGE&quot;);
+                        //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;chatname&quot;, tech_pvt-&gt;chatmessages[which].chatname);
+                        //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;id&quot;, tech_pvt-&gt;chatmessages[which].id);
+                        switch_event_add_body(event, &quot;%s&quot;, tech_pvt-&gt;sms_body);
+                        if(session){
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;during-call&quot;, &quot;true&quot;);
+                        } else { //no session
+                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;during-call&quot;, &quot;false&quot;);
+                        }
+                        switch_event_fire(&amp;event);
+                } else{
+                        ERRORA(&quot;cannot create event on interface %s. WHY?????\n&quot;, GSMOPEN_P_LOG, tech_pvt-&gt;name);
+                }
+        }
+
+        if(session){
+                switch_core_session_rwunlock(session);
+        }
+        //memset(&amp;tech_pvt-&gt;chatmessages[which], '\0', sizeof(&amp;tech_pvt-&gt;chatmessages[which]) );
+        memset(tech_pvt-&gt;sms_message, '\0', sizeof(tech_pvt-&gt;sms_message) );
+        return 0;
+}
+
+
+#ifdef NOTDEF
+SWITCH_STANDARD_API(skypiax_chat_function)
+{
+        char *mycmd = NULL, *argv[10] = { 0 };
+        int argc = 0;
+        private_t *tech_pvt = NULL;
+        //int tried =0;
+        int i;
+        int found = 0;
+        //char skype_msg[1024];
+
+        if (!switch_strlen_zero(cmd) &amp;&amp; (mycmd = strdup(cmd))) {
+                argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (!argc) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_CHAT_SYNTAX);
+                goto end;
+        }
+
+        if (argc &lt; 3) {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_CHAT_SYNTAX);
+                goto end;
+        }
+
+        if (argv[0]) {
+                for (i = 0; !found &amp;&amp; i &lt; GSMOPEN_MAX_INTERFACES; i++) {
+                        /* we've been asked for a normal interface name, or we have not found idle interfaces to serve as the &quot;ANY&quot; interface */
+                        if (strlen(globals.GSMOPEN_INTERFACES[i].name)
+                                        &amp;&amp; (strncmp(globals.GSMOPEN_INTERFACES[i].name, argv[0], strlen(argv[0])) == 0)) {
+                                tech_pvt = &amp;globals.GSMOPEN_INTERFACES[i];
+                                stream-&gt;write_function(stream, &quot;Using interface: globals.GSMOPEN_INTERFACES[%d].name=|||%s|||\n&quot;, i, globals.GSMOPEN_INTERFACES[i].name);
+                                found = 1;
+                                break;
+                        }
+
+                }
+                if (!found) {
+                        stream-&gt;write_function(stream, &quot;ERROR: A Skypiax interface with name='%s' was not found\n&quot;, argv[0]);
+                        goto end;
+                } else {
+
+                        //chat_send(const char *proto, const char *from, const char *to, const char *subject, const char *body, const char *type, const char *hint);
+                        //chat_send(p*roto, const char *from, const char *to, const char *subject, const char *body, const char *type, const char *hint);
+                        //chat_send(MDL_CHAT_PROTO, tech_pvt-&gt;skype_user, argv[1], &quot;SIMPLE MESSAGE&quot;, switch_str_nil((char *) &amp;cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), NULL, hint);
+
+                        NOTICA(&quot;chat_send(proto=%s, from=%s, to=%s, subject=%s, body=%s, type=NULL, hint=%s)\n&quot;, GSMOPEN_P_LOG, MDL_CHAT_PROTO, tech_pvt-&gt;skype_user, argv[1], &quot;SIMPLE MESSAGE&quot;, switch_str_nil((char *) &amp;cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), tech_pvt-&gt;name);
+
+                        chat_send(MDL_CHAT_PROTO, tech_pvt-&gt;skype_user, argv[1], &quot;SIMPLE MESSAGE&quot;, switch_str_nil((char *) &amp;cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]), NULL, tech_pvt-&gt;name);
+
+                        //NOTICA(&quot;TEXT is: %s\n&quot;, GSMOPEN_P_LOG, (char *) &amp;cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1] );
+                        //snprintf(skype_msg, sizeof(skype_msg), &quot;CHAT CREATE %s&quot;, argv[1]);
+                        //skypiax_signaling_write(tech_pvt, skype_msg);
+                        //switch_sleep(100);
+                }
+        } else {
+                stream-&gt;write_function(stream, &quot;ERROR, usage: %s&quot;, GSMOPEN_CHAT_SYNTAX);
+                goto end;
+        }
+
+#ifdef NOTDEF
+
+        found=0;
+
+        while(!found){
+                for(i=0; i&lt;MAX_CHATS; i++){
+                        if(!strcmp(tech_pvt-&gt;chats[i].dialog_partner, argv[1]) ){
+                                snprintf(skype_msg, sizeof(skype_msg), &quot;CHATMESSAGE %s %s&quot;, tech_pvt-&gt;chats[i].chatname, (char *) &amp;cmd[strlen(argv[0]) + 1 + strlen(argv[1]) + 1]);
+                                skypiax_signaling_write(tech_pvt, skype_msg);
+                                found=1;
+                                break;
+                        }
+                }
+                if(found){
+                        break;
+                }
+                if(tried &gt; 1000){
+                        stream-&gt;write_function(stream, &quot;ERROR: no chat with dialog_partner='%s' was found\n&quot;, argv[1]);
+                        break;
+                }
+                switch_sleep(1000);
+        }
+#endif //NOTDEF
+
+end:
+        switch_safe_free(mycmd);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+#endif// NOTDEF
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>