chan_vpb: Fix a gcc 7 out-of-bounds complaint
[asterisk/asterisk.git] / addons / chan_mobile.c
index dd48f93..8f04af7 100644 (file)
  * \ingroup channel_drivers
  */
 
  * \ingroup channel_drivers
  */
 
+/*! \li \ref chan_mobile.c uses the configuration file \ref chan_mobile.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*!
+ * \page chan_mobile.conf chan_mobile.conf
+ * \verbinclude chan_mobile.conf.sample
+ */
+
 /*** MODULEINFO
        <depend>bluetooth</depend>
        <defaultenabled>no</defaultenabled>
 /*** MODULEINFO
        <depend>bluetooth</depend>
        <defaultenabled>no</defaultenabled>
+       <support_level>extended</support_level>
  ***/
 
 #include "asterisk.h"
 
  ***/
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
 #include <pthread.h>
 #include <signal.h>
 
 #include <pthread.h>
 #include <signal.h>
 
@@ -63,16 +71,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/app.h"
 #include "asterisk/manager.h"
 #include "asterisk/io.h"
 #include "asterisk/app.h"
 #include "asterisk/manager.h"
 #include "asterisk/io.h"
+#include "asterisk/smoother.h"
+#include "asterisk/format_cache.h"
 
 #define MBL_CONFIG "chan_mobile.conf"
 #define MBL_CONFIG_OLD "mobile.conf"
 
 #define DEVICE_FRAME_SIZE 48
 
 #define MBL_CONFIG "chan_mobile.conf"
 #define MBL_CONFIG_OLD "mobile.conf"
 
 #define DEVICE_FRAME_SIZE 48
-#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR
+#define DEVICE_FRAME_FORMAT ast_format_slin
 #define CHANNEL_FRAME_SIZE 320
 
 #define CHANNEL_FRAME_SIZE 320
 
-static struct ast_format prefformat;
-
 static int discovery_interval = 60;                    /* The device discovery interval, default 60 seconds. */
 static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */
 static sdp_session_t *sdp_session;
 static int discovery_interval = 60;                    /* The device discovery interval, default 60 seconds. */
 static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */
 static sdp_session_t *sdp_session;
@@ -137,6 +145,7 @@ struct mbl_pvt {
        int ring_sched_id;
        struct ast_dsp *dsp;
        struct ast_sched_context *sched;
        int ring_sched_id;
        struct ast_dsp *dsp;
        struct ast_sched_context *sched;
+       int hangupcause;
 
        /* flags */
        unsigned int outgoing:1;        /*!< outgoing call */
 
        /* flags */
        unsigned int outgoing:1;        /*!< outgoing call */
@@ -162,6 +171,9 @@ static int handle_response_ring(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmti(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf);
 static int handle_response_cusd(struct mbl_pvt *pvt, char *buf);
+static int handle_response_busy(struct mbl_pvt *pvt);
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf);
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf);
 static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
 
 /* CLI stuff */
 static int handle_sms_prompt(struct mbl_pvt *pvt, char *buf);
 
 /* CLI stuff */
@@ -195,17 +207,17 @@ static char *mblsendsms_desc =
 "  Message - text of the message\n";
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
 "  Message - text of the message\n";
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-               const struct ast_channel *requestor);
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor);
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
-               const struct ast_channel *requestor, void *data, int *cause);
-static int mbl_call(struct ast_channel *ast, char *dest, int timeout);
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
+static int mbl_call(struct ast_channel *ast, const char *dest, int timeout);
 static int mbl_hangup(struct ast_channel *ast);
 static int mbl_answer(struct ast_channel *ast);
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static struct ast_frame *mbl_read(struct ast_channel *ast);
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int mbl_hangup(struct ast_channel *ast);
 static int mbl_answer(struct ast_channel *ast);
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static struct ast_frame *mbl_read(struct ast_channel *ast);
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-static int mbl_devicestate(void *data);
+static int mbl_devicestate(const char *data);
 
 static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen);
 
 
 static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen);
 
@@ -331,6 +343,7 @@ struct hfp_pvt {
        struct hfp_cind cind_map;       /*!< the cind name to index mapping for this AG */
        int rsock;                      /*!< our rfcomm socket */
        int rport;                      /*!< our rfcomm port */
        struct hfp_cind cind_map;       /*!< the cind name to index mapping for this AG */
        int rsock;                      /*!< our rfcomm socket */
        int rport;                      /*!< our rfcomm port */
+       int sent_alerting;              /*!< have we sent alerting? */
 };
 
 
 };
 
 
@@ -425,6 +438,10 @@ typedef enum {
        AT_CMER,
        AT_CIND_TEST,
        AT_CUSD,
        AT_CMER,
        AT_CIND_TEST,
        AT_CUSD,
+       AT_BUSY,
+       AT_NO_DIALTONE,
+       AT_NO_CARRIER,
+       AT_ECAM,
 } at_message_t;
 
 static int at_match_prefix(char *buf, char *prefix);
 } at_message_t;
 
 static int at_match_prefix(char *buf, char *prefix);
@@ -556,7 +573,7 @@ static char *handle_cli_mobile_search(struct ast_cli_entry *e, int cmd, struct a
        max_rsp = 255;
        flags = IREQ_CACHE_FLUSH;
 
        max_rsp = 255;
        flags = IREQ_CACHE_FLUSH;
 
-       ii = alloca(max_rsp * sizeof(inquiry_info));
+       ii = ast_alloca(max_rsp * sizeof(inquiry_info));
        num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
        if (num_rsp > 0) {
                ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
        num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
        if (num_rsp > 0) {
                ast_cli(a->fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
@@ -819,9 +836,8 @@ e_return:
 */
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
 */
 
 static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num,
-               const struct ast_channel *requestor)
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
 {
 {
-
        struct ast_channel *chn;
 
        pvt->answered = 0;
        struct ast_channel *chn;
 
        pvt->answered = 0;
@@ -836,29 +852,30 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num
        ast_dsp_digitreset(pvt->dsp);
 
        chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,
        ast_dsp_digitreset(pvt->dsp);
 
        chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context,
-                       requestor ? requestor->linkedid : "", 0,
+                       assignedids, requestor, 0,
                        "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
        if (!chn) {
                goto e_return;
        }
 
                        "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff);
        if (!chn) {
                goto e_return;
        }
 
-       chn->tech = &mbl_tech;
-       ast_format_cap_add(chn->nativeformats, &prefformat);
-       ast_format_copy(&chn->rawreadformat, &prefformat);
-       ast_format_copy(&chn->rawwriteformat, &prefformat);
-       ast_format_copy(&chn->writeformat, &prefformat);
-       ast_format_copy(&chn->readformat, &prefformat);
-       chn->tech_pvt = pvt;
+       ast_channel_tech_set(chn, &mbl_tech);
+       ast_channel_nativeformats_set(chn, mbl_tech.capabilities);
+       ast_channel_set_rawreadformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_rawwriteformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_writeformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_set_readformat(chn, DEVICE_FRAME_FORMAT);
+       ast_channel_tech_pvt_set(chn, pvt);
 
        if (state == AST_STATE_RING)
 
        if (state == AST_STATE_RING)
-               chn->rings = 1;
+               ast_channel_rings_set(chn, 1);
 
 
-       ast_string_field_set(chn, language, "en");
+       ast_channel_language_set(chn, "en");
        pvt->owner = chn;
 
        if (pvt->sco_socket != -1) {
                ast_channel_set_fd(chn, 0, pvt->sco_socket);
        }
        pvt->owner = chn;
 
        if (pvt->sco_socket != -1) {
                ast_channel_set_fd(chn, 0, pvt->sco_socket);
        }
+       ast_channel_unlock(chn);
 
        return chn;
 
 
        return chn;
 
@@ -867,7 +884,7 @@ e_return:
 }
 
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
 }
 
 static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *cap,
-               const struct ast_channel *requestor, void *data, int *cause)
+               const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
 {
 
        struct ast_channel *chn = NULL;
 {
 
        struct ast_channel *chn = NULL;
@@ -882,14 +899,14 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *
                return NULL;
        }
 
                return NULL;
        }
 
-       if (!(ast_format_cap_iscompatible(cap, &prefformat))) {
-               char tmp[256];
-               ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
+       if (ast_format_cap_iscompatible_format(cap, DEVICE_FRAME_FORMAT) == AST_FORMAT_CMP_NOT_EQUAL) {
+               struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%s'\n", ast_format_cap_get_names(cap, &codec_buf));
                *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
                return NULL;
        }
 
                *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
                return NULL;
        }
 
-       dest_dev = ast_strdupa((char *)data);
+       dest_dev = ast_strdupa(data);
 
        dest_num = strchr(dest_dev, '/');
        if (dest_num)
 
        dest_num = strchr(dest_dev, '/');
        if (dest_num)
@@ -926,7 +943,7 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *
        }
 
        ast_mutex_lock(&pvt->lock);
        }
 
        ast_mutex_lock(&pvt->lock);
-       chn = mbl_new(AST_STATE_DOWN, pvt, NULL, requestor);
+       chn = mbl_new(AST_STATE_DOWN, pvt, NULL, assignedids, requestor);
        ast_mutex_unlock(&pvt->lock);
        if (!chn) {
                ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
        ast_mutex_unlock(&pvt->lock);
        if (!chn) {
                ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
@@ -938,16 +955,15 @@ static struct ast_channel *mbl_request(const char *type, struct ast_format_cap *
 
 }
 
 
 }
 
-static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
+static int mbl_call(struct ast_channel *ast, const char *dest, int timeout)
 {
 {
-
        struct mbl_pvt *pvt;
        struct mbl_pvt *pvt;
-       char *dest_dev = NULL;
+       char *dest_dev;
        char *dest_num = NULL;
 
        char *dest_num = NULL;
 
-       dest_dev = ast_strdupa((char *)dest);
+       dest_dev = ast_strdupa(dest);
 
 
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_PHONE) {
                dest_num = strchr(dest_dev, '/');
 
        if (pvt->type == MBL_TYPE_PHONE) {
                dest_num = strchr(dest_dev, '/');
@@ -958,12 +974,12 @@ static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
                *dest_num++ = 0x00;
        }
 
                *dest_num++ = 0x00;
        }
 
-       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
-               ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast->name);
+       if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
+               ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
                return -1;
        }
 
                return -1;
        }
 
-       ast_debug(1, "Calling %s on %s\n", dest, ast->name);
+       ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
 
        ast_mutex_lock(&pvt->lock);
        if (pvt->type == MBL_TYPE_PHONE) {
 
        ast_mutex_lock(&pvt->lock);
        if (pvt->type == MBL_TYPE_PHONE) {
@@ -972,6 +988,7 @@ static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
                        ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
                        return -1;
                }
                        ast_log(LOG_ERROR, "error sending ATD command on %s\n", pvt->id);
                        return -1;
                }
+               pvt->hangupcause = 0;
                pvt->needchup = 1;
                msg_queue_push(pvt, AT_OK, AT_D);
        } else {
                pvt->needchup = 1;
                msg_queue_push(pvt, AT_OK, AT_D);
        } else {
@@ -1001,11 +1018,11 @@ static int mbl_hangup(struct ast_channel *ast)
 
        struct mbl_pvt *pvt;
 
 
        struct mbl_pvt *pvt;
 
-       if (!ast->tech_pvt) {
+       if (!ast_channel_tech_pvt(ast)) {
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
        }
                ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
                return 0;
        }
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        ast_debug(1, "[%s] hanging up device\n", pvt->id);
 
 
        ast_debug(1, "[%s] hanging up device\n", pvt->id);
 
@@ -1024,7 +1041,7 @@ static int mbl_hangup(struct ast_channel *ast)
        pvt->incoming = 0;
        pvt->needring = 0;
        pvt->owner = NULL;
        pvt->incoming = 0;
        pvt->needring = 0;
        pvt->owner = NULL;
-       ast->tech_pvt = NULL;
+       ast_channel_tech_pvt_set(ast, NULL);
 
        ast_mutex_unlock(&pvt->lock);
 
 
        ast_mutex_unlock(&pvt->lock);
 
@@ -1039,7 +1056,7 @@ static int mbl_answer(struct ast_channel *ast)
 
        struct mbl_pvt *pvt;
 
 
        struct mbl_pvt *pvt;
 
-       pvt = ast->tech_pvt;
+       pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
@@ -1058,7 +1075,7 @@ static int mbl_answer(struct ast_channel *ast)
 
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
 
 static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
 
        if (pvt->type == MBL_TYPE_HEADSET)
                return 0;
@@ -1080,7 +1097,7 @@ static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int durat
 static struct ast_frame *mbl_read(struct ast_channel *ast)
 {
 
 static struct ast_frame *mbl_read(struct ast_channel *ast)
 {
 
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
        struct ast_frame *fr = &ast_null_frame;
        int r;
 
        struct ast_frame *fr = &ast_null_frame;
        int r;
 
@@ -1096,7 +1113,7 @@ static struct ast_frame *mbl_read(struct ast_channel *ast)
 
        memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
        pvt->fr.frametype = AST_FRAME_VOICE;
 
        memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
        pvt->fr.frametype = AST_FRAME_VOICE;
-       ast_format_set(&pvt->fr.subclass.format, DEVICE_FRAME_FORMAT, 0);
+       pvt->fr.subclass.format = DEVICE_FRAME_FORMAT;
        pvt->fr.src = "Mobile";
        pvt->fr.offset = AST_FRIENDLY_OFFSET;
        pvt->fr.mallocd = 0;
        pvt->fr.src = "Mobile";
        pvt->fr.offset = AST_FRIENDLY_OFFSET;
        pvt->fr.mallocd = 0;
@@ -1134,7 +1151,7 @@ e_return:
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 
 static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 
-       struct mbl_pvt *pvt = ast->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(ast);
        struct ast_frame *f;
 
        ast_debug(3, "*** mbl_write\n");
        struct ast_frame *f;
 
        ast_debug(3, "*** mbl_write\n");
@@ -1162,7 +1179,7 @@ static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
 
 static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 {
 
-       struct mbl_pvt *pvt = newchan->tech_pvt;
+       struct mbl_pvt *pvt = ast_channel_tech_pvt(newchan);
 
        if (!pvt) {
                ast_debug(1, "fixup failed, no pvt on newchan\n");
 
        if (!pvt) {
                ast_debug(1, "fixup failed, no pvt on newchan\n");
@@ -1178,7 +1195,7 @@ static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
 
 }
 
 
 }
 
-static int mbl_devicestate(void *data)
+static int mbl_devicestate(const char *data)
 {
 
        char *device;
 {
 
        char *device;
@@ -1305,6 +1322,9 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
                        if (ast_channel_trylock(pvt->owner)) {
                                DEADLOCK_AVOIDANCE(&pvt->lock);
                        } else {
                        if (ast_channel_trylock(pvt->owner)) {
                                DEADLOCK_AVOIDANCE(&pvt->lock);
                        } else {
+                               if (pvt->hangupcause != 0) {
+                                       ast_channel_hangupcause_set(pvt->owner, pvt->hangupcause);
+                               }
                                ast_queue_hangup(pvt->owner);
                                ast_channel_unlock(pvt->owner);
                                break;
                                ast_queue_hangup(pvt->owner);
                                ast_channel_unlock(pvt->owner);
                                break;
@@ -1317,21 +1337,8 @@ static int mbl_queue_hangup(struct mbl_pvt *pvt)
 
 static int mbl_ast_hangup(struct mbl_pvt *pvt)
 {
 
 static int mbl_ast_hangup(struct mbl_pvt *pvt)
 {
-       int res = 0;
-       for (;;) {
-               if (pvt->owner) {
-                       if (ast_channel_trylock(pvt->owner)) {
-                               DEADLOCK_AVOIDANCE(&pvt->lock);
-                       } else {
-                               res = ast_hangup(pvt->owner);
-                               /* no need to unlock, ast_hangup() frees the
-                                * channel */
-                               break;
-                       }
-               } else
-                       break;
-       }
-       return res;
+       ast_hangup(pvt->owner);
+       return 0;
 }
 
 /*!
 }
 
 /*!
@@ -1378,7 +1385,7 @@ static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel)
        memset(&addr, 0, sizeof(addr));
        addr.rc_family = AF_BLUETOOTH;
        bacpy(&addr.rc_bdaddr, &src);
        memset(&addr, 0, sizeof(addr));
        addr.rc_family = AF_BLUETOOTH;
        bacpy(&addr.rc_bdaddr, &src);
-       addr.rc_channel = (uint8_t) 1;
+       addr.rc_channel = (uint8_t) 0;
        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                ast_debug(1, "bind() failed (%d).\n", errno);
                close(s);
        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                ast_debug(1, "bind() failed (%d).\n", errno);
                close(s);
@@ -1535,8 +1542,8 @@ static int rfcomm_read_and_append_char(int rsock, char **buf, size_t count, size
 }
 
 /*!
 }
 
 /*!
- * \brief Read until '\r\n'.
- * This function consumes the '\r\n' but does not add it to buf.
+ * \brief Read until \verbatim '\r\n'. \endverbatim
+ * This function consumes the \verbatim'\r\n'\endverbatim but does not add it to buf.
  */
 static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
 {
  */
 static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1563,7 +1570,7 @@ static int rfcomm_read_until_crlf(int rsock, char **buf, size_t count, size_t *i
 
 /*!
  * \brief Read the remainder of an AT SMS prompt.
 
 /*!
  * \brief Read the remainder of an AT SMS prompt.
- * \note the entire parsed string is '\r\n> '
+ * \note the entire parsed string is \verbatim '\r\n> ' \endverbatim
  *
  * By the time this function is executed, only a ' ' is left to read.
  */
  *
  * By the time this function is executed, only a ' ' is left to read.
  */
@@ -1581,7 +1588,7 @@ e_return:
 }
 
 /*!
 }
 
 /*!
- * \brief Read until a \r\nOK\r\n message.
+ * \brief Read until a \verbatim \r\nOK\r\n \endverbatim message.
  */
 static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
 {
  */
 static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1678,7 +1685,7 @@ static int rfcomm_read_until_ok(int rsock, char **buf, size_t count, size_t *in_
 
 /*!
  * \brief Read the remainder of a +CMGR message.
 
 /*!
  * \brief Read the remainder of a +CMGR message.
- * \note the entire parsed string is '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n'
+ * \note the entire parsed string is \verbatim '+CMGR: ...\r\n...\r\n...\r\n...\r\nOK\r\n' \endverbatim
  */
 static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
 {
  */
 static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1697,7 +1704,7 @@ static int rfcomm_read_cmgr(int rsock, char **buf, size_t count, size_t *in_coun
 
 /*!
  * \brief Read and AT result code.
 
 /*!
  * \brief Read and AT result code.
- * \note the entire parsed string is '\r\n<result code>\r\n'
+ * \note the entire parsed string is \verbatim '\r\n<result code>\r\n' \endverbatim
  */
 static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
 {
  */
 static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1729,13 +1736,13 @@ static int rfcomm_read_result(int rsock, char **buf, size_t count, size_t *in_co
        return 1;
 
 e_return:
        return 1;
 
 e_return:
-       ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket");
+       ast_log(LOG_ERROR, "error parsing AT result on rfcomm socket\n");
        return res;
 }
 
 /*!
  * \brief Read the remainder of an AT command.
        return res;
 }
 
 /*!
  * \brief Read the remainder of an AT command.
- * \note the entire parsed string is '<at command>\r'
+ * \note the entire parsed string is \verbatim '<at command>\r' \endverbatim
  */
 static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
 {
  */
 static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_count)
 {
@@ -1769,8 +1776,8 @@ static int rfcomm_read_command(int rsock, char **buf, size_t count, size_t *in_c
  * \endverbatim
  *
  * These formats correspond to AT result codes, AT commands, and the AT SMS
  * \endverbatim
  *
  * These formats correspond to AT result codes, AT commands, and the AT SMS
- * prompt respectively.  When messages are read the leading and trailing '\r'
- * and '\n' characters are discarded.  If the given buffer is not large enough
+ * prompt respectively.  When messages are read the leading and trailing \verbatim '\r' \endverbatim
+ * and \verbatim '\n' \endverbatim characters are discarded.  If the given buffer is not large enough
  * to hold the response, what does not fit in the buffer will be dropped.
  *
  * \note The rfcomm connection to the device is asynchronous, so there is no
  * to hold the response, what does not fit in the buffer will be dropped.
  *
  * \note The rfcomm connection to the device is asynchronous, so there is no
@@ -2032,6 +2039,14 @@ static at_message_t at_read_full(int rsock, char *buf, size_t count)
                return AT_VGS;
        } else if (at_match_prefix(buf, "+CUSD:")) {
                return AT_CUSD;
                return AT_VGS;
        } else if (at_match_prefix(buf, "+CUSD:")) {
                return AT_CUSD;
+       } else if (at_match_prefix(buf, "BUSY")) {
+               return AT_BUSY;
+       } else if (at_match_prefix(buf, "NO DIALTONE")) {
+               return AT_NO_DIALTONE;
+       } else if (at_match_prefix(buf, "NO CARRIER")) {
+               return AT_NO_CARRIER;
+       } else if (at_match_prefix(buf, "*ECAV:")) {
+               return AT_ECAM;
        } else {
                return AT_UNKNOWN;
        }
        } else {
                return AT_UNKNOWN;
        }
@@ -2076,6 +2091,12 @@ static inline const char *at_msg2str(at_message_t msg)
                return "SMS PROMPT";
        case AT_CMS_ERROR:
                return "+CMS ERROR";
                return "SMS PROMPT";
        case AT_CMS_ERROR:
                return "+CMS ERROR";
+       case AT_BUSY:
+               return "BUSY";
+       case AT_NO_DIALTONE:
+               return "NO DIALTONE";
+       case AT_NO_CARRIER:
+               return "NO CARRIER";
        /* at commands */
        case AT_A:
                return "ATA";
        /* at commands */
        case AT_A:
                return "ATA";
@@ -2103,6 +2124,8 @@ static inline const char *at_msg2str(at_message_t msg)
                return "AT+CIND=?";
        case AT_CUSD:
                return "AT+CUSD";
                return "AT+CIND=?";
        case AT_CUSD:
                return "AT+CUSD";
+       case AT_ECAM:
+               return "AT*ECAM";
        }
 }
 
        }
 }
 
@@ -2111,6 +2134,40 @@ static inline const char *at_msg2str(at_message_t msg)
  * bluetooth handsfree profile helpers
  */
 
  * bluetooth handsfree profile helpers
  */
 
+ /*!
+ * \brief Parse a ECAV event.
+ * \param hfp an hfp_pvt struct
+ * \param buf the buffer to parse (null terminated)
+ * \return -1 on error (parse error) or a ECAM value on success
+ *
+ * Example string: *ECAV: <ccid>,<ccstatus>,<calltype>[,<processid>]
+ * [,exitcause][,<number>,<type>]
+ *
+ * Example indicating busy: *ECAV: 1,7,1
+ */
+static int hfp_parse_ecav(struct hfp_pvt *hfp, char *buf)
+{
+       int ccid = 0;
+       int ccstatus = 0;
+       int calltype = 0;
+
+       if (!sscanf(buf, "*ECAV: %2d,%2d,%2d", &ccid, &ccstatus, &calltype)) {
+               ast_debug(1, "[%s] error parsing ECAV event '%s'\n", hfp->owner->id, buf);
+               return -1;
+       }
+
+       return ccstatus;
+}
+
+/*!
+ * \brief Enable Sony Erricson extensions / indications.
+ * \param hfp an hfp_pvt struct
+ */
+static int hfp_send_ecam(struct hfp_pvt *hfp)
+{
+       return rfcomm_write(hfp->rsock, "AT*ECAM=1\r");
+}
+
 /*!
  * \brief Parse a CIEV event.
  * \param hfp an hfp_pvt struct
 /*!
  * \brief Parse a CIEV event.
  * \param hfp an hfp_pvt struct
@@ -2130,7 +2187,7 @@ static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
                return HFP_CIND_NONE;
        }
 
                return HFP_CIND_NONE;
        }
 
-       if (i >= sizeof(hfp->cind_state)) {
+       if (i >= ARRAY_LEN(hfp->cind_state)) {
                ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
                return HFP_CIND_NONE;
        }
                ast_debug(2, "[%s] CIEV event index too high (%s)\n", hfp->owner->id, buf);
                return HFP_CIND_NONE;
        }
@@ -2143,7 +2200,7 @@ static int hfp_parse_ciev(struct hfp_pvt *hfp, char *buf, int *value)
  * \brief Parse a CLIP event.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
  * \brief Parse a CLIP event.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * @note buf will be modified when the CID string is parsed
+ * \note buf will be modified when the CID string is parsed
  * \return NULL on error (parse error) or a pointer to the caller id
  * information in buf
  */
  * \return NULL on error (parse error) or a pointer to the caller id
  * information in buf
  */
@@ -2189,7 +2246,7 @@ static char *hfp_parse_clip(struct hfp_pvt *hfp, char *buf)
  * \brief Parse a CMTI notification.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
  * \brief Parse a CMTI notification.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * @note buf will be modified when the CMTI message is parsed
+ * \note buf will be modified when the CMTI message is parsed
  * \return -1 on error (parse error) or the index of the new sms message
  */
 static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
  * \return -1 on error (parse error) or the index of the new sms message
  */
 static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
@@ -2214,7 +2271,7 @@ static int hfp_parse_cmti(struct hfp_pvt *hfp, char *buf)
  * \param from_number a pointer to a char pointer which will store the from
  * number
  * \param text a pointer to a char pointer which will store the message text
  * \param from_number a pointer to a char pointer which will store the from
  * number
  * \param text a pointer to a char pointer which will store the message text
- * @note buf will be modified when the CMGR message is parsed
+ * \note buf will be modified when the CMGR message is parsed
  * \retval -1 parse error
  * \retval 0 success
  */
  * \retval -1 parse error
  * \retval 0 success
  */
@@ -2240,6 +2297,7 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
                        if (buf[i] == '"') {
                                state++;
                        }
                        if (buf[i] == '"') {
                                state++;
                        }
+                       break;
                case 2: /* mark the start of the number */
                        if (from_number) {
                                *from_number = &buf[i];
                case 2: /* mark the start of the number */
                        if (from_number) {
                                *from_number = &buf[i];
@@ -2277,20 +2335,19 @@ static int hfp_parse_cmgr(struct hfp_pvt *hfp, char *buf, char **from_number, ch
  * \brief Parse a CUSD answer.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
  * \brief Parse a CUSD answer.
  * \param hfp an hfp_pvt struct
  * \param buf the buffer to parse (null terminated)
- * @note buf will be modified when the CUSD string is parsed
+ * \note buf will be modified when the CUSD string is parsed
  * \return NULL on error (parse error) or a pointer to the cusd message
  * information in buf
  */
 static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
 {
  * \return NULL on error (parse error) or a pointer to the cusd message
  * information in buf
  */
 static char *hfp_parse_cusd(struct hfp_pvt *hfp, char *buf)
 {
-       int i, state, message_start, message_end;
+       int i, message_start, message_end;
        char *cusd;
        size_t s;
 
        /* parse cusd message in the following format:
         * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
         */
        char *cusd;
        size_t s;
 
        /* parse cusd message in the following format:
         * +CUSD: 0,"100,00 EURO, valid till 01.01.2010, you are using tariff "Mega Tariff". More informations *111#."
         */
-       state = 0;
        message_start = 0;
        message_end = 0;
        s = strlen(buf);
        message_start = 0;
        message_end = 0;
        s = strlen(buf);
@@ -2613,7 +2670,7 @@ static int hfp_parse_cind_indicator(struct hfp_pvt *hfp, int group, char *indica
        int value;
 
        /* store the current indicator */
        int value;
 
        /* store the current indicator */
-       if (group >= sizeof(hfp->cind_state)) {
+       if (group >= ARRAY_LEN(hfp->cind_state)) {
                ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
                return -1;
        }
                ast_debug(1, "ignoring CIND state '%s' for group %d, we only support up to %d indicators\n", indicator, group, (int) sizeof(hfp->cind_state));
                return -1;
        }
@@ -2688,7 +2745,7 @@ static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
 {
        int i, state, group;
        size_t s;
 {
        int i, state, group;
        size_t s;
-       char *indicator = NULL, *values;
+       char *indicator = NULL;
 
        hfp->nocallsetup = 1;
 
 
        hfp->nocallsetup = 1;
 
@@ -2727,7 +2784,6 @@ static int hfp_parse_cind_test(struct hfp_pvt *hfp, char *buf)
                        }
                        break;
                case 5: /* mark the start of the value range */
                        }
                        break;
                case 5: /* mark the start of the value range */
-                       values = &buf[i];
                        state++;
                        break;
                case 6: /* find the end of the value range */
                        state++;
                        break;
                case 6: /* find the end of the value range */
@@ -2988,7 +3044,6 @@ static int sdp_search(char *addr, int profile)
 
 static sdp_session_t *sdp_register(void)
 {
 
 static sdp_session_t *sdp_register(void)
 {
-
        uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
        uint8_t rfcomm_channel = 1;
        const char *service_name = "Asterisk PABX";
        uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
        uint8_t rfcomm_channel = 1;
        const char *service_name = "Asterisk PABX";
@@ -2999,7 +3054,6 @@ static sdp_session_t *sdp_register(void)
        sdp_list_t  *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
        sdp_data_t *channel = 0;
 
        sdp_list_t  *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
        sdp_data_t *channel = 0;
 
-       int err = 0;
        sdp_session_t *session = 0;
 
        sdp_record_t *record = sdp_record_alloc();
        sdp_session_t *session = 0;
 
        sdp_record_t *record = sdp_record_alloc();
@@ -3035,8 +3089,12 @@ static sdp_session_t *sdp_register(void)
 
        if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
                ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
 
        if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
                ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
-       else
-               err = sdp_record_register(session, record, 0);
+       else {
+               if (sdp_record_register(session, record, 0) < 0) {
+                       ast_log(LOG_WARNING, "Failed to sdp_record_register error: %d\n", errno);
+                       return NULL;
+               }
+       }
 
        sdp_data_free(channel);
        sdp_list_free(rfcomm_list, 0);
 
        sdp_data_free(channel);
        sdp_list_free(rfcomm_list, 0);
@@ -3216,6 +3274,14 @@ static int handle_response_ok(struct mbl_pvt *pvt, char *buf)
                        break;
                case AT_CLIP:
                        ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
                        break;
                case AT_CLIP:
                        ast_debug(1, "[%s] caling line indication enabled\n", pvt->id);
+                       if (hfp_send_ecam(pvt->hfp) || msg_queue_push(pvt, AT_OK, AT_ECAM)) {
+                               ast_debug(1, "[%s] error enabling Sony Ericsson call monitoring extensions\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       break;
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Sony Ericsson call monitoring is active on device\n", pvt->id);
                        if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
                                ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
                                goto e_return;
                        if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
                                ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
                                goto e_return;
@@ -3347,6 +3413,21 @@ static int handle_response_error(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
                        ast_debug(1, "[%s] no SMS support\n", pvt->id);
                        break;
                        ast_debug(1, "[%s] error setting CNMI\n", pvt->id);
                        ast_debug(1, "[%s] no SMS support\n", pvt->id);
                        break;
+               case AT_ECAM:
+                       ast_debug(1, "[%s] Mobile does not support Sony Ericsson extensions\n", pvt->id);
+
+                       /* this is not a fatal error, let's continue with the initialization */
+
+                       if (hfp_send_vgs(pvt->hfp, 15) || msg_queue_push(pvt, AT_OK, AT_VGS)) {
+                               ast_debug(1, "[%s] error synchronizing gain settings\n", pvt->id);
+                               goto e_return;
+                       }
+
+                       pvt->timeout = -1;
+                       pvt->hfp->initialized = 1;
+                       ast_verb(3, "Bluetooth Device %s initialized and ready.\n", pvt->id);
+
+                       break;
                /* end initialization stuff */
 
                case AT_A:
                /* end initialization stuff */
 
                case AT_A:
@@ -3442,6 +3523,9 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                case HFP_CIND_CALLSETUP_NONE:
                        if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
                                if (pvt->owner) {
                case HFP_CIND_CALLSETUP_NONE:
                        if (pvt->hfp->cind_state[pvt->hfp->cind_map.call] != HFP_CIND_CALL_ACTIVE) {
                                if (pvt->owner) {
+                                       if (pvt->hfp->sent_alerting == 1) {
+                                               handle_response_busy(pvt);
+                                       }
                                        if (mbl_queue_hangup(pvt)) {
                                                ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
                                                return -1;
                                        if (mbl_queue_hangup(pvt)) {
                                                ast_log(LOG_ERROR, "[%s] error queueing hangup, disconnectiong...\n", pvt->id);
                                                return -1;
@@ -3460,6 +3544,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        break;
                case HFP_CIND_CALLSETUP_OUTGOING:
                        if (pvt->outgoing) {
                        break;
                case HFP_CIND_CALLSETUP_OUTGOING:
                        if (pvt->outgoing) {
+                               pvt->hfp->sent_alerting = 0;
                                ast_debug(1, "[%s] outgoing call\n", pvt->id);
                        } else {
                                ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
                                ast_debug(1, "[%s] outgoing call\n", pvt->id);
                        } else {
                                ast_verb(3, "[%s] user dialed from handset, disconnecting\n", pvt->id);
@@ -3470,6 +3555,7 @@ static int handle_response_ciev(struct mbl_pvt *pvt, char *buf)
                        if (pvt->outgoing) {
                                ast_debug(1, "[%s] remote alerting\n", pvt->id);
                                mbl_queue_control(pvt, AST_CONTROL_RINGING);
                        if (pvt->outgoing) {
                                ast_debug(1, "[%s] remote alerting\n", pvt->id);
                                mbl_queue_control(pvt, AST_CONTROL_RINGING);
+                               pvt->hfp->sent_alerting = 1;
                        }
                        break;
                }
                        }
                        break;
                }
@@ -3502,7 +3588,7 @@ static int handle_response_clip(struct mbl_pvt *pvt, char *buf)
                        ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
                }
 
                        ast_debug(1, "[%s] error parsing CLIP: %s\n", pvt->id, buf);
                }
 
-               if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL))) {
+               if (!(chan = mbl_new(AST_STATE_RING, pvt, clip, NULL, NULL))) {
                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                        hfp_send_chup(pvt->hfp);
                        msg_queue_push(pvt, AT_OK, AT_CHUP);
                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                        hfp_send_chup(pvt->hfp);
                        msg_queue_push(pvt, AT_OK, AT_CHUP);
@@ -3592,12 +3678,12 @@ static int handle_response_cmgr(struct mbl_pvt *pvt, char *buf)
                pvt->incoming_sms = 0;
 
                /* XXX this channel probably does not need to be associated with this pvt */
                pvt->incoming_sms = 0;
 
                /* XXX this channel probably does not need to be associated with this pvt */
-               if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL))) {
+               if (!(chan = mbl_new(AST_STATE_DOWN, pvt, NULL, NULL, NULL))) {
                        ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
                        return -1;
                }
 
                        ast_debug(1, "[%s] error creating sms message channel, disconnecting\n", pvt->id);
                        return -1;
                }
 
-               strcpy(chan->exten, "sms");
+               ast_channel_exten_set(chan, "sms");
                pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
                pbx_builtin_setvar_helper(chan, "SMSTXT", text);
 
                pbx_builtin_setvar_helper(chan, "SMSSRC", from_number);
                pbx_builtin_setvar_helper(chan, "SMSTXT", text);
 
@@ -3664,12 +3750,56 @@ static int handle_response_cusd(struct mbl_pvt *pvt, char *buf)
        return 0;
 }
 
        return 0;
 }
 
+/*!
+ * \brief Handle BUSY messages.
+ * \param pvt a mbl_pvt structure
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_busy(struct mbl_pvt *pvt)
+{
+       pvt->hangupcause = AST_CAUSE_USER_BUSY;
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_BUSY);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO DIALTONE messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_dialtone(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO DIALTONE\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
+/*!
+ * \brief Handle NO CARRIER messages.
+ * \param pvt a mbl_pvt structure
+ * \param buf a null terminated buffer containing an AT message
+ * \retval 0 success
+ * \retval -1 error
+ */
+static int handle_response_no_carrier(struct mbl_pvt *pvt, char *buf)
+{
+       ast_verb(1, "[%s] mobile reports NO CARRIER\n", pvt->id);
+       pvt->needchup = 1;
+       mbl_queue_control(pvt, AST_CONTROL_CONGESTION);
+       return 0;
+}
+
 
 static void *do_monitor_phone(void *data)
 {
        struct mbl_pvt *pvt = (struct mbl_pvt *)data;
        struct hfp_pvt *hfp = pvt->hfp;
 
 static void *do_monitor_phone(void *data)
 {
        struct mbl_pvt *pvt = (struct mbl_pvt *)data;
        struct hfp_pvt *hfp = pvt->hfp;
-       char buf[256];
+       char buf[350];
        int t;
        at_message_t at_msg;
        struct msg_queue_entry *entry;
        int t;
        at_message_t at_msg;
        struct msg_queue_entry *entry;
@@ -3723,10 +3853,7 @@ static void *do_monitor_phone(void *data)
                }
 
                if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
                }
 
                if ((at_msg = at_read_full(hfp->rsock, buf, sizeof(buf))) < 0) {
-                       /* XXX gnu specific strerror_r is assummed here, this
-                        * is not really safe.  See the strerror(3) man page
-                        * for more info. */
-                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        break;
                }
 
                        break;
                }
 
@@ -3822,6 +3949,40 @@ static void *do_monitor_phone(void *data)
                        }
                        ast_mutex_unlock(&pvt->lock);
                        break;
                        }
                        ast_mutex_unlock(&pvt->lock);
                        break;
+               case AT_BUSY:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_busy(pvt)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_DIALTONE:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_dialtone(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_NO_CARRIER:
+                       ast_mutex_lock(&pvt->lock);
+                       if (handle_response_no_carrier(pvt, buf)) {
+                               ast_mutex_unlock(&pvt->lock);
+                               goto e_cleanup;
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
+               case AT_ECAM:
+                       ast_mutex_lock(&pvt->lock);
+                       if (hfp_parse_ecav(hfp, buf) == 7) {
+                               if (handle_response_busy(pvt)) {
+                                       ast_mutex_unlock(&pvt->lock);
+                                       goto e_cleanup;
+                               }
+                       }
+                       ast_mutex_unlock(&pvt->lock);
+                       break;
                case AT_UNKNOWN:
                        ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
                        break;
                case AT_UNKNOWN:
                        ast_debug(1, "[%s] ignoring unknown message: %s\n", pvt->id, buf);
                        break;
@@ -3829,7 +3990,7 @@ static void *do_monitor_phone(void *data)
                        ast_debug(1, "[%s] error parsing message\n", pvt->id);
                        goto e_cleanup;
                case AT_READ_ERROR:
                        ast_debug(1, "[%s] error parsing message\n", pvt->id);
                        goto e_cleanup;
                case AT_READ_ERROR:
-                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror_r(errno, buf, sizeof(buf)), errno);
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        goto e_cleanup;
                default:
                        break;
                        goto e_cleanup;
                default:
                        break;
@@ -3907,11 +4068,7 @@ static void *do_monitor_headset(void *data)
                        continue;
 
                if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
                        continue;
 
                if ((at_msg = at_read_full(pvt->rfcomm_socket, buf, sizeof(buf))) < 0) {
-                       if (strerror_r(errno, buf, sizeof(buf)))
-                               ast_debug(1, "[%s] error reading from device\n", pvt->id);
-                       else
-                               ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, buf, errno);
-
+                       ast_debug(1, "[%s] error reading from device: %s (%d)\n", pvt->id, strerror(errno), errno);
                        goto e_cleanup;
                }
                ast_debug(1, "[%s] %s\n", pvt->id, buf);
                        goto e_cleanup;
                }
                ast_debug(1, "[%s] %s\n", pvt->id, buf);
@@ -3973,7 +4130,7 @@ static void *do_monitor_headset(void *data)
 
                                pvt->incoming = 1;
 
 
                                pvt->incoming = 1;
 
-                               if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL))) {
+                               if (!(chan = mbl_new(AST_STATE_UP, pvt, NULL, NULL, NULL))) {
                                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                                        ast_mutex_unlock(&pvt->lock);
                                        goto e_cleanup;
                                        ast_log(LOG_ERROR, "[%s] unable to allocate channel for incoming call\n", pvt->id);
                                        ast_mutex_unlock(&pvt->lock);
                                        goto e_cleanup;
@@ -3981,7 +4138,7 @@ static void *do_monitor_headset(void *data)
 
                                ast_channel_set_fd(chan, 0, pvt->sco_socket);
 
 
                                ast_channel_set_fd(chan, 0, pvt->sco_socket);
 
-                               ast_copy_string(chan->exten, "s", AST_MAX_EXTENSION);
+                               ast_channel_exten_set(chan, "s");
                                if (ast_pbx_start(chan)) {
                                        ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
                                        ast_hangup(chan);
                                if (ast_pbx_start(chan)) {
                                        ast_log(LOG_ERROR, "[%s] unable to start pbx on incoming call\n", pvt->id);
                                        ast_hangup(chan);
@@ -4097,18 +4254,17 @@ static void *do_discovery(void *data)
 static void *do_sco_listen(void *data)
 {
        struct adapter_pvt *adapter = (struct adapter_pvt *) data;
 static void *do_sco_listen(void *data)
 {
        struct adapter_pvt *adapter = (struct adapter_pvt *) data;
-       int res;
 
        while (!check_unloading()) {
                /* check for new sco connections */
 
        while (!check_unloading()) {
                /* check for new sco connections */
-               if ((res = ast_io_wait(adapter->accept_io, 0)) == -1) {
+               if (ast_io_wait(adapter->accept_io, 0) == -1) {
                        /* handle errors */
                        ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
                        break;
                }
 
                /* handle audio data */
                        /* handle errors */
                        ast_log(LOG_ERROR, "ast_io_wait() failed for adapter %s\n", adapter->id);
                        break;
                }
 
                /* handle audio data */
-               if ((res = ast_io_wait(adapter->io, 1)) == -1) {
+               if (ast_io_wait(adapter->io, 1) == -1) {
                        ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
                        break;
                }
                        ast_log(LOG_ERROR, "ast_io_wait() failed for audio on adapter %s\n", adapter->id);
                        break;
                }
@@ -4531,7 +4687,8 @@ static int unload_module(void)
        if (sdp_session)
                sdp_close(sdp_session);
 
        if (sdp_session)
                sdp_close(sdp_session);
 
-       mbl_tech.capabilities = ast_format_cap_destroy(mbl_tech.capabilities);
+       ao2_ref(mbl_tech.capabilities, -1);
+       mbl_tech.capabilities = NULL;
        return 0;
 }
 
        return 0;
 }
 
@@ -4540,16 +4697,20 @@ static int load_module(void)
 
        int dev_id, s;
 
 
        int dev_id, s;
 
-       if (!(mbl_tech.capabilities = ast_format_cap_alloc())) {
+       if (!(mbl_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
                return AST_MODULE_LOAD_DECLINE;
        }
                return AST_MODULE_LOAD_DECLINE;
        }
-       ast_format_set(&prefformat, DEVICE_FRAME_FORMAT, 0);
-       ast_format_cap_add(mbl_tech.capabilities, &prefformat);
+
+       ast_format_cap_append(mbl_tech.capabilities, DEVICE_FRAME_FORMAT, 0);
        /* Check if we have Bluetooth, no point loading otherwise... */
        dev_id = hci_get_route(NULL);
        /* Check if we have Bluetooth, no point loading otherwise... */
        dev_id = hci_get_route(NULL);
+
        s = hci_open_dev(dev_id);
        if (dev_id < 0 || s < 0) {
                ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
        s = hci_open_dev(dev_id);
        if (dev_id < 0 || s < 0) {
                ast_log(LOG_ERROR, "No Bluetooth devices found. Not loading module.\n");
+               ao2_ref(mbl_tech.capabilities, -1);
+               mbl_tech.capabilities = NULL;
+               hci_close_dev(s);
                return AST_MODULE_LOAD_DECLINE;
        }
 
                return AST_MODULE_LOAD_DECLINE;
        }
 
@@ -4557,6 +4718,8 @@ static int load_module(void)
 
        if (mbl_load_config()) {
                ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
 
        if (mbl_load_config()) {
                ast_log(LOG_ERROR, "Errors reading config file %s. Not loading module.\n", MBL_CONFIG);
+               ao2_ref(mbl_tech.capabilities, -1);
+               mbl_tech.capabilities = NULL;
                return AST_MODULE_LOAD_DECLINE;
        }
 
                return AST_MODULE_LOAD_DECLINE;
        }
 
@@ -4581,14 +4744,14 @@ static int load_module(void)
        return AST_MODULE_LOAD_SUCCESS;
 
 e_cleanup:
        return AST_MODULE_LOAD_SUCCESS;
 
 e_cleanup:
-       if (sdp_session)
-               sdp_close(sdp_session);
+       unload_module();
 
 
-       return AST_MODULE_LOAD_FAILURE;
+       return AST_MODULE_LOAD_DECLINE;
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
 }
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Bluetooth Mobile Device Channel Driver",
-               .load = load_module,
-               .unload = unload_module,
-               .load_pri = AST_MODPRI_CHANNEL_DRIVER,
+       .support_level = AST_MODULE_SUPPORT_EXTENDED,
+       .load = load_module,
+       .unload = unload_module,
+       .load_pri = AST_MODPRI_CHANNEL_DRIVER,
 );
 );