Changeset 14337


Ignore:
Timestamp:
2009-02-01T09:13:16+01:00 (9 years ago)
Author:
zandbelt
Message:

update chan_mobile to r725 based on backport patch from http://www.asterisk.org/node/48557

Location:
packages/net
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • packages/net/asterisk-1.4.x/Makefile

    r13712 r14337  
    1010 
    1111PKG_NAME:=asterisk 
    12 PKG_VERSION:=1.4.22 
    13 PKG_RELEASE:=2 
     12PKG_VERSION:=1.4.23.1 
     13PKG_RELEASE:=1 
    1414 
    1515PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 
    1616PKG_SOURCE_URL:=http://downloads.digium.com/pub/asterisk/releases/ 
    17 #PKG_MD5SUM:=c4cf69eb6eae3105806b08d3efc28ec7 
    18 PKG_MD5SUM:=7626febc4a01e16e012dfccb9e4ab9d2 
     17PKG_MD5SUM:=4788954a93f5fbf78e55e2aa6e03329f 
    1918 
    2019PKG_BUILD_DEPENDS:= libopenh323 pwlib 
  • packages/net/asterisk-1.4.x/patches/023-autoconf-chan_h323.patch

    r13685 r14337  
    1 diff -Nru asterisk-1.4.22.org/acinclude.m4 asterisk-1.4.22/acinclude.m4 
    2 --- asterisk-1.4.22.org/acinclude.m4    2008-07-22 22:49:41.000000000 +0200 
    3 +++ asterisk-1.4.22/acinclude.m4        2008-11-29 15:06:28.000000000 +0100 
    4 @@ -588,6 +588,7 @@ 
     1diff -Nru asterisk-1.4.23.1.org/autoconf/ast_check_openh323.m4 asterisk-1.4.23.1/autoconf/ast_check_openh323.m4 
     2--- asterisk-1.4.23.1.org/autoconf/ast_check_openh323.m4        2008-10-20 06:57:33.000000000 +0200 
     3+++ asterisk-1.4.23.1/autoconf/ast_check_openh323.m4    2009-01-31 15:30:03.000000000 +0100 
     4@@ -119,6 +119,7 @@ 
    55                                ;; 
    66                esac 
     
    1010                AC_SUBST([OPENH323_SUFFIX]) 
    1111                AC_SUBST([OPENH323_BUILD]) 
    12 diff -Nru asterisk-1.4.22.org/configure.ac asterisk-1.4.22/configure.ac 
    13 --- asterisk-1.4.22.org/configure.ac    2008-09-08 18:26:00.000000000 +0200 
    14 +++ asterisk-1.4.22/configure.ac        2008-11-29 15:06:28.000000000 +0100 
    15 @@ -1259,7 +1259,7 @@ 
     12diff -Nru asterisk-1.4.23.1.org/configure.ac asterisk-1.4.23.1/configure.ac 
     13--- asterisk-1.4.23.1.org/configure.ac  2008-12-15 18:43:59.000000000 +0100 
     14+++ asterisk-1.4.23.1/configure.ac      2009-01-31 15:29:14.000000000 +0100 
     15@@ -1278,7 +1278,7 @@ 
    1616        if test "${HAS_PWLIB:-unset}" != "unset"; then 
    17                 AST_CHECK_OPENH323_PLATFORM() 
     17                AST_CHECK_PWLIB_PLATFORM() 
    1818  
    1919-               PLATFORM_PWLIB="pt_${PWLIB_PLATFORM}_r" 
  • packages/net/asterisk-1.4.x/patches/030-acinclude.patch

    r13685 r14337  
    1 diff -Nru asterisk-1.4.22.org/acinclude.m4 asterisk-1.4.22/acinclude.m4 
    2 --- asterisk-1.4.22.org/acinclude.m4    2008-07-22 22:49:41.000000000 +0200 
    3 +++ asterisk-1.4.22/acinclude.m4        2008-11-29 15:08:07.000000000 +0100 
    4 @@ -664,7 +664,7 @@ 
     1diff -Nru asterisk-1.4.23.1.org/autoconf/ast_prog_ld.m4 asterisk-1.4.23.1/autoconf/ast_prog_ld.m4 
     2--- asterisk-1.4.23.1.org/autoconf/ast_prog_ld.m4       2008-10-20 06:45:56.000000000 +0200 
     3+++ asterisk-1.4.23.1/autoconf/ast_prog_ld.m4   2009-01-31 15:46:48.000000000 +0100 
     4@@ -7,7 +7,7 @@ 
    55        [assume the C compiler uses GNU ld @<:@default=no@:>@])], 
    66     [test "$withval" = no || with_gnu_ld=yes], 
     
    1111 AC_REQUIRE([AC_CANONICAL_HOST])dnl 
    1212 AC_REQUIRE([AC_CANONICAL_BUILD])dnl 
    13 @@ -769,28 +769,6 @@ 
    14   AC_SUBST([EGREP]) 
    15  ])]) # AST_PROG_EGREP 
    16   
     13diff -Nru asterisk-1.4.23.1.org/autoconf/ast_prog_sed.m4 asterisk-1.4.23.1/autoconf/ast_prog_sed.m4 
     14--- asterisk-1.4.23.1.org/autoconf/ast_prog_sed.m4      2008-10-20 06:45:56.000000000 +0200 
     15+++ asterisk-1.4.23.1/autoconf/ast_prog_sed.m4  1970-01-01 01:00:00.000000000 +0100 
     16@@ -1,21 +0,0 @@ 
    1717-# AST_PROG_SED 
    1818-# ----------- 
     
    3636- rm -f conftest.sed 
    3737-])# AST_PROG_SED 
    38 - 
    39  dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 
    40  dnl 
    41  dnl @summary figure out how to build C programs using POSIX threads 
  • packages/net/asterisk-1.4.x/patches/035-main-asterisk-uclibc-daemon.patch

    r13712 r14337  
    1 diff -Nru asterisk-1.4.22.org/main/asterisk.c asterisk-1.4.22/main/asterisk.c 
    2 --- asterisk-1.4.22.org/main/asterisk.c 2008-07-26 17:31:21.000000000 +0200 
    3 +++ asterisk-1.4.22/main/asterisk.c     2008-12-20 22:49:58.000000000 +0100 
    4 @@ -2935,7 +2935,38 @@ 
     1diff -Nru asterisk-1.4.23.1.org/main/asterisk.c asterisk-1.4.23.1/main/asterisk.c 
     2--- asterisk-1.4.23.1.org/main/asterisk.c       2008-12-23 16:35:38.000000000 +0100 
     3+++ asterisk-1.4.23.1/main/asterisk.c   2009-01-31 15:41:40.000000000 +0100 
     4@@ -2986,9 +2986,40 @@ 
    55 #if HAVE_WORKING_FORK 
    66        if (ast_opt_always_fork || !ast_opt_no_fork) { 
    77 #ifndef HAVE_SBIN_LAUNCHD 
    88+#ifndef __UCLIBC__ 
    9                 daemon(1, 0); 
     9                if (daemon(1, 0) < 0) { 
     10                        ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno)); 
     11                } 
    1012+#else 
    1113+/* 
     
    1719+   but duplication of uClibc daemon.c code in here does work. 
    1820+*/ 
    19 +       int fd; 
    20 +       switch (fork()) { 
    21 +               case -1: 
    22 +                       exit(1); 
    23 +               case 0: 
    24 +                       break; 
    25 +               default: 
    26 +                       _exit(0); 
    27 +       } 
    28 +       if (setsid() == -1) 
    29 +               exit(1); 
    30 +       if (fork()) 
    31 +               _exit(0); 
    32 +       if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 
    33 +               dup2(fd, STDIN_FILENO); 
    34 +               dup2(fd, STDOUT_FILENO); 
    35 +               dup2(fd, STDERR_FILENO); 
    36 +               if (fd > 2) 
    37 +                       close(fd); 
    38 +       } 
     21+       int fd; 
     22+       switch (fork()) { 
     23+               case -1: 
     24+                       exit(1); 
     25+               case 0: 
     26+                       break; 
     27+               default: 
     28+                       _exit(0); 
     29+       } 
     30+       if (setsid() == -1) 
     31+               exit(1); 
     32+       if (fork()) 
     33+               _exit(0); 
     34+       if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 
     35+               dup2(fd, STDIN_FILENO); 
     36+               dup2(fd, STDOUT_FILENO); 
     37+               dup2(fd, STDERR_FILENO); 
     38+               if (fd > 2) 
     39+                       close(fd); 
     40+       } 
    3941+#endif 
    4042                ast_mainpid = getpid(); 
  • packages/net/asterisk-addons-1.4.x/Makefile

    r12795 r14337  
    1111PKG_NAME:=asterisk-addons 
    1212PKG_VERSION:=1.4.7 
    13 PKG_RELEASE:=1 
     13PKG_RELEASE:=2 
    1414 
    1515PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 
  • packages/net/asterisk-addons-1.4.x/patches/011-chan_mobile.patch

    r12795 r14337  
    1 diff -Nru asterisk-addons-1.4.6.org/build_tools/menuselect-deps.in asterisk-addons-1.4.6/build_tools/menuselect-deps.in 
    2 --- asterisk-addons-1.4.6.org/build_tools/menuselect-deps.in    2007-05-14 18:22:44.000000000 +0200 
    3 +++ asterisk-addons-1.4.6/build_tools/menuselect-deps.in        2008-03-06 08:38:14.000000000 +0100 
     1diff -Nru asterisk-addons-1.4.7.org/build_tools/menuselect-deps.in asterisk-addons-1.4.7/build_tools/menuselect-deps.in 
     2--- asterisk-addons-1.4.7.org/build_tools/menuselect-deps.in    2007-05-14 18:22:44.000000000 +0200 
     3+++ asterisk-addons-1.4.7/build_tools/menuselect-deps.in        2009-02-01 08:45:32.000000000 +0100 
    44@@ -1,2 +1,3 @@ 
    55+BLUETOOTH=@PBX_BLUETOOTH@ 
    66 MYSQLCLIENT=@PBX_MYSQLCLIENT@ 
    77 ASTERISK=@PBX_ASTERISK@ 
    8 diff -Nru asterisk-addons-1.4.6.org/channels/chan_mobile.c asterisk-addons-1.4.6/channels/chan_mobile.c 
    9 --- asterisk-addons-1.4.6.org/channels/chan_mobile.c    1970-01-01 01:00:00.000000000 +0100 
    10 +++ asterisk-addons-1.4.6/channels/chan_mobile.c        2008-03-06 08:38:57.000000000 +0100 
    11 @@ -0,0 +1,1867 @@ 
     8diff -Nru asterisk-addons-1.4.7.org/channels/chan_mobile.c asterisk-addons-1.4.7/channels/chan_mobile.c 
     9--- asterisk-addons-1.4.7.org/channels/chan_mobile.c    1970-01-01 01:00:00.000000000 +0100 
     10+++ asterisk-addons-1.4.7/channels/chan_mobile.c        2009-02-01 08:44:17.000000000 +0100 
     11@@ -0,0 +1,2150 @@ 
    1212+/* 
    1313+ * Asterisk -- An open source telephony toolkit. 
     
    3131+ * 
    3232+ * \brief Bluetooth Mobile Device channel driver 
    33 + *  
     33+ * 
    3434+ * \author Dave Bowerman <david.bowerman@gmail.com> 
    3535+ * 
     
    4343+#include <asterisk.h> 
    4444+ 
    45 +ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416 $") 
     45+ASTERISK_FILE_VERSION(__FILE__, "$Revision$") 
    4646+ 
    4747+#include <stdio.h> 
     
    6464+#include <bluetooth/rfcomm.h> 
    6565+#include <bluetooth/sco.h> 
     66+#include <bluetooth/l2cap.h> 
    6667+ 
    6768+#include <asterisk/lock.h> 
     
    7879+#include <asterisk/causes.h> 
    7980+#include <asterisk/dsp.h> 
    80 + 
    81 +#ifndef ast_debug 
    82 +#define ast_debug(level, ...) do {       \ 
    83 +        if (option_debug >= (level)) {       \ 
    84 +                ast_log(LOG_DEBUG, __VA_ARGS__); \ 
    85 +        }                                    \ 
    86 +} while (0) 
    87 +#endif 
    88 + 
    89 +#define AST_MODULE "chan_mobile" 
     81+#include <asterisk/app.h> 
     82+#include <asterisk/manager.h> 
    9083+ 
    9184+#define MBL_CONFIG "mobile.conf" 
    9285+ 
    93 +static int prefformat = AST_FORMAT_SLINEAR; 
    94 + 
    95 +static int discovery_interval = 60;    /* The device discovery interval, default 60 seconds. */ 
    96 +static int sco_socket;                 /* This is global so it can be closed on module unload outside of the listener thread */ 
     86+#define DEVICE_FRAME_SIZE 48 
     87+#define DEVICE_FRAME_FORMAT AST_FORMAT_SLINEAR 
     88+#define CHANNEL_FRAME_SIZE 320 
     89+ 
     90+static int prefformat = DEVICE_FRAME_FORMAT; 
     91+ 
     92+static int discovery_interval = 60;                    /* The device discovery interval, default 60 seconds. */ 
     93+static pthread_t discovery_thread = AST_PTHREADT_NULL; /* The discovery thread */ 
    9794+static sdp_session_t *sdp_session; 
    9895+ 
     
    110107+       MBL_STATE_INIT5, 
    111108+       MBL_STATE_INIT6, 
     109+       MBL_STATE_INIT7, 
    112110+       MBL_STATE_PREIDLE, 
    113111+       MBL_STATE_IDLE, 
     
    126124+}; 
    127125+ 
     126+struct adapter_pvt { 
     127+       int dev_id;                                     /* device id */ 
     128+       int hci_socket;                                 /* device descriptor */ 
     129+       char id[31];                                    /* the 'name' from mobile.conf */ 
     130+       bdaddr_t addr;                                  /* adddress of adapter */ 
     131+       unsigned int inuse:1;                           /* are we in use ? */ 
     132+       unsigned int alignment_detection:1;             /* do alignment detection on this adpater? */ 
     133+       int sco_socket; 
     134+       AST_LIST_ENTRY(adapter_pvt) entry; 
     135+}; 
     136+ 
     137+static AST_RWLIST_HEAD_STATIC(adapters, adapter_pvt); 
     138+ 
    128139+struct mbl_pvt { 
    129 +       struct ast_channel *owner;              /* Channel we belong to, possibly NULL */ 
    130 +       struct ast_frame fr;                    /* "null" frame */ 
    131 +       enum mbl_type type;                     /* Phone or Headset */ 
    132 +       char id[31];                            /* The id from mobile.conf */ 
    133 +       char bdaddr[18];                        /* the bdaddr of the device */ 
    134 +       char context[AST_MAX_CONTEXT];          /* the context for incoming calls */ 
    135 +       char connected;                         /* is it connected? */ 
    136 +       int rfcomm_port;                        /* rfcomm port number */ 
    137 +       int rfcomm_socket;                      /* rfcomm socket descriptor */ 
     140+       struct ast_channel *owner;                      /* Channel we belong to, possibly NULL */ 
     141+       struct ast_frame fr;                            /* "null" frame */ 
     142+       enum mbl_type type;                             /* Phone or Headset */ 
     143+       char id[31];                                    /* The id from mobile.conf */ 
     144+       int group;                                      /* group number for group dialling */ 
     145+       bdaddr_t addr;                                  /* address of device */ 
     146+       struct adapter_pvt *adapter;                    /* the adapter we use */ 
     147+       char context[AST_MAX_CONTEXT];                  /* the context for incoming calls */ 
     148+       char connected;                                 /* is it connected? */ 
     149+       int rfcomm_port;                                /* rfcomm port number */ 
     150+       int rfcomm_socket;                              /* rfcomm socket descriptor */ 
    138151+       char rfcomm_buf[256]; 
    139 +       int sco_socket;                         /* sco socket descriptor */ 
    140 +       enum mbl_state state;                   /* monitor thread current state */ 
    141 +       pthread_t monitor_thread;               /* monitor thread handle */ 
    142 +       char sco_in_buf[48 + AST_FRIENDLY_OFFSET]; 
    143 +       char sco_out_buf[352]; 
    144 +       char *sco_out_ptr; 
    145 +       int sco_out_len; 
    146 +       char dial_number[AST_MAX_EXTENSION];    /* number for the monitor thread to dial */ 
     152+       char io_buf[CHANNEL_FRAME_SIZE + AST_FRIENDLY_OFFSET]; 
     153+       char io_save_buf[DEVICE_FRAME_SIZE]; 
     154+       int io_save_len; 
     155+       int io_pipe[2]; 
     156+       int sco_socket;                                 /* sco socket descriptor */ 
     157+       pthread_t sco_listener_thread;                  /* inbound sco listener for this device */ 
     158+       enum mbl_state state;                           /* monitor thread current state */ 
     159+       pthread_t monitor_thread;                       /* monitor thread handle */ 
     160+       char dial_number[AST_MAX_EXTENSION];            /* number for the monitor thread to dial */ 
    147161+       int dial_timeout; 
    148 +       char ciev_call_0[4];                    /* dynamically build reponse strings */ 
    149 +       char ciev_call_1[4]; 
    150 +       char ciev_callsetup_0[4]; 
    151 +       char ciev_callsetup_1[4]; 
    152 +       char ciev_callsetup_2[4]; 
    153 +       char ciev_callsetup_3[4]; 
    154 +       char no_callsetup; 
    155 +       char has_sms; 
    156 +       char sms_txt[161]; 
     162+       char ciev_call_0[5];                            /* dynamically built reponse strings */ 
     163+       char ciev_call_1[5]; 
     164+       char ciev_callsetup_0[5]; 
     165+       char ciev_callsetup_1[5]; 
     166+       char ciev_callsetup_2[5]; 
     167+       char ciev_callsetup_3[5]; 
     168+       unsigned int no_callsetup:1; 
     169+       unsigned int has_sms:1; 
     170+       unsigned int sent_answer:1; 
     171+       unsigned int do_alignment_detection:1; 
     172+       unsigned int alignment_detection_triggered:1; 
     173+       unsigned int do_hangup:1; 
     174+       unsigned int blackberry:1; 
     175+       short alignment_samples[4]; 
     176+       int alignment_count; 
     177+       char sms_txt[160]; 
    157178+       struct ast_dsp *dsp; 
    158179+       struct ast_frame *dsp_fr; 
    159180+       int dtmf_skip; 
    160181+       int skip_frames; 
    161 +       char sent_answer; 
    162182+       char hangup_count; 
    163183+       AST_LIST_ENTRY(mbl_pvt) entry; 
    164184+}; 
    165185+ 
    166 +static AST_LIST_HEAD_STATIC(devices, mbl_pvt); 
    167 + 
    168 +/* The discovery thread */ 
    169 +static pthread_t discovery_thread = AST_PTHREADT_NULL; 
    170 +/* The sco listener thread */ 
    171 +static pthread_t sco_listener_thread = AST_PTHREADT_NULL; 
     186+static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt); 
    172187+ 
    173188+/* CLI stuff */ 
     
    184199+"       Send command to the rfcomm port.\n"; 
    185200+ 
    186 +static int do_show_devices(int, int, char **); 
    187 +static int do_search_devices(int, int, char **); 
    188 +static int do_send_rfcomm(int, int, char **); 
     201+static int handle_cli_mobile_show_devices(int fd, int argc, char **argv); 
     202+static int handle_cli_mobile_search(int fd, int argc, char **argv); 
     203+static int handle_cli_mobile_rfcomm(int fd, int argc, char **argv); 
    189204+ 
    190205+static struct ast_cli_entry mbl_cli[] = { 
    191 +       {{"mobile", "show", "devices", NULL}, do_show_devices, "Show Bluetooth Cell / Mobile devices", show_usage}, 
    192 +       {{"mobile", "search", NULL}, do_search_devices, "Search for Bluetooth Cell / Mobile devices", search_usage}, 
    193 +       {{"mobile", "rfcomm", NULL}, do_send_rfcomm, "Send commands to the rfcomm port for debugging", rfcomm_usage} 
     206+       {{"mobile", "show", "devices", NULL}, handle_cli_mobile_show_devices, "Show Bluetooth Cell / Mobile devices", show_usage}, 
     207+       {{"mobile", "search", NULL}, handle_cli_mobile_search, "Search for Bluetooth Cell / Mobile devices", search_usage}, 
     208+       {{"mobile", "rfcomm", NULL}, handle_cli_mobile_rfcomm, "Send commands to the rfcomm port for debugging", rfcomm_usage}, 
    194209+}; 
    195210+ 
     
    211226+"  Message - text of the message\n"; 
    212227+ 
     228+static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num); 
    213229+static struct ast_channel *mbl_request(const char *type, int format, void *data, int *cause); 
    214230+static int mbl_call(struct ast_channel *ast, char *dest, int timeout); 
     
    221237+static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 
    222238+static int mbl_devicestate(void *data); 
    223 +static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num); 
    224 + 
     239+ 
     240+static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen); 
     241+ 
     242+static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel); 
    225243+static int rfcomm_write(struct mbl_pvt *pvt, char *buf); 
    226244+static int rfcomm_read(struct mbl_pvt *pvt, char *buf, char flush, int timeout); 
    227 +static int sco_connect(char *bdaddr); 
     245+ 
     246+static int sco_connect(bdaddr_t src, bdaddr_t dst); 
     247+static int sco_write(int s, char *buf, int len); 
     248+static int sco_read(int s, char *buf, int len); 
     249+ 
     250+static void *do_sco_listen(void *data); 
    228251+static int sdp_search(char *addr, int profile); 
    229252+ 
     
    244267+}; 
    245268+ 
    246 +static int do_show_devices(int fd, int argc, char **argv) 
    247 +{ 
    248 + 
     269+/* CLI Commands implementation */ 
     270+ 
     271+static int handle_cli_mobile_show_devices(int fd, int argc, char **argv) 
     272+{ 
    249273+       struct mbl_pvt *pvt; 
    250 + 
    251 +       #define FORMAT "%-15.15s %-17.17s %-9.9s %-5.5s %-3.3s\n" 
    252 + 
    253 +       ast_cli(fd, FORMAT, "ID", "Address", "Connected", "State", "SMS"); 
    254 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    255 +               ast_cli(fd, FORMAT, pvt->id, pvt->bdaddr, pvt->connected?"Yes":"No", (pvt->state == MBL_STATE_IDLE)?"Free":(pvt->state < MBL_STATE_IDLE)?"Init":"Busy", (pvt->has_sms)?"Yes":"No"); 
    256 +       }        
     274+       char bdaddr[18]; 
     275+       char group[6]; 
     276+ 
     277+#define FORMAT1 "%-15.15s %-17.17s %-5.5s %-15.15s %-9.9s %-5.5s %-3.3s\n" 
     278+ 
     279+       if (argc != 3) 
     280+               return RESULT_SHOWUSAGE; 
     281+ 
     282+       ast_cli(fd, FORMAT1, "ID", "Address", "Group", "Adapter", "Connected", "State", "SMS"); 
     283+       AST_RWLIST_RDLOCK(&devices); 
     284+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     285+               ba2str(&pvt->addr, bdaddr); 
     286+               snprintf(group, 5, "%d", pvt->group); 
     287+               ast_cli(fd, FORMAT1, pvt->id, bdaddr, group, pvt->adapter->id, pvt->connected ? "Yes" : "No", 
     288+                       (pvt->state == MBL_STATE_IDLE) ? "Free" : (pvt->state < MBL_STATE_IDLE) ? "Init" : "Busy", 
     289+                       (pvt->has_sms) ? "Yes" : "No"); 
     290+       } 
     291+       AST_RWLIST_UNLOCK(&devices); 
     292+ 
     293+#undef FORMAT1 
    257294+ 
    258295+       return RESULT_SUCCESS; 
    259 + 
    260 +} 
    261 + 
    262 +static int do_search_devices(int fd, int argc, char **argv) 
    263 +{ 
    264 + 
    265 +       int hci_socket; 
     296+} 
     297+ 
     298+static int handle_cli_mobile_search(int fd, int argc, char **argv) 
     299+{ 
     300+       struct adapter_pvt *adapter; 
    266301+       inquiry_info *ii = NULL; 
    267302+       int max_rsp, num_rsp; 
    268 +       int dev_id, len, flags; 
     303+       int len, flags; 
    269304+       int i, phport, hsport; 
    270305+       char addr[19] = {0}; 
    271306+       char name[31] = {0}; 
    272307+ 
    273 +       #define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n" 
    274 +       #define FORMAT3 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n" 
    275 + 
    276 +       dev_id = hci_get_route(NULL); 
    277 +       hci_socket = hci_open_dev(dev_id); 
     308+#define FORMAT1 "%-17.17s %-30.30s %-6.6s %-7.7s %-4.4s\n" 
     309+#define FORMAT2 "%-17.17s %-30.30s %-6.6s %-7.7s %d\n" 
     310+ 
     311+       if (argc != 2) 
     312+               return RESULT_SHOWUSAGE; 
     313+ 
     314+       /* find a free adapter */ 
     315+       AST_RWLIST_RDLOCK(&adapters); 
     316+       AST_RWLIST_TRAVERSE(&adapters, adapter, entry) { 
     317+               if (!adapter->inuse) 
     318+                       break; 
     319+       } 
     320+       AST_RWLIST_UNLOCK(&adapters); 
     321+ 
     322+       if (!adapter) { 
     323+               ast_cli(fd, "All Bluetooth adapters are in use at this time.\n"); 
     324+               return RESULT_SUCCESS; 
     325+       } 
     326+ 
    278327+       len  = 8; 
    279328+       max_rsp = 255; 
    280329+       flags = IREQ_CACHE_FLUSH; 
    281330+ 
    282 +       ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info)); 
    283 +       num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags); 
     331+       ii = alloca(max_rsp * sizeof(inquiry_info)); 
     332+       num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags); 
    284333+       if (num_rsp > 0) { 
    285 +               ast_cli(fd, FORMAT2, "Address", "Name", "Usable", "Type", "Port"); 
     334+               ast_cli(fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port"); 
    286335+               for (i = 0; i < num_rsp; i++) { 
    287 +                       ba2str(&(ii+i)->bdaddr, addr); 
     336+                       ba2str(&(ii + i)->bdaddr, addr); 
    288337+                       name[0] = 0x00; 
    289 +                       if (hci_read_remote_name(hci_socket, &(ii+i)->bdaddr, sizeof(name)-1, name, 0) < 0) 
     338+                       if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0) 
    290339+                               strcpy(name, "[unknown]"); 
    291340+                       phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID); 
     
    294343+                       else 
    295344+                               hsport = 0; 
    296 +                       ast_cli(fd, FORMAT3, addr, name, (phport > 0 || hsport > 0)?"Yes":"No", (phport > 0)?"Phone":"Headset", (phport > 0)?phport:hsport); 
     345+                       ast_cli(fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No", 
     346+                               (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport); 
    297347+               } 
    298348+       } else 
    299349+               ast_cli(fd, "No Bluetooth Cell / Mobile devices found.\n"); 
    300350+ 
    301 +       free(ii); 
    302 + 
    303 +       hci_close_dev(hci_socket); 
     351+#undef FORMAT1 
     352+#undef FORMAT2 
    304353+ 
    305354+       return RESULT_SUCCESS; 
    306 + 
    307 +} 
    308 + 
    309 +static int do_send_rfcomm(int fd, int argc, char **argv) 
    310 +{ 
    311 + 
    312 +       struct mbl_pvt *pvt; 
     355+} 
     356+ 
     357+static int handle_cli_mobile_rfcomm(int fd, int argc, char **argv) 
     358+{ 
    313359+       char buf[128]; 
    314 + 
    315 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
     360+       struct mbl_pvt *pvt = NULL; 
     361+ 
     362+       if (argc != 4) 
     363+               return RESULT_SHOWUSAGE; 
     364+ 
     365+       AST_RWLIST_RDLOCK(&devices); 
     366+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
    316367+               if (!strcmp(pvt->id, argv[2])) 
    317368+                       break; 
    318369+       } 
     370+       AST_RWLIST_UNLOCK(&devices); 
    319371+ 
    320372+       if (!pvt || !pvt->connected) { 
    321 +               sprintf(buf, "Device %s not found.\n", argv[2]); 
    322 +               ast_cli(fd, buf); 
     373+               ast_cli(fd, "Device %s not found.\n", argv[2]); 
    323374+               return RESULT_SUCCESS; 
    324375+       } 
    325376+ 
    326 +       sprintf(buf, "%s\r", argv[3]); 
     377+       snprintf(buf, sizeof(buf), "%s\r", argv[3]); 
    327378+       rfcomm_write(pvt, buf); 
    328379+ 
    329380+       return RESULT_SUCCESS; 
    330 + 
    331 +} 
     381+} 
     382+ 
     383+/* 
     384+ 
     385+       Dialplan applications implementation 
     386+ 
     387+*/ 
    332388+ 
    333389+static int mbl_status_exec(struct ast_channel *ast, void *data) 
     
    335391+ 
    336392+       struct mbl_pvt *pvt; 
    337 +       char *args = NULL, *device = NULL, *variable = NULL; 
     393+       char *parse; 
    338394+       int stat; 
    339395+       char status[2]; 
    340396+ 
    341 +       if (!data) 
     397+       AST_DECLARE_APP_ARGS(args, 
     398+               AST_APP_ARG(device); 
     399+               AST_APP_ARG(variable); 
     400+       ); 
     401+ 
     402+       if (ast_strlen_zero(data)) 
    342403+               return -1; 
    343404+ 
    344 +       args = ast_strdupa((char *)data); 
    345 +       device = strsep(&args, "|"); 
    346 +       if (device && (device[0] != 0x00)) { 
    347 +               variable = args; 
    348 +       } else 
     405+       parse = ast_strdupa(data); 
     406+ 
     407+       AST_STANDARD_APP_ARGS(args, parse); 
     408+ 
     409+       if (ast_strlen_zero(args.device) || ast_strlen_zero(args.variable)) 
    349410+               return -1; 
    350411+ 
    351412+       stat = 1; 
    352413+ 
    353 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    354 +               if (!strcmp(pvt->id, device)) 
     414+       AST_RWLIST_RDLOCK(&devices); 
     415+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     416+               if (!strcmp(pvt->id, args.device)) 
    355417+                       break; 
    356418+       } 
     419+       AST_RWLIST_UNLOCK(&devices); 
    357420+ 
    358421+       if (pvt) { 
     
    363426+       } 
    364427+ 
    365 +       sprintf(status, "%d", stat); 
    366 +       pbx_builtin_setvar_helper(ast, variable, status); 
     428+       snprintf(status, sizeof(status), "%d", stat); 
     429+       pbx_builtin_setvar_helper(ast, args.variable, status); 
    367430+ 
    368431+       return 0; 
     
    374437+ 
    375438+       struct mbl_pvt *pvt; 
    376 +       char *args = NULL, *device = NULL, *dest = NULL, *message = NULL; 
    377 + 
    378 +       if (!data) 
     439+       char *parse; 
     440+ 
     441+       AST_DECLARE_APP_ARGS(args, 
     442+               AST_APP_ARG(device); 
     443+               AST_APP_ARG(dest); 
     444+               AST_APP_ARG(message); 
     445+       ); 
     446+ 
     447+       if (ast_strlen_zero(data)) 
    379448+               return -1; 
    380449+ 
    381 +       args = ast_strdupa((char *)data); 
    382 +       device = strsep(&args, "|"); 
    383 +       if (device && (device[0] != 0x00)) { 
    384 +               dest = strsep(&args, "|"); 
    385 +               if (dest && (dest[0] != 0x00)) { 
    386 +                       message = args; 
    387 +                       if (!message || (message[0] == 0x00)) { 
    388 +                               ast_log(LOG_ERROR,"NULL Message to be sent-- SMS will not be sent.\n"); 
    389 +                               return -1; 
    390 +                       } 
    391 +               } else { 
    392 +                       ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n"); 
    393 +                       return -1; 
    394 +               } 
    395 +                
    396 +       } else { 
     450+       parse = ast_strdupa(data); 
     451+ 
     452+       AST_STANDARD_APP_ARGS(args, parse); 
     453+ 
     454+       if (ast_strlen_zero(args.device)) { 
    397455+               ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n"); 
    398456+               return -1; 
    399457+       } 
    400 +        
    401 + 
    402 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    403 +               if (!strcmp(pvt->id, device)) 
     458+ 
     459+       if (ast_strlen_zero(args.dest)) { 
     460+               ast_log(LOG_ERROR,"NULL destination for message -- SMS will not be sent.\n"); 
     461+               return -1; 
     462+       } 
     463+ 
     464+       if (ast_strlen_zero(args.message)) { 
     465+               ast_log(LOG_ERROR,"NULL Message to be sent -- SMS will not be sent.\n"); 
     466+               return -1; 
     467+       } 
     468+ 
     469+       AST_RWLIST_RDLOCK(&devices); 
     470+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     471+               if (!strcmp(pvt->id, args.device)) 
    404472+                       break; 
    405473+       } 
     474+       AST_RWLIST_UNLOCK(&devices); 
    406475+ 
    407476+       if (!pvt) { 
    408 +               ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n",device); 
     477+               ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device); 
    409478+               return -1; 
    410479+       } 
    411 +        
     480+ 
    412481+       if (!pvt->connected) { 
    413 +               ast_log(LOG_ERROR,"bluetooth device %s wasn't connected -- SMS will not be sent.\n",device); 
     482+               ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device); 
    414483+               return -1; 
    415484+       } 
    416 +        
     485+ 
    417486+       if (!pvt->has_sms) { 
    418 +               ast_log(LOG_ERROR,"bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n",device); 
     487+               ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device); 
    419488+               return -1; 
    420489+       } 
    421 +        
     490+ 
    422491+       if (pvt->state != MBL_STATE_IDLE) { 
    423 +               ast_log(LOG_ERROR,"bluetooth device %s isn't IDLE -- SMS will not be sent.\n",device); 
     492+               ast_log(LOG_ERROR,"Bluetooth device %s isn't IDLE -- SMS will not be sent.\n", args.device); 
    424493+               return -1; 
    425494+       } 
    426 +        
    427 +       strcpy(pvt->dial_number, dest); 
    428 +       memset(pvt->sms_txt, 0x0, sizeof(pvt->sms_txt)); 
    429 +       strncpy(pvt->sms_txt, message, 160); 
     495+ 
     496+       ast_copy_string(pvt->dial_number, args.dest, sizeof(pvt->dial_number)); 
     497+       ast_copy_string(pvt->sms_txt, args.message, sizeof(pvt->sms_txt)); 
    430498+       pvt->state = MBL_STATE_OUTSMS; 
    431499+ 
    432500+       return 0; 
     501+ 
     502+} 
     503+ 
     504+/* 
     505+ 
     506+       Channel Driver callbacks 
     507+ 
     508+*/ 
     509+ 
     510+static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num) 
     511+{ 
     512+ 
     513+       struct ast_channel *chn; 
     514+ 
     515+       if (pipe(pvt->io_pipe) == -1) { 
     516+               ast_log(LOG_ERROR, "Failed to create io_pipe.\n"); 
     517+               return NULL; 
     518+       } 
     519+ 
     520+       if (pvt->sco_socket != -1) 
     521+               close(pvt->sco_socket); 
     522+       pvt->sco_socket = -1; 
     523+       pvt->io_save_len = 0; 
     524+       pvt->sent_answer = 0; 
     525+       pvt->skip_frames = 0; 
     526+       pvt->alignment_count = 0; 
     527+       pvt->alignment_detection_triggered = 0; 
     528+       if (pvt->adapter->alignment_detection) 
     529+               pvt->do_alignment_detection = 1; 
     530+       else 
     531+               pvt->do_alignment_detection = 0; 
     532+       pvt->do_hangup = 1; 
     533+       chn = ast_channel_alloc(1, state, cid_num, pvt->id, 0, 0, pvt->context, 0, "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff); 
     534+       if (chn) { 
     535+               chn->tech = &mbl_tech; 
     536+               chn->nativeformats = prefformat; 
     537+               chn->rawreadformat = prefformat; 
     538+               chn->rawwriteformat = prefformat; 
     539+               chn->writeformat = prefformat; 
     540+               chn->readformat = prefformat; 
     541+               chn->tech_pvt = pvt; 
     542+               chn->fds[0] = pvt->io_pipe[0]; 
     543+               if (state == AST_STATE_RING) 
     544+                       chn->rings = 1; 
     545+               ast_string_field_set(chn, language, "en"); 
     546+               pvt->owner = chn; 
     547+               return chn; 
     548+       } 
     549+ 
     550+       return NULL; 
    433551+ 
    434552+} 
     
    441559+       char *dest_dev = NULL; 
    442560+       char *dest_num = NULL; 
    443 +       int oldformat; 
     561+       int oldformat, group = -1; 
    444562+ 
    445563+       if (!data) { 
     
    463581+               *dest_num++ = 0x00; 
    464582+ 
    465 +       /* Find requested device and make sure its connected. */ 
    466 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    467 +               if (!strcmp(pvt->id, dest_dev)) { 
     583+       if (((dest_dev[0] == 'g') || (dest_dev[0] == 'G')) && ((dest_dev[1] >= '0') && (dest_dev[1] <= '9'))) { 
     584+               group = atoi(&dest_dev[1]); 
     585+       } 
     586+ 
     587+       /* Find requested device and make sure it's connected. */ 
     588+       AST_RWLIST_RDLOCK(&devices); 
     589+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     590+               if (group > -1 && pvt->group == group && pvt->connected && !pvt->owner) { 
    468591+                       break; 
    469 +               } 
    470 +       } 
     592+               } else if (!strcmp(pvt->id, dest_dev)) { 
     593+                       break; 
     594+               } 
     595+       } 
     596+       AST_RWLIST_UNLOCK(&devices); 
    471597+       if (!pvt || !pvt->connected || pvt->owner) { 
    472598+               ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev); 
     
    476602+ 
    477603+       if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) { 
    478 +               ast_log(LOG_WARNING, "Cant determine destination number.\n"); 
     604+               ast_log(LOG_WARNING, "Can't determine destination number.\n"); 
    479605+               *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION; 
    480606+               return NULL; 
    481607+       } 
    482608+ 
    483 +       pvt->sco_out_ptr = pvt->sco_out_buf; 
    484 +       pvt->sco_out_len = 0; 
    485 + 
    486609+       chn = mbl_new(AST_STATE_DOWN, pvt, NULL); 
    487610+       if (!chn) { 
    488 +               ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); 
     611+               ast_log(LOG_WARNING, "Unable to allocate channel structure.\n"); 
    489612+               *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL; 
    490613+               return NULL; 
     
    520643+       } 
    521644+ 
    522 +       ast_debug(1, "Calling %s on %s\n", dest, ast->name); 
     645+       ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name); 
    523646+ 
    524647+       if (pvt->type == MBL_TYPE_PHONE) { 
     
    530653+       } 
    531654+ 
    532 + 
    533655+       return 0; 
    534656+ 
     
    546668+       pvt = ast->tech_pvt; 
    547669+ 
    548 +       ast_debug(1, "Hanging up device %s.\n", pvt->id); 
    549 + 
    550 +       ast_channel_lock(ast); 
     670+       ast_log(LOG_DEBUG, "Hanging up device %s.\n", pvt->id); 
     671+ 
    551672+       ast->fds[0] = -1; 
    552 +       ast_channel_unlock(ast); 
     673+        
     674+       close(pvt->io_pipe[0]); 
     675+       close(pvt->io_pipe[1]); 
    553676+ 
    554677+       if (pvt->type == MBL_TYPE_HEADSET && pvt->sco_socket != -1) { 
     
    558681+ 
    559682+       if ((pvt->state == MBL_STATE_INCOMING || pvt->state == MBL_STATE_OUTGOING || pvt->state == MBL_STATE_DIAL1 || pvt->state == MBL_STATE_RING3) && pvt->type == MBL_TYPE_PHONE) { 
    560 +               rfcomm_write(pvt, "AT+CHUP\r"); 
     683+               if (pvt->do_hangup) { 
     684+                       rfcomm_write(pvt, "AT+CHUP\r"); 
     685+               } 
    561686+               pvt->state = MBL_STATE_HANGUP; 
    562687+               pvt->hangup_count = 0; 
     
    601726+       struct mbl_pvt *pvt; 
    602727+       char buf[11]; 
    603 +        
     728+ 
    604729+       pvt = ast->tech_pvt; 
    605730+ 
     
    607732+               return 0; 
    608733+ 
    609 +       ast_debug(1, "Dialed %c\n", digit); 
     734+       ast_log(LOG_DEBUG, "Dialed %c\n", digit); 
    610735+ 
    611736+       switch(digit) { 
     
    622747+       case '*': 
    623748+       case '#': 
    624 +               sprintf(buf, "AT+VTS=%c\r", digit); 
     749+               snprintf(buf, sizeof(buf), "AT+VTS=%c\r", digit); 
    625750+               rfcomm_write(pvt, buf); 
    626751+               break; 
     
    634759+} 
    635760+ 
    636 +/* 
    637 + 
    638 +       The SCO protocol basically delivers audio in 48 byte 'frames' in slin format. 
    639 +       Here we just package these into an ast_frame and return them. 
    640 +       The SCO connection from the device to Asterisk happens asynchronously, so it is feasible 
    641 +       that Asterisk will call mbl_read() before the device has connected. In that case we just return 
    642 +       a null frame. 
    643 + 
    644 +*/ 
    645 + 
    646761+static struct ast_frame *mbl_read(struct ast_channel *ast) 
    647762+{ 
    648763+ 
    649764+       struct mbl_pvt *pvt = ast->tech_pvt; 
     765+       struct ast_frame *f; 
    650766+       int r; 
    651 +       struct ast_frame *f; 
     767+ 
     768+       //ast_log(LOG_DEBUG, "*** mbl_read()\n"); 
    652769+ 
    653770+       if (!pvt->owner) { 
    654771+               return &ast_null_frame; 
    655772+       } 
    656 + 
    657 +       if (pvt->state == MBL_STATE_HANGUP) { 
    658 +               return &ast_null_frame; 
    659 +       } 
    660 + 
    661 +       if (pvt->sco_socket == -1) { 
    662 +               return &ast_null_frame; 
    663 +       } 
    664 + 
     773+       memset(&pvt->fr, 0x00, sizeof(struct ast_frame)); 
    665774+       pvt->fr.frametype = AST_FRAME_VOICE; 
    666 +       pvt->fr.subclass = AST_FORMAT_SLINEAR; 
    667 +       pvt->fr.data = pvt->sco_in_buf + AST_FRIENDLY_OFFSET; 
    668 + 
    669 +       if ((r = read(pvt->sco_socket, pvt->fr.data, 48)) == 48) { 
    670 +               if (pvt->skip_frames == 0) { 
    671 +                       f = ast_dsp_process(0, pvt->dsp, &pvt->fr); 
    672 +                       if (f && (f->frametype == AST_FRAME_DTMF_END)) { 
    673 +                               pvt->fr.frametype = AST_FRAME_DTMF_END; 
    674 +                               pvt->fr.subclass = f->subclass; 
    675 +                               pvt->skip_frames = pvt->dtmf_skip; 
    676 +                       } 
    677 +                       return &pvt->fr; 
     775+       pvt->fr.subclass = DEVICE_FRAME_FORMAT; 
     776+       pvt->fr.datalen = CHANNEL_FRAME_SIZE; 
     777+       pvt->fr.samples = CHANNEL_FRAME_SIZE / 2; 
     778+       pvt->fr.src = "Mobile"; 
     779+       pvt->fr.offset = AST_FRIENDLY_OFFSET; 
     780+       pvt->fr.mallocd = 0; 
     781+       pvt->fr.delivery.tv_sec = 0; 
     782+       pvt->fr.delivery.tv_usec = 0; 
     783+       pvt->fr.data = pvt->io_buf + AST_FRIENDLY_OFFSET; 
     784+ 
     785+       if ((r = read(pvt->io_pipe[0], pvt->fr.data, CHANNEL_FRAME_SIZE)) != CHANNEL_FRAME_SIZE) { 
     786+               if (r == -1) { 
     787+                       ast_log(LOG_ERROR, "read error %d\n", errno); 
     788+                       return &ast_null_frame; 
    678789+               } else { 
    679 +                       pvt->skip_frames--; 
    680 +               } 
    681 +       } else if (r == -1) { 
    682 +               ast_debug(1, "mbl_read() read error %d.\n", errno); 
    683 +               close(pvt->sco_socket); 
    684 +               pvt->sco_socket = -1; 
    685 +               ast_channel_lock(ast); 
    686 +               ast->fds[0] = -1; 
    687 +               ast_channel_unlock(ast); 
    688 +       } else { 
    689 +               ast_debug(1, "mbl_read() read short frame. (%d)\n", r); 
    690 +       } 
    691 + 
    692 +       return &ast_null_frame; 
    693 + 
    694 +} 
    695 + 
    696 +/* 
    697 + 
    698 +       We need to deliver 48 byte 'frames' of slin format audio to the device. 
    699 +       mbl_write() handles this by buffering short frames until the next time we are called. 
    700 + 
    701 +*/ 
     790+                       pvt->fr.datalen = r; 
     791+                       pvt->fr.samples = r / 2; 
     792+               } 
     793+       } 
     794+ 
     795+       f = ast_dsp_process(0, pvt->dsp, &pvt->fr); 
     796+       if (f && (f->frametype == AST_FRAME_DTMF_END)) { 
     797+               pvt->fr.frametype = AST_FRAME_DTMF_END; 
     798+               pvt->fr.subclass = f->subclass; 
     799+       } 
     800+ 
     801+       return &pvt->fr; 
     802+ 
     803+} 
    702804+ 
    703805+static int mbl_write(struct ast_channel *ast, struct ast_frame *frame) 
     
    705807+ 
    706808+       struct mbl_pvt *pvt = ast->tech_pvt; 
    707 +       int num_frames, i, r; 
    708 +       char *pfr; 
     809+       int i, r, io_need, num_frames; 
     810+       char *pfr, buf[DEVICE_FRAME_SIZE]; 
     811+ 
     812+       //ast_log(LOG_DEBUG, "*** mbl_write\n"); 
    709813+ 
    710814+       if (frame->frametype != AST_FRAME_VOICE) { 
    711815+               return 0; 
    712816+       } 
    713 +       if (pvt->sco_socket == -1) { 
    714 +               return 0; 
    715 +       } 
    716 + 
    717 +       if (pvt->state == MBL_STATE_HANGUP) { 
    718 +               return 0; 
    719 +       } 
    720 + 
    721 +       if (frame->datalen > sizeof(pvt->sco_out_buf) - pvt->sco_out_len) { 
    722 +               frame->datalen = sizeof(pvt->sco_out_buf) - pvt->sco_out_len; 
    723 +               ast_debug(1, "Overrun on sco_out_buf detected.\n"); 
    724 +       } 
    725 + 
    726 +       memmove(pvt->sco_out_ptr, frame->data, frame->datalen); 
    727 +       pvt->sco_out_len += frame->datalen; 
    728 +       num_frames = pvt->sco_out_len / 48; 
    729 + 
    730 +       pfr = pvt->sco_out_buf; 
     817+ 
     818+       io_need = 0; 
     819+       if (pvt->io_save_len > 0) { 
     820+               io_need = DEVICE_FRAME_SIZE - pvt->io_save_len; 
     821+               memcpy(pvt->io_save_buf + pvt->io_save_len, frame->data, io_need); 
     822+               sco_write(pvt->sco_socket, pvt->io_save_buf, DEVICE_FRAME_SIZE); 
     823+               if ((r = sco_read(pvt->sco_socket, buf, DEVICE_FRAME_SIZE))) { 
     824+                       if (pvt->do_alignment_detection) 
     825+                               do_alignment_detection(pvt, buf, r); 
     826+                       if (ast->_state == AST_STATE_UP)        /* Dont queue the audio in the pipe if the call is not up yet. just toss it. */ 
     827+                               sco_write(pvt->io_pipe[1], buf, r); 
     828+               } 
     829+       } 
     830+ 
     831+       num_frames = (frame->datalen - io_need) / DEVICE_FRAME_SIZE; 
     832+       pfr = frame->data + io_need; 
     833+ 
    731834+       for (i=0; i<num_frames; i++) { 
    732 +               if ((r = write(pvt->sco_socket, pfr, 48)) == -1) { 
    733 +                       close(pvt->sco_socket); 
    734 +                       pvt->sco_socket = -1; 
    735 +               } 
    736 +               pfr += 48; 
    737 +       } 
    738 + 
    739 +       pvt->sco_out_len = pvt->sco_out_len - (num_frames * 48); 
    740 +       memmove(pvt->sco_out_buf, pfr, pvt->sco_out_len); 
    741 +       pvt->sco_out_ptr = pvt->sco_out_buf + pvt->sco_out_len;  
    742 +        
     835+               sco_write(pvt->sco_socket, pfr, DEVICE_FRAME_SIZE); 
     836+               if ((r = sco_read(pvt->sco_socket, buf, DEVICE_FRAME_SIZE))) { 
     837+                       if (pvt->do_alignment_detection) 
     838+                               do_alignment_detection(pvt, buf, r); 
     839+                       if (ast->_state == AST_STATE_UP) 
     840+                               sco_write(pvt->io_pipe[1], buf, r); 
     841+               } 
     842+               pfr += DEVICE_FRAME_SIZE; 
     843+       } 
     844+ 
     845+       pvt->io_save_len = (frame->datalen - io_need) - (num_frames * DEVICE_FRAME_SIZE); 
     846+       if (pvt->io_save_len > 0) { 
     847+               memcpy(pvt->io_save_buf, pfr, pvt->io_save_len); 
     848+       } 
     849+ 
    743850+       return 0; 
    744851+ 
     
    766873+       device = ast_strdupa(S_OR(data, "")); 
    767874+ 
    768 +       ast_debug(1, "Checking device state for device %s\n", device); 
    769 + 
    770 +       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
     875+       ast_log(LOG_DEBUG, "Checking device state for device %s\n", device); 
     876+ 
     877+       AST_RWLIST_RDLOCK(&devices); 
     878+       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
    771879+               if (!strcmp(pvt->id, device)) 
    772880+                       break; 
    773881+       } 
     882+       AST_RWLIST_UNLOCK(&devices); 
    774883+ 
    775884+       if (pvt) { 
     
    786895+} 
    787896+ 
    788 +static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num) 
    789 +{ 
    790 + 
    791 +       struct ast_channel *chn; 
    792 + 
    793 +       chn = ast_channel_alloc(1, state, 0, 0, 0, 0, 0, 0, "Mobile/%s-%04lx", pvt->id, ast_random() & 0xffff); 
    794 +       if (chn) { 
    795 +               chn->tech = &mbl_tech; 
    796 +               chn->nativeformats = prefformat; 
    797 +               chn->rawreadformat = prefformat; 
    798 +               chn->rawwriteformat = prefformat; 
    799 +               chn->writeformat = prefformat; 
    800 +               chn->readformat = prefformat; 
    801 +               chn->readq.first = NULL; 
    802 +               pvt->fr.frametype = AST_FRAME_VOICE; 
    803 +               pvt->fr.subclass = AST_FORMAT_SLINEAR; 
    804 +               pvt->fr.datalen = 48; 
    805 +               pvt->fr.samples = 24; 
    806 +               pvt->fr.src = "Mobile"; 
    807 +               pvt->fr.offset = AST_FRIENDLY_OFFSET; 
    808 +               pvt->fr.mallocd = 0; 
    809 +               pvt->fr.delivery.tv_sec = 0; 
    810 +               pvt->fr.delivery.tv_usec = 0; 
    811 +               pvt->fr.data = pvt->sco_in_buf + AST_FRIENDLY_OFFSET; 
    812 +               chn->tech_pvt = pvt; 
    813 +               if (state == AST_STATE_RING) 
    814 +                       chn->rings = 1; 
    815 +               ast_copy_string(chn->context, pvt->context, sizeof(chn->context)); 
    816 +               ast_copy_string(chn->exten, "s", sizeof(chn->exten)); 
    817 +               ast_string_field_set(chn, language, "en"); 
    818 +               if (cid_num) 
    819 +                       chn->cid.cid_num = ast_strdup(cid_num); 
    820 +               chn->cid.cid_name = ast_strdup(pvt->id); 
    821 +               pvt->owner = chn; 
    822 + 
    823 +       } 
    824 + 
    825 +       return chn; 
    826 + 
    827 +} 
    828 + 
    829 +static int rfcomm_connect(char *bdaddr, int remote_channel) { 
    830 + 
    831 +       bdaddr_t dst; 
     897+/* 
     898+ 
     899+       Callback helpers 
     900+ 
     901+*/ 
     902+ 
     903+/* 
     904+ 
     905+       do_alignment_detection() 
     906+ 
     907+       This routine attempts to detect where we get misaligned sco audio data from the bluetooth adaptor. 
     908+ 
     909+       Its enabled by alignmentdetect=yes under the adapter entry in mobile.conf 
     910+ 
     911+       Some adapters suffer a problem where occasionally they will byte shift the audio stream one byte to the right. 
     912+       The result is static or white noise on the inbound (from the adapter) leg of the call. 
     913+       This is characterised by a sudden jump in magnitude of the value of the 16 bit samples. 
     914+ 
     915+       Here we look at the first 4 48 byte frames. We average the absolute values of each sample in the frame, 
     916+       then average the sum of the averages of frames 1, 2, and 3. 
     917+       Frame zero is usually zero. 
     918+       If the end result > 100, and it usually is if we have the problem, set a flag and compensate by shifting the bytes 
     919+       for each subsequent frame during the call. 
     920+ 
     921+       If the result is <= 100 then clear the flag so we dont come back in here... 
     922+ 
     923+       This seems to work OK.... 
     924+ 
     925+*/ 
     926+ 
     927+static void do_alignment_detection(struct mbl_pvt *pvt, char *buf, int buflen) 
     928+{ 
     929+ 
     930+       int i; 
     931+       short a, *s; 
     932+       char *p; 
     933+ 
     934+       if (pvt->alignment_detection_triggered) { 
     935+               for (i=buflen, p=buf+buflen-1; i>0; i--, p--) 
     936+                       *p = *(p-1); 
     937+               *(p+1) = 0; 
     938+               return; 
     939+       } 
     940+ 
     941+       if (pvt->alignment_count < 4) { 
     942+               s = (short *)buf; 
     943+               for (i=0, a=0; i<buflen/2; i++) { 
     944+                       a += *s++; 
     945+                       a /= i+1; 
     946+               } 
     947+               pvt->alignment_samples[pvt->alignment_count++] = a; 
     948+               return; 
     949+       } 
     950+ 
     951+       ast_log(LOG_DEBUG, "Alignment Detection result is [%-d %-d %-d %-d]\n", pvt->alignment_samples[0], pvt->alignment_samples[1], pvt->alignment_samples[2], pvt->alignment_samples[3]); 
     952+ 
     953+       a = abs(pvt->alignment_samples[1]) + abs(pvt->alignment_samples[2]) + abs(pvt->alignment_samples[3]); 
     954+       a /= 3; 
     955+       if (a > 100) { 
     956+               pvt->alignment_detection_triggered = 1; 
     957+               ast_log(LOG_DEBUG, "Alignment Detection Triggered.\n"); 
     958+       } else 
     959+               pvt->do_alignment_detection = 0; 
     960+ 
     961+} 
     962+ 
     963+/* 
     964+ 
     965+       rfcomm helpers 
     966+ 
     967+*/ 
     968+ 
     969+static int rfcomm_connect(bdaddr_t src, bdaddr_t dst, int remote_channel) { 
     970+ 
    832971+       struct sockaddr_rc addr; 
    833972+       int s; 
    834973+ 
    835 +       str2ba(bdaddr, &dst); 
    836 + 
    837974+       if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { 
    838 +               ast_debug(1, "socket() failed (%d).\n", errno); 
     975+               ast_log(LOG_DEBUG, "socket() failed (%d).\n", errno); 
     976+               return -1; 
     977+       } 
     978+ 
     979+       memset(&addr, 0, sizeof(addr)); 
     980+       addr.rc_family = AF_BLUETOOTH; 
     981+       bacpy(&addr.rc_bdaddr, &src); 
     982+       addr.rc_channel = (uint8_t) 1; 
     983+       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
     984+               ast_log(LOG_DEBUG, "bind() failed (%d).\n", errno); 
     985+               close(s); 
    839986+               return -1; 
    840987+       } 
     
    845992+       addr.rc_channel = remote_channel; 
    846993+       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
    847 +               ast_debug(1, "connect() failed (%d).\n", errno); 
     994+               ast_log(LOG_DEBUG, "connect() failed (%d).\n", errno); 
    848995+               close(s); 
    849996+               return -1; 
     
    8611008+       int len; 
    8621009+ 
    863 +       ast_debug(1, "rfcomm_write() (%s) [%s]\n", pvt->id, buf); 
     1010+       ast_log(LOG_DEBUG, "rfcomm_write() (%s) [%s]\n", pvt->id, buf); 
    8641011+       len = strlen(buf); 
    8651012+       p = buf; 
    8661013+       while (len > 0) { 
    8671014+               if ((num_write = write(pvt->rfcomm_socket, p, len)) == -1) { 
    868 +                       ast_debug(1, "rfcomm_write() error [%d]\n", errno); 
     1015+                       ast_log(LOG_DEBUG, "rfcomm_write() error [%d]\n", errno); 
    8691016+                       return 0; 
    8701017+               } 
     
    9431090+} 
    9441091+ 
    945 +static int sco_connect(char *bdaddr) 
    946 +{ 
    947 + 
    948 +       bdaddr_t dst; 
     1092+/* 
     1093+ 
     1094+       sco helpers 
     1095+ 
     1096+*/ 
     1097+ 
     1098+static int sco_connect(bdaddr_t src, bdaddr_t dst) 
     1099+{ 
     1100+ 
    9491101+       struct sockaddr_sco addr; 
    9501102+       int s; 
    9511103+ 
    952 +       str2ba(bdaddr, &dst); 
    953 + 
    9541104+       if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { 
    955 +               ast_debug(1, "socket() failed (%d).\n", errno); 
     1105+               ast_log(LOG_DEBUG, "socket() failed (%d).\n", errno); 
     1106+               return -1; 
     1107+       } 
     1108+ 
     1109+       memset(&addr, 0, sizeof(addr)); 
     1110+       addr.sco_family = AF_BLUETOOTH; 
     1111+       bacpy(&addr.sco_bdaddr, &src); 
     1112+       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
     1113+               ast_log(LOG_DEBUG, "bind() failed (%d).\n", errno); 
     1114+               close(s); 
    9561115+               return -1; 
    9571116+       } 
     
    9621121+ 
    9631122+       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
    964 +               ast_debug(1, "sco connect() failed (%d).\n", errno); 
     1123+               ast_log(LOG_DEBUG, "sco connect() failed (%d).\n", errno); 
    9651124+               close(s); 
    9661125+               return -1; 
     
    9711130+} 
    9721131+ 
     1132+static int sco_write(int s, char *buf, int len) 
     1133+{ 
     1134+ 
     1135+       int r; 
     1136+ 
     1137+       if (s == -1) { 
     1138+               ast_log(LOG_DEBUG, "sco_write() not ready\n"); 
     1139+               return 0; 
     1140+       } 
     1141+ 
     1142+       ast_log(LOG_DEBUG, "sco_write()\n"); 
     1143+ 
     1144+       r = write(s, buf, len); 
     1145+       if (r == -1) { 
     1146+               ast_log(LOG_DEBUG, "sco write error %d\n", errno); 
     1147+               return 0; 
     1148+       } 
     1149+ 
     1150+       return 1; 
     1151+ 
     1152+} 
     1153+ 
     1154+static int sco_read(int s, char *buf, int len) 
     1155+{ 
     1156+ 
     1157+       int r; 
     1158+ 
     1159+       if (s == -1) { 
     1160+               ast_log(LOG_DEBUG, "sco_read() not ready\n"); 
     1161+               return 0; 
     1162+       } 
     1163+ 
     1164+       ast_log(LOG_DEBUG, "sco_read()\n"); 
     1165+ 
     1166+       r = read(s, buf, len); 
     1167+       if (r == -1) { 
     1168+               ast_log(LOG_DEBUG, "sco_read() error %d\n", errno); 
     1169+               return 0; 
     1170+       } 
     1171+ 
     1172+       return r; 
     1173+ 
     1174+} 
     1175+ 
    9731176+/* 
    9741177+ 
    975 +       sdp_search() performs a service discovery on the given device to determine whether 
    976 +       or not it supports the Handsfree Profile. 
     1178+       sdp helpers 
    9771179+ 
    9781180+*/ 
     
    9941196+       session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY); 
    9951197+       if (!session) { 
    996 +               ast_debug(1, "sdp_connect() failed on device %s.\n", addr); 
     1198+               ast_log(LOG_DEBUG, "sdp_connect() failed on device %s.\n", addr); 
    9971199+               return 0; 
    9981200+       } 
     
    10141216+                       sdp_list_free(response_list, 0); 
    10151217+               } else 
    1016 +                       ast_debug(1, "No responses returned for device %s.\n", addr); 
     1218+                       ast_log(LOG_DEBUG, "No responses returned for device %s.\n", addr); 
    10171219+       } else 
    1018 +               ast_debug(1, "sdp_service_search_attr_req() failed on device %s.\n", addr); 
    1019 + 
     1220+               ast_log(LOG_DEBUG, "sdp_service_search_attr_req() failed on device %s.\n", addr); 
    10201221+ 
    10211222+       sdp_list_free(search_list, 0); 
     
    10261227+ 
    10271228+} 
    1028 + 
    1029 +/* 
    1030 + 
    1031 +       sdp_register() 
    1032 + 
    1033 +       Register GENERIC_AUDIO & HEADSET with the SDP daemon on the Asterisk Box. 
    1034 +       This assists connections to phones/pda's with dud bluetooth stacks like the IMate Jasjam 
    1035 +       and some Nokia's 
    1036 + 
    1037 +*/ 
    10381229+ 
    10391230+static sdp_session_t *sdp_register(void) 
     
    11011292+/* 
    11021293+ 
    1103 +       Phone Monitor Thread 
    1104 + 
    1105 +       This thread is spun once a phone device is discovered and considered capable of being used, i.e. supports Handsfree Profile, 
    1106 +       and its configured in mobile.conf. 
    1107 +       The thread lives for the lifetime of the bluetooth connection, and handles the 'control' side of all calls. 
     1294+       Thread routines 
    11081295+ 
    11091296+*/ 
     
    11221309+       char brsf, nsmode, *p, *p1; 
    11231310+       char sms_src[13]; 
    1124 +       char sms_txt[161]; 
     1311+       char sms_txt[160]; 
    11251312+ 
    11261313+       brsf = nsmode = 0; 
     
    11451332+ 
    11461333+               if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) { 
    1147 +                       ast_debug(1, "rfcomm_read() (%s) [%s]\n", pvt->id, buf); 
     1334+                       ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf); 
    11481335+                       switch (pvt->state) { 
    11491336+                       case MBL_STATE_INIT: 
    11501337+                               if (strstr(buf, "+BRSF:")) { 
    11511338+                                       brsf = 1; 
    1152 +                               } else if (strstr(buf, "ERROR") && !nsmode) { /* Hmmm, Non-Standard Phone, just continue */ 
     1339+                               } else if (strstr(buf, "ERROR") && !nsmode) {   /* Hmmm, Non-Standard Phone, just continue */ 
    11531340+                                       rfcomm_write(pvt, "AT+CIND=?\r"); 
    11541341+                                       pvt->state++; 
    11551342+                                       nsmode = 1; 
    11561343+                               } else if (strstr(buf, "OK") && brsf) { 
    1157 +                                       rfcomm_write(pvt, "AT+CIND=?\r"); 
    1158 +                                       pvt->state++; 
     1344+                                       if (pvt->blackberry) { 
     1345+                                               rfcomm_write(pvt, "AT+CMER=3,0,0,1\r"); 
     1346+                                               pvt->state = MBL_STATE_INIT3; 
     1347+                                       } else { 
     1348+                                               rfcomm_write(pvt, "AT+CIND=?\r"); 
     1349+                                               pvt->state++; 
     1350+                                       } 
    11591351+                               } 
    11601352+                               break; 
     
    11721364+                                               } 
    11731365+                                               if (strstr(buf+i, "\"call\"")) 
    1174 +                                                       callp = group2;  
     1366+                                                       callp = group2; 
    11751367+                                               if (strstr(buf+i, "\"call_setup\"")) 
    11761368+                                                       callsetupp = group2; 
     
    11781370+                                                       callsetupp = group2; 
    11791371+                                       } 
    1180 +                                       sprintf(pvt->ciev_call_0, "%d,0", callp); 
    1181 +                                       sprintf(pvt->ciev_call_1, "%d,1", callp); 
    1182 +                                       sprintf(pvt->ciev_callsetup_0, "%d,0", callsetupp); 
    1183 +                                       sprintf(pvt->ciev_callsetup_1, "%d,1", callsetupp); 
    1184 +                                       sprintf(pvt->ciev_callsetup_2, "%d,2", callsetupp); 
    1185 +                                       sprintf(pvt->ciev_callsetup_3, "%d,3", callsetupp); 
     1372+                                       snprintf(pvt->ciev_call_0, sizeof(pvt->ciev_call_0), "%d,0", callp); 
     1373+                                       snprintf(pvt->ciev_call_1, sizeof(pvt->ciev_call_1), "%d,1", callp); 
     1374+                                       snprintf(pvt->ciev_callsetup_0, sizeof(pvt->ciev_callsetup_0), "%d,0", callsetupp); 
     1375+                                       snprintf(pvt->ciev_callsetup_1, sizeof(pvt->ciev_callsetup_1), "%d,1", callsetupp); 
     1376+                                       snprintf(pvt->ciev_callsetup_2, sizeof(pvt->ciev_callsetup_2), "%d,2", callsetupp); 
     1377+                                       snprintf(pvt->ciev_callsetup_3, sizeof(pvt->ciev_callsetup_3), "%d,3", callsetupp); 
    11861378+                                       if (callsetupp == 0) /* This phone has no call setup indication!! ... */ 
    11871379+                                               pvt->no_callsetup = 1; 
    1188 +                                       ast_debug(1, "CIEV_CALL=%d CIEV_CALLSETUP=%d\n", callp, callsetupp); 
     1380+                                       ast_log(LOG_DEBUG, "CIEV_CALL=%d CIEV_CALLSETUP=%d\n", callp, callsetupp); 
    11891381+                               } 
    11901382+                               if (strstr(buf, "OK")) { 
     
    12011393+                                       } 
    12021394+                               } else if (strstr(buf, "OK")) { 
    1203 +                                       rfcomm_write(pvt, "AT+CMER=3,0,0,1\r"); 
    1204 +                                       pvt->state++; 
     1395+                                       if (pvt->blackberry) { 
     1396+                                               rfcomm_write(pvt, "AT+CLIP=1\r"); 
     1397+                                               pvt->state = MBL_STATE_INIT4; 
     1398+                                       } else { 
     1399+                                               rfcomm_write(pvt, "AT+CMER=3,0,0,1\r"); 
     1400+                                               pvt->state++; 
     1401+                                       } 
    12051402+                               } 
    12061403+                               break; 
    12071404+                       case MBL_STATE_INIT3: 
    12081405+                               if (strstr(buf, "OK")) { 
    1209 +                                       rfcomm_write(pvt, "AT+CLIP=1\r"); 
     1406+                                       if (pvt->blackberry) { 
     1407+                                               rfcomm_write(pvt, "AT+CIND=?\r"); 
     1408+                                               pvt->state = MBL_STATE_INIT1; 
     1409+                                       } else { 
     1410+                                               rfcomm_write(pvt, "AT+CLIP=1\r"); 
     1411+                                               pvt->state++; 
     1412+                                       } 
     1413+                               } 
     1414+                               break; 
     1415+                       case MBL_STATE_INIT4: 
     1416+                               if (strstr(buf, "OK")) { 
     1417+                                       rfcomm_write(pvt, "AT+VGS=15\r"); 
    12101418+                                       pvt->state++; 
    12111419+                               } 
    12121420+                               break; 
    1213 +                       case MBL_STATE_INIT4: 
     1421+                       case MBL_STATE_INIT5: 
    12141422+                               if (strstr(buf, "OK")) { 
    12151423+                                       rfcomm_write(pvt, "AT+CMGF=1\r"); 
     
    12171425+                               } 
    12181426+                               break; 
    1219 +                       case MBL_STATE_INIT5: 
    1220 +                               if (strstr(buf, "ERROR")) { /* No SMS Support ! */ 
     1427+                       case MBL_STATE_INIT6: 
     1428+                               if (strstr(buf, "ERROR")) {     /* No SMS Support ! */ 
    12211429+                                       pvt->state = MBL_STATE_PREIDLE; 
    12221430+                               } else if (strstr(buf, "OK")) { 
     
    12251433+                               } 
    12261434+                               break; 
    1227 +                       case MBL_STATE_INIT6: 
    1228 +                               if (strstr(buf, "OK")) { /* We have SMS Support */ 
     1435+                       case MBL_STATE_INIT7: 
     1436+                               if (strstr(buf, "OK")) {        /* We have SMS Support */ 
    12291437+                                       pvt->has_sms = 1; 
    12301438+                                       pvt->state = MBL_STATE_PREIDLE; 
    12311439+                               } else if (strstr(buf, "ERROR")) { 
    12321440+                                       pvt->has_sms = 0; 
    1233 +                                       ast_log(LOG_NOTICE,"Device %s has no bluetooth SMS capability.\n", pvt->id); 
    12341441+                                       pvt->state = MBL_STATE_PREIDLE; 
    12351442+                               } 
     
    12381445+                               break; 
    12391446+                       case MBL_STATE_IDLE: 
    1240 +                               ast_debug(1, "Device %s %s [%s]\n", pvt->bdaddr, pvt->id, buf); 
     1447+                               ast_log(LOG_DEBUG, "Device %s [%s]\n", pvt->id, buf); 
    12411448+                               if (strstr(buf, "RING")) { 
    12421449+                                       pvt->state = MBL_STATE_RING; 
     
    12621469+                               if (strstr(buf, "+CIEV")) { 
    12631470+                                       if (strstr(buf, pvt->ciev_call_0)) {                            /* call was hung up */ 
     1471+                                               pvt->do_hangup = 0; 
    12641472+                                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP); 
    12651473+                                       } else if (strstr(buf, pvt->ciev_callsetup_3)) {                /* b-party ringing */ 
     
    12791487+                                               } 
    12801488+                                       } 
    1281 +                                       pvt->sco_out_ptr = pvt->sco_out_buf; 
    1282 +                                       pvt->sco_out_len = 0; 
    1283 +                                       pvt->sent_answer = 0; 
    12841489+                                       chn = mbl_new(AST_STATE_RING, pvt, cid_num); 
    12851490+                                       if (chn) { 
     
    12971502+                               break; 
    12981503+                       case MBL_STATE_RING2: 
    1299 +                               pvt->sco_out_ptr = pvt->sco_out_buf; 
    1300 +                               pvt->sco_out_len = 0; 
    1301 +                               pvt->sent_answer = 0; 
    13021504+                               chn = mbl_new(AST_STATE_RING, pvt, cid_num); 
    13031505+                               if (chn) { 
     
    13201522+                                               } else {                /* User answered on handset!, disconnect */ 
    13211523+                                                       pvt->state = MBL_STATE_IDLE; 
    1322 +                                                       ast_log(LOG_NOTICE,"Closing the sco_socket in RING3 with CIEV\n"); 
    13231524+                                                       if (pvt->sco_socket > -1) 
    13241525+                                                               close(pvt->sco_socket); 
     
    13341535+                               if (strstr(buf, "+CIEV")) { 
    13351536+                                       if (strstr(buf, pvt->ciev_call_0)) { 
     1537+                                               pvt->do_hangup = 0; 
    13361538+                                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP); 
    13371539+                                       } 
     
    13401542+                       case MBL_STATE_HANGUP: 
    13411543+                               if (strstr(buf, "OK") || strstr(buf, pvt->ciev_call_0)) { 
     1544+                                       close(pvt->sco_socket); 
     1545+                                       pvt->sco_socket = -1; 
    13421546+                                       pvt->state = MBL_STATE_IDLE; 
    13431547+                               } 
     
    13651569+                                       pvt->state = MBL_STATE_IDLE; 
    13661570+                               } else { 
    1367 +                                       memset(sms_txt, 0x00, sizeof(sms_txt)); 
    1368 +                                       strncpy(sms_txt, buf, strlen(buf)); 
     1571+                                       ast_copy_string(sms_txt, buf, sizeof(sms_txt)); 
    13691572+                               } 
    13701573+                               break; 
     
    13861589+                                       smsi = atoi(p); 
    13871590+                                       if (smsi > 0) { 
    1388 +                                               sprintf(buf, "AT+CMGR=%d\r", smsi); 
     1591+                                               snprintf(buf, sizeof(buf), "AT+CMGR=%d\r", smsi); 
    13891592+                                               rfcomm_write(pvt, buf); 
    13901593+                                               pvt->state = MBL_STATE_INSMS; 
     
    13981601+                               rfcomm_write(pvt, "AT+CMER=3,0,0,1\r"); 
    13991602+                       } else if (pvt->state == MBL_STATE_INIT3) { /* Some devices dont respond to AT+CMER=3,0,0,1 properly. VK 2020 for example */ 
    1400 +                                 pvt->state++; 
    1401 +                                 rfcomm_write(pvt, "AT+CLIP=1\r"); 
     1603+                               pvt->state++; 
     1604+                               rfcomm_write(pvt, "AT+CLIP=1\r"); 
    14021605+                       } else if (pvt->state == MBL_STATE_PREIDLE) { 
    14031606+                               pvt->connected = 1; 
     
    14051608+                               pvt->state = MBL_STATE_IDLE; 
    14061609+                       } else if (pvt->state == MBL_STATE_DIAL) { 
    1407 +                               sprintf(buf, "ATD%s;\r", pvt->dial_number); 
     1610+                               snprintf(buf, sizeof(buf), "ATD%s;\r", pvt->dial_number); 
    14081611+                               if (!rfcomm_write(pvt, buf)) { 
    14091612+                                       ast_log(LOG_ERROR, "Dial failed on %s state %d\n", pvt->owner->name, pvt->state); 
     
    14211624+                               pvt->state = MBL_STATE_RING2; 
    14221625+                       } else if (pvt->state == MBL_STATE_HANGUP) { 
    1423 +                               if (pvt->hangup_count == 6) { 
    1424 +                                       ast_debug(1, "Device %s failed to hangup after 6 tries, disconnecting.\n", pvt->id); 
    1425 +                                       monitor = 0; 
    1426 +                               } 
    1427 +                               rfcomm_write(pvt, "AT+CHUP\r"); 
    1428 +                               pvt->hangup_count++; 
     1626+                               if (pvt->do_hangup) { 
     1627+                                       if (pvt->hangup_count == 6) { 
     1628+                                               ast_log(LOG_DEBUG, "Device %s failed to hangup after 6 tries, disconnecting.\n", pvt->id); 
     1629+                                               monitor = 0; 
     1630+                                       } 
     1631+                                       rfcomm_write(pvt, "AT+CHUP\r"); 
     1632+                                       pvt->hangup_count++; 
     1633+                               } else 
     1634+                                       pvt->state = MBL_STATE_IDLE; 
    14291635+                       } else if (pvt->state == MBL_STATE_OUTSMS) { 
    1430 +                               sprintf(buf, "AT+CMGS=\"%s\"\r", pvt->dial_number); 
     1636+                               snprintf(buf, sizeof(buf), "AT+CMGS=\"%s\"\r", pvt->dial_number); 
    14311637+                               rfcomm_write(pvt, buf); 
    14321638+                               pvt->state = MBL_STATE_OUTSMS1; 
    14331639+                       } else if (pvt->state == MBL_STATE_OUTSMS1) { 
    14341640+                               if (pvt->rfcomm_buf[0] == '>') { 
    1435 +                                       sprintf(buf, "%s%c", pvt->sms_txt, 0x1a); 
     1641+                                       snprintf(buf, sizeof(buf), "%s%c", pvt->sms_txt, 0x1a); 
    14361642+                                       rfcomm_write(pvt, buf); 
    14371643+                                       pvt->state = MBL_STATE_OUTSMS2; 
     
    14521658+       } 
    14531659+ 
    1454 +       close(pvt->rfcomm_socket); 
    1455 +       close(pvt->sco_socket); 
     1660+       if (pvt->rfcomm_socket > -1) 
     1661+               close(pvt->rfcomm_socket); 
     1662+       if (pvt->sco_socket > -1) 
     1663+               close(pvt->sco_socket); 
    14561664+       pvt->sco_socket = -1; 
    14571665+       pvt->connected = 0; 
    14581666+       pvt->monitor_thread = AST_PTHREADT_NULL; 
    14591667+ 
     1668+       pthread_cancel(pvt->sco_listener_thread); 
     1669+       pthread_join(pvt->sco_listener_thread, NULL); 
     1670+       pvt->sco_listener_thread = AST_PTHREADT_NULL; 
     1671+ 
     1672+       close(pvt->adapter->sco_socket); 
     1673+ 
     1674+       manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id); 
     1675+ 
     1676+       pvt->adapter->inuse = 0; 
     1677+ 
    14601678+       return NULL; 
    14611679+ 
    14621680+} 
    1463 + 
    1464 +/* 
    1465 + 
    1466 +       Headset Monitor Thread 
    1467 + 
    1468 +       This thread is spun once a headset device is discovered and considered capable of being used, i.e. supports Headset Profile, 
    1469 +       and its configured in mobile.conf. 
    1470 +       The thread lives for the lifetime of the bluetooth connection, and handles the 'control' side of all calls. 
    1471 + 
    1472 +*/ 
    14731681+ 
    14741682+static void *do_monitor_headset(void *data) 
     
    14911699+ 
    14921700+               if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) { 
    1493 +                       ast_debug(1, "rfcomm_read() (%s) [%s]\n", pvt->id, buf); 
     1701+                       ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf); 
    14941702+                       switch (pvt->state) { 
    14951703+                       case MBL_STATE_RING2: 
    14961704+                               if (strstr(buf, "AT+CKPD=")) { 
    1497 +                                       ast_channel_lock(pvt->owner); 
    1498 +                                       pvt->owner->fds[0] = pvt->sco_socket; 
    1499 +                                       ast_log(LOG_NOTICE,"pvt-sco_socket used for fds in headphone code\n"); 
    1500 +                                       ast_channel_unlock(pvt->owner); 
    15011705+                                       ast_queue_control(pvt->owner, AST_CONTROL_ANSWER); 
    15021706+                                       pvt->state = MBL_STATE_INCOMING; 
     
    15241728+                               pvt->state = MBL_STATE_IDLE; 
    15251729+                       } else if (pvt->state == MBL_STATE_RING) { 
    1526 +                               pvt->sco_socket = sco_connect(pvt->bdaddr); 
     1730+                               pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr); 
    15271731+                               if (pvt->sco_socket > -1) { 
    1528 +                                       ast_log(LOG_NOTICE,"sco_connect returned -1 in state RING\n"); 
    15291732+                                       ast_setstate(pvt->owner, AST_STATE_RINGING); 
    15301733+                                       ast_queue_control(pvt->owner, AST_CONTROL_RINGING); 
     
    15441747+       } 
    15451748+ 
     1749+       if (pvt->rfcomm_socket > -1) 
     1750+               close(pvt->rfcomm_socket); 
     1751+       if (pvt->sco_socket > -1) 
     1752+               close(pvt->sco_socket); 
     1753+       pvt->sco_socket = -1; 
     1754+       pvt->connected = 0; 
     1755+       pvt->monitor_thread = AST_PTHREADT_NULL; 
     1756+ 
     1757+       manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Disconnect\r\nDevice: %s\r\n", pvt->id); 
     1758+ 
     1759+       pvt->adapter->inuse = 0; 
     1760+ 
    15461761+       return NULL; 
    15471762+ 
     
    15561771+                       return 0; 
    15571772+               } 
     1773+               /* we are a phone, so spin the sco listener on the adapter as well */ 
     1774+               if (ast_pthread_create_background(&pvt->sco_listener_thread, NULL, do_sco_listen, pvt->adapter) < 0) { 
     1775+                       ast_log(LOG_ERROR, "Unable to create sco listener thread for device %s.\n", pvt->id); 
     1776+               } 
     1777+ 
    15581778+       } else { 
    15591779+               if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_headset, pvt) < 0) { 
     
    15671787+} 
    15681788+ 
    1569 +/* 
    1570 + 
    1571 +       Device Discovery Thread. 
    1572 + 
    1573 +       This thread wakes every 'discovery_interval' seconds and trys to connect to 
    1574 +       those configured devices which are not connected. This saves the user from having 
    1575 +       to manually connect his/her cell phone to the asterisk box. Once a successful 
    1576 +       connection is made, a monitor thread is spun on the device which lives for the 
    1577 +       lifetime of the connection. 
    1578 + 
    1579 +*/ 
    1580 + 
    15811789+static void *do_discovery(void *data) 
    15821790+{ 
    15831791+ 
    1584 +       struct mbl_pvt *pvt = data; 
     1792+       struct adapter_pvt *adapter; 
     1793+       struct mbl_pvt *pvt; 
    15851794+ 
    15861795+       for (;;) { 
    1587 +               AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    1588 +                       if (!pvt->connected) { 
    1589 +                               if ((pvt->rfcomm_socket = rfcomm_connect(pvt->bdaddr, pvt->rfcomm_port)) > -1) { 
    1590 +                                       pvt->state = 0; 
    1591 +                                       if (start_monitor(pvt)) { 
    1592 +                                               pvt->connected = 1; 
    1593 +                                               if (option_verbose > 2) 
    1594 +                                                       ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has connected.\n", pvt->id); 
     1796+               AST_RWLIST_RDLOCK(&adapters); 
     1797+               AST_RWLIST_TRAVERSE(&adapters, adapter, entry) { 
     1798+                       if (!adapter->inuse) { 
     1799+                               AST_RWLIST_RDLOCK(&devices); 
     1800+                               AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     1801+                                       if (!adapter->inuse && !pvt->connected && !strcmp(adapter->id, pvt->adapter->id)) { 
     1802+                                               if ((pvt->rfcomm_socket = rfcomm_connect(adapter->addr, pvt->addr, pvt->rfcomm_port)) > -1) { 
     1803+                                                       pvt->state = 0; 
     1804+                                                       if (start_monitor(pvt)) { 
     1805+                                                               pvt->connected = 1; 
     1806+                                                               adapter->inuse = 1; 
     1807+                                                               manager_event(EVENT_FLAG_SYSTEM, "MobileStatus", "Status: Connect\r\nDevice: %s\r\n", pvt->id); 
     1808+                                                               if (option_verbose > 2) 
     1809+                                                                       ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has connected.\n", pvt->id); 
     1810+                                                       } 
     1811+                                               } 
    15951812+                                       } 
    15961813+                               } 
     1814+                               AST_RWLIST_UNLOCK(&devices); 
    15971815+                       } 
    15981816+               } 
     1817+               AST_RWLIST_UNLOCK(&adapters); 
    15991818+               /* Go to sleep */ 
    16001819+               sleep(discovery_interval); 
     
    16041823+} 
    16051824+ 
    1606 +/* 
    1607 + 
    1608 +       This thread listens for incoming sco connections. 
    1609 +       Although the Bluetooth Handsfree Profile Specification says that either end may initiate the audio connection, 
    1610 +       in practice some devices (LG TU500) get upset unless they initiate the connection. 
    1611 +       We leave all sco initiation to the device. 
    1612 +       On an inbound sco connection, we need to find the appropriate device, and set the channel fd accordingly. 
    1613 + 
    1614 +*/ 
    1615 + 
    16161825+static void *do_sco_listen(void *data) 
    16171826+{ 
    16181827+ 
    16191828+       int ns; 
    1620 +       bdaddr_t local; 
    16211829+       struct sockaddr_sco addr; 
     1830+       char saddr[18]; 
    16221831+       struct sco_options so; 
    16231832+       socklen_t len; 
    16241833+       int opt = 1; 
    1625 +       char saddr[18]; 
    16261834+       socklen_t addrlen; 
    16271835+       struct mbl_pvt *pvt; 
    1628 + 
    1629 +       hci_devba(0, &local); 
    1630 + 
    1631 +       if ((sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { 
     1836+       struct adapter_pvt *adapter = (struct adapter_pvt *) data; 
     1837+ 
     1838+       if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) { 
    16321839+               ast_log(LOG_ERROR, "Unable to create sco listener socket.\n"); 
    16331840+               return NULL; 
     
    16351842+       memset(&addr, 0, sizeof(addr)); 
    16361843+       addr.sco_family = AF_BLUETOOTH; 
    1637 +       bacpy(&addr.sco_bdaddr, &local); 
    1638 +       if (bind(sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
     1844+       bacpy(&addr.sco_bdaddr, &adapter->addr); 
     1845+       if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 
    16391846+               ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno); 
    1640 +               close(sco_socket); 
     1847+               close(adapter->sco_socket); 
    16411848+               return NULL; 
    16421849+       } 
    1643 +       if (setsockopt(sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { 
     1850+       if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { 
    16441851+               ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n"); 
    1645 +               close(sco_socket); 
     1852+               close(adapter->sco_socket); 
    16461853+               return NULL; 
    16471854+       } 
    1648 +       if (listen(sco_socket, 5) < 0) { 
     1855+       if (listen(adapter->sco_socket, 5) < 0) { 
    16491856+               ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n"); 
    1650 +               close(sco_socket); 
     1857+               close(adapter->sco_socket); 
    16511858+               return NULL; 
    16521859+       } 
    16531860+       while (1) { 
    1654 +               addrlen = sizeof(struct sockaddr); 
    1655 +               ast_log(LOG_NOTICE, "About to accept the sco_socket...\n"); 
    1656 +               if ((ns = accept(sco_socket, (struct sockaddr *)&addr, &addrlen)) > -1) { 
    1657 +                       ast_log(LOG_NOTICE, "sco_socket returns %d...\n",ns); 
    1658 +                       ba2str(&addr.sco_bdaddr, saddr); 
    1659 + 
     1861+               ast_log(LOG_DEBUG, "About to accept() socket.\n"); 
     1862+               addrlen = sizeof(struct sockaddr_sco); 
     1863+               if ((ns = accept(adapter->sco_socket, (struct sockaddr *)&addr, &addrlen)) > -1) { 
     1864+                       ast_log(LOG_DEBUG, "accept()ed socket.\n"); 
    16601865+                       len = sizeof(so); 
    16611866+                       getsockopt(ns, SOL_SCO, SCO_OPTIONS, &so, &len); 
    16621867+ 
    1663 +                       ast_debug(1, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu); 
     1868+                       ba2str(&addr.sco_bdaddr, saddr); 
     1869+                       ast_log(LOG_DEBUG, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu); 
    16641870+ 
    16651871+                       pvt = NULL; 
    1666 +                       AST_LIST_TRAVERSE(&devices, pvt, entry) { 
    1667 +                               if (!strcmp(pvt->bdaddr, saddr)) 
     1872+                       AST_RWLIST_RDLOCK(&devices); 
     1873+                       AST_RWLIST_TRAVERSE(&devices, pvt, entry) { 
     1874+                               if (!bacmp(&pvt->addr, &addr.sco_bdaddr))  
    16681875+                                       break; 
    16691876+                       } 
     1877+                       AST_RWLIST_UNLOCK(&devices); 
    16701878+                       if (pvt) { 
    1671 +                               ast_log(LOG_NOTICE,"about to close the pvt-sco_socket and set it ns\n"); 
    16721879+                               if (pvt->sco_socket != -1) 
    16731880+                                       close(pvt->sco_socket); 
    16741881+                               pvt->sco_socket = ns; 
    1675 +                               if (pvt->owner) { 
    1676 +                                       ast_channel_lock(pvt->owner); 
    1677 +                                       pvt->owner->fds[0] = ns; 
    1678 +                                       ast_channel_unlock(pvt->owner); 
    1679 +                               } 
    16801882+                       } else 
    1681 +                               ast_debug(1, "Could not find device for incoming Audio Connection.\n"); 
    1682 +               } 
    1683 +               else ast_log(LOG_NOTICE, "Accept got a -1...."); 
     1883+                               ast_log(LOG_DEBUG, "Could not find device for incoming Audio Connection.\n"); 
     1884+               } else { 
     1885+                        ast_log(LOG_ERROR, "accept() failed %d\n", errno); 
     1886+               } 
    16841887+       } 
    16851888+ 
     
    16871890+ 
    16881891+} 
     1892+ 
     1893+/* 
     1894+ 
     1895+       Module 
     1896+ 
     1897+*/ 
    16891898+ 
    16901899+static int mbl_load_config(void) 
     
    16941903+       char *cat = NULL; 
    16951904+       struct ast_variable *var; 
    1696 +       const char *address, *port, *context, *type, *skip; 
     1905+       const char *id, *address, *useadapter, *port, *context, *type, *skip, *group, *master, *nocallsetup, *aligndetect, *blackberry; 
    16971906+       struct mbl_pvt *pvt; 
     1907+       struct adapter_pvt *adapter; 
     1908+       uint16_t vs; 
     1909+       struct hci_dev_req dr; 
     1910+       char nadapters = 0; 
     1911+       // struct ast_flags config_flags = { 0 }; 
    16981912+ 
    16991913+       cfg = ast_config_load(MBL_CONFIG); 
     
    17061920+       } 
    17071921+ 
     1922+       /* load adapters first */ 
    17081923+       cat = ast_category_browse(cfg, NULL); 
    17091924+       while (cat) { 
    1710 +               if (strcasecmp(cat, "general")) { 
    1711 +                       ast_debug(1, "Loading device %s.\n", cat); 
     1925+               if (!strcasecmp(cat, "adapter")) { 
     1926+                       id = ast_variable_retrieve(cfg, cat, "id"); 
    17121927+                       address = ast_variable_retrieve(cfg, cat, "address"); 
     1928+                       master = ast_variable_retrieve(cfg, cat, "forcemaster"); 
     1929+                       aligndetect = ast_variable_retrieve(cfg, cat, "alignmentdetection"); 
     1930+                       ast_log(LOG_DEBUG, "Loading adapter %s %s.\n", id, address); 
     1931+                       if (!ast_strlen_zero(id) && !ast_strlen_zero(address)) { 
     1932+                               if ((adapter = ast_calloc(1, sizeof(*adapter)))) { 
     1933+                                       ast_copy_string(adapter->id, id, sizeof(adapter->id)); 
     1934+                                       str2ba(address, &adapter->addr); 
     1935+                                       if (!ast_strlen_zero(aligndetect)) { 
     1936+                                               if (*aligndetect == 'Y' || *aligndetect == 'y') 
     1937+                                                       adapter->alignment_detection = 1; 
     1938+                                       } 
     1939+                                       adapter->dev_id = hci_devid(address); 
     1940+                                       adapter->hci_socket = hci_open_dev(adapter->dev_id); 
     1941+                                       if (adapter->dev_id < 0 || adapter->hci_socket < 0) { 
     1942+                                               ast_log(LOG_ERROR, "Unable to open adapter %s. It won't be enabled.\n", adapter->id); 
     1943+                                               ast_free(adapter); 
     1944+                                       } else { 
     1945+                                               if ((master) && (*master)) { 
     1946+                                                       dr.dev_id = adapter->dev_id; 
     1947+                                                       if (hci_strtolm("master", &dr.dev_opt)) { 
     1948+                                                               if (ioctl(adapter->hci_socket, HCISETLINKMODE, (unsigned long) &dr) < 0) { 
     1949+                                                                       ast_log(LOG_WARNING, "Unable to set adapter %s link mode to MASTER.\n", adapter->id); 
     1950+                                                               } 
     1951+                                                       } 
     1952+                                               } 
     1953+                                               hci_read_voice_setting(adapter->hci_socket, &vs, 1000); 
     1954+                                               vs = htobs(vs); 
     1955+                                               if (vs != 0x0060) { 
     1956+                                                       ast_log(LOG_ERROR, "Incorrect voice setting for adapter %s, it must be 0x0060 - see 'man hciconfig' for details.\n", adapter->id); 
     1957+                                                       hci_close_dev(adapter->hci_socket); 
     1958+                                                       ast_free(adapter); 
     1959+                                               } else { 
     1960+                                                       AST_RWLIST_WRLOCK(&adapters); 
     1961+                                                       AST_RWLIST_INSERT_HEAD(&adapters, adapter, entry); 
     1962+                                                       AST_RWLIST_UNLOCK(&adapters); 
     1963+                                                       nadapters++; 
     1964+                                               } 
     1965+                                       } 
     1966+                               } 
     1967+                       } else 
     1968+                               ast_log(LOG_ERROR, "id/address missing for adapter %s. It won't be enabled.\n", cat); 
     1969+               } 
     1970+               cat = ast_category_browse(cfg, cat); 
     1971+       } 
     1972+ 
     1973+       if (!nadapters) { 
     1974+               ast_log(LOG_WARNING, "***********************************************************************\n"); 
     1975+               ast_log(LOG_WARNING, "No Adapters defined. Please review mobile.conf. See sample for details.\n"); 
     1976+               ast_log(LOG_WARNING, "***********************************************************************\n"); 
     1977+       } 
     1978+ 
     1979+       /* now load devices */ 
     1980+       cat = ast_category_browse(cfg, NULL); 
     1981+       while (cat) { 
     1982+               if (strcasecmp(cat, "general") && strcasecmp(cat, "adapter")) { 
     1983+                       ast_log(LOG_DEBUG, "Loading device %s.\n", cat); 
     1984+                       address = ast_variable_retrieve(cfg, cat, "address"); 
     1985+                       useadapter = ast_variable_retrieve(cfg, cat, "adapter"); 
    17131986+                       port = ast_variable_retrieve(cfg, cat, "port"); 
    17141987+                       context = ast_variable_retrieve(cfg, cat, "context"); 
    1715 +                       ast_log(LOG_NOTICE, "context for non-general category %s was %s\n", cat, context); 
    17161988+                       type = ast_variable_retrieve(cfg, cat, "type"); 
    17171989+                       skip = ast_variable_retrieve(cfg, cat, "dtmfskip"); 
    1718 +                       if (address && port) { 
    1719 +                               if ((pvt = ast_malloc(sizeof(struct mbl_pvt)))) { 
     1990+                       group = ast_variable_retrieve(cfg, cat, "group"); 
     1991+                       nocallsetup = ast_variable_retrieve(cfg, cat, "nocallsetup"); 
     1992+                       blackberry = ast_variable_retrieve(cfg, cat, "blackberry"); 
     1993+                       if (!ast_strlen_zero(address) && !ast_strlen_zero(port) && !ast_strlen_zero(useadapter)) { 
     1994+                               /* find the adapter */ 
     1995+                               AST_RWLIST_RDLOCK(&adapters); 
     1996+                               AST_RWLIST_TRAVERSE(&adapters, adapter, entry) { 
     1997+                                       if (!strcmp(adapter->id, useadapter)) 
     1998+                                               break; 
     1999+                               } 
     2000+                               AST_RWLIST_UNLOCK(&adapters); 
     2001+                               if (!adapter) { 
     2002+                                       ast_log(LOG_ERROR, "Device %s configured to use unknown adapter %s. It won't be enabled.\n", cat, useadapter); 
     2003+                                       break; 
     2004+                               } 
     2005+                               if ((pvt = ast_calloc(1, sizeof(*pvt)))) { 
    17202006+                                       if (type && !strcmp(type, "headset")) 
    17212007+                                               pvt->type = MBL_TYPE_HEADSET; 
    17222008+                                       else 
    17232009+                                               pvt->type = MBL_TYPE_PHONE; 
     2010+ 
     2011+                                       if (blackberry) 
     2012+                                               pvt->blackberry = ast_true(blackberry); 
     2013+ 
    17242014+                                       ast_copy_string(pvt->id, cat, sizeof(pvt->id)); 
    1725 +                                       ast_copy_string(pvt->bdaddr, address, sizeof(pvt->bdaddr)); 
     2015+                                       str2ba(address, &pvt->addr); 
    17262016+                                       ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context)); 
    1727 +                                       pvt->connected = 0; 
     2017+                                       if (group) 
     2018+                                               pvt->group = atoi(group);       /* group 0 if invalid */ 
    17282019+                                       pvt->state = MBL_STATE_INIT; 
    17292020+                                       pvt->rfcomm_socket = -1; 
    17302021+                                       pvt->rfcomm_port = atoi(port); 
    1731 +                                       pvt->rfcomm_buf[0] = 0x00; 
    17322022+                                       pvt->sco_socket = -1; 
    17332023+                                       pvt->monitor_thread = AST_PTHREADT_NULL; 
    1734 +                                       pvt->owner = NULL; 
    1735 +                                       pvt->no_callsetup = 0; 
    1736 +                                       pvt->has_sms = 0; 
     2024+                                       pvt->sco_listener_thread = AST_PTHREADT_NULL; 
     2025+                                       if (!ast_strlen_zero(nocallsetup)) { 
     2026+                                               if ((*nocallsetup == 'y') || (*nocallsetup == 'Y')) { 
     2027+                                                       pvt->no_callsetup = 1; 
     2028+                                                       ast_log(LOG_DEBUG, "Setting nocallsetup mode for device %s.\n", pvt->id); 
     2029+                                               } 
     2030+                                       } 
    17372031+                                       pvt->dsp = ast_dsp_new(); 
    17382032+                                       if (skip) { 
     
    17412035+                                       } else 
    17422036+                                               pvt->dtmf_skip = 200; 
    1743 +                                       pvt->skip_frames = 0; 
    17442037+                                       ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DTMF_DETECT); 
    17452038+                                       ast_dsp_digitmode(pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); 
    1746 +                                       AST_LIST_INSERT_HEAD(&devices, pvt, entry); 
     2039+                                       pvt->adapter = adapter; 
     2040+                                       AST_RWLIST_WRLOCK(&devices); 
     2041+                                       AST_RWLIST_INSERT_HEAD(&devices, pvt, entry); 
     2042+                                       AST_RWLIST_UNLOCK(&devices); 
    17472043+                               } 
    17482044+                       } else { 
    1749 +                               ast_log(LOG_ERROR, "Device %s has no address/port configured. It wont be enabled.\n", cat); 
     2045+                               ast_log(LOG_ERROR, "Device %s has no address/port/adapter configured. It won't be enabled.\n", cat); 
    17502046+                       } 
    17512047+               } 
     
    17592055+} 
    17602056+ 
    1761 +static int reload_module(void) 
    1762 +{ 
    1763 + 
    1764 +       return 0; 
    1765 + 
    1766 +} 
    1767 + 
    17682057+static int unload_module(void) 
    17692058+{ 
    17702059+ 
    17712060+       struct mbl_pvt *pvt; 
     2061+       struct adapter_pvt *adapter; 
    17722062+ 
    17732063+       /* First, take us out of the channel loop */ 
     
    17792069+               pthread_join(discovery_thread, NULL); 
    17802070+       } 
    1781 +       /* Kill the sco listener thread */ 
    1782 +       if (sco_listener_thread != AST_PTHREADT_NULL) { 
    1783 +               pthread_cancel(sco_listener_thread); 
    1784 +               pthread_join(sco_listener_thread, NULL); 
    1785 +       } 
    1786 +       if ((close(sco_socket) == -1)) 
    1787 +               ast_log(LOG_ERROR, "Unable to close sco_socket %d.\n", errno); 
     2071+ 
     2072+       /* Destroy the device list */ 
     2073+       AST_RWLIST_WRLOCK(&devices); 
     2074+       while ((pvt = AST_RWLIST_REMOVE_HEAD(&devices, entry))) { 
     2075+               if (pvt->monitor_thread != AST_PTHREADT_NULL) { 
     2076+                       pthread_cancel(pvt->monitor_thread); 
     2077+                       pthread_join(pvt->monitor_thread, NULL); 
     2078+               } 
     2079+               if (pvt->sco_listener_thread != AST_PTHREADT_NULL) { 
     2080+                       pthread_cancel(pvt->sco_listener_thread); 
     2081+                       pthread_join(pvt->sco_listener_thread, NULL); 
     2082+               } 
     2083+               if (pvt->sco_socket > -1) { 
     2084+                       close(pvt->sco_socket); 
     2085+               } 
     2086+               if (pvt->adapter->sco_socket > -1) { 
     2087+                       close(pvt->adapter->sco_socket); 
     2088+               } 
     2089+               if (pvt->rfcomm_socket > -1) { 
     2090+                       close(pvt->rfcomm_socket); 
     2091+               } 
     2092+               ast_dsp_free(pvt->dsp); 
     2093+               ast_free(pvt); 
     2094+       } 
     2095+       AST_RWLIST_UNLOCK(&devices); 
     2096+ 
     2097+       /* Destroy the adapter list */ 
     2098+       AST_RWLIST_WRLOCK(&adapters); 
     2099+       while ((adapter = AST_RWLIST_REMOVE_HEAD(&adapters, entry))) { 
     2100+               hci_close_dev(adapter->hci_socket); 
     2101+               ast_free(adapter); 
     2102+       } 
     2103+       AST_RWLIST_UNLOCK(&adapters); 
     2104+ 
     2105+       if (sdp_session) 
     2106+               sdp_close(sdp_session); 
    17882107+ 
    17892108+       /* Unregister the CLI & APP */ 
     
    17922111+       ast_unregister_application(app_mblsendsms); 
    17932112+ 
    1794 +       /* Destroy the device list */ 
    1795 +       while ((pvt = AST_LIST_REMOVE_HEAD(&devices, entry))) { 
    1796 +               if (pvt->monitor_thread != AST_PTHREADT_NULL) { 
    1797 +                       pthread_cancel(pvt->monitor_thread); 
    1798 +                       pthread_join(pvt->monitor_thread, NULL); 
    1799 +               } 
    1800 +               if (pvt->sco_socket > -1) { 
    1801 +                       close(pvt->sco_socket); 
    1802 +               } 
    1803 +               if (pvt->rfcomm_socket > -1) { 
    1804 +                       close(pvt->rfcomm_socket); 
    1805 +               } 
    1806 +               ast_dsp_free(pvt->dsp); 
    1807 +               free(pvt); 
    1808 +       } 
    1809 + 
    1810 +       if (sdp_session) 
    1811 +               sdp_close(sdp_session); 
    1812 + 
    18132113+       return 0; 
    18142114+ 
     
    18192119+ 
    18202120+       int dev_id, s; 
    1821 +       uint16_t vs; 
    18222121+ 
    18232122+       /* Check if we have Bluetooth, no point loading otherwise... */ 
     
    18292128+       } 
    18302129+ 
    1831 +       hci_read_voice_setting(s, &vs, 1000); 
    1832 +       vs = htobs(vs); 
    1833 +       if (vs != 0x0060) { 
    1834 +               ast_log(LOG_ERROR, "Bluetooth voice setting must be 0x0060 - see hciconfig hci0 voice.\n"); 
    1835 +               hci_close_dev(s); 
    1836 +               return AST_MODULE_LOAD_DECLINE; 
    1837 +       } 
    1838 + 
    18392130+       hci_close_dev(s); 
    18402131+ 
     
    18512142+               return AST_MODULE_LOAD_DECLINE; 
    18522143+       } 
    1853 +       /* Spin the sco listener thread */ 
    1854 +       if (ast_pthread_create_background(&sco_listener_thread, NULL, do_sco_listen, NULL) < 0) { 
    1855 +               ast_log(LOG_ERROR, "Unable to create sco listener thread.\n"); 
    1856 +               pthread_cancel(discovery_thread); 
    1857 +               pthread_join(discovery_thread, NULL); 
    1858 +               return AST_MODULE_LOAD_DECLINE; 
    1859 +       } 
    18602144+ 
    18612145+       ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0])); 
     
    18752159+               .load = load_module, 
    18762160+               .unload = unload_module, 
    1877 +               .reload = reload_module, 
    18782161+); 
    1879 diff -Nru asterisk-addons-1.4.6.org/configs/mobile.conf.sample asterisk-addons-1.4.6/configs/mobile.conf.sample 
    1880 --- asterisk-addons-1.4.6.org/configs/mobile.conf.sample        1970-01-01 01:00:00.000000000 +0100 
    1881 +++ asterisk-addons-1.4.6/configs/mobile.conf.sample    2008-03-06 08:38:14.000000000 +0100 
    1882 @@ -0,0 +1,30 @@ 
     2162diff -Nru asterisk-addons-1.4.7.org/configs/mobile.conf.sample asterisk-addons-1.4.7/configs/mobile.conf.sample 
     2163--- asterisk-addons-1.4.7.org/configs/mobile.conf.sample        1970-01-01 01:00:00.000000000 +0100 
     2164+++ asterisk-addons-1.4.7/configs/mobile.conf.sample    2009-02-01 08:46:24.000000000 +0100 
     2165@@ -0,0 +1,68 @@ 
    18832166+; 
    18842167+; mobile.conf 
     2168+; configuration file for chan_mobile 
    18852169+; 
    18862170+ 
    18872171+[general] 
    1888 +interval=60            ; Number of seconds between trying to connect to devices.  
     2172+interval=30            ; Number of seconds between trying to connect to devices.  
     2173+ 
     2174+; The following is a list of adapters we use. 
     2175+; id must be unique and address is the bdaddr of the adapter from hciconfig. 
     2176+; Each adapter may only have one device (headset or phone) connected at a time. 
     2177+; Add an [adapter] entry for each adapter you have. 
     2178+ 
     2179+[adapter] 
     2180+id=blue 
     2181+address=00:09:DD:60:01:A3 
     2182+;forcemaster=yes       ; attempt to force adapter into master mode. default is no. 
     2183+;alignmentdetection=yes ; enable this if you sometimes get 'white noise' on asterisk side of the call 
     2184+                       ; its a bug in the bluetooth adapter firmware, enabling this will compensate for it. 
     2185+                       ; default is no. 
     2186+ 
     2187+[adapter] 
     2188+id=dlink 
     2189+address=00:80:C8:35:52:78 
    18892190+ 
    18902191+; The following is a list of the devices we deal with. 
    18912192+; Every device listed below will be available for calls in and out of Asterisk.  
    1892 +; Discovered devices not in this list are not available. 
     2193+; Each device needs an adapter=xxxx entry which determines which bluetooth adapter is used. 
    18932194+; Use the CLI command 'mobile search' to discover devices. 
    18942195+; Use the CLI command 'mobile show devices' to see device status. 
    18952196+; 
    1896 +; To place out through a cell phone use Dial(Mobile/[device]/NNN.....) in your dialplan. 
     2197+; To place a call out through a mobile phone use Dial(Mobile/[device]/NNN.....) or Dial(Mobile/gn/NNN......) in your dialplan. 
    18972198+; To call a headset use Dial(Mobile/[device]). 
    18982199+ 
    1899 +;[dave] 
    1900 +;address=00:12:56:90:6E:00 
    1901 +;port=4 
    1902 +;context=incoming-mobile 
    1903 + 
    1904 +;[blackberry] 
    1905 +;address=00:0F:86:0E:AE:42 
    1906 +;port=2 
    1907 +;context=incoming-mobile 
    1908 + 
    1909 +;[headset] 
    1910 +;address=00:0B:9E:11:74:A5 
    1911 +;port=1 
    1912 +;type=headset 
    1913 diff -Nru asterisk-addons-1.4.6.org/configure.ac asterisk-addons-1.4.6/configure.ac 
    1914 --- asterisk-addons-1.4.6.org/configure.ac      2008-02-13 23:58:11.000000000 +0100 
    1915 +++ asterisk-addons-1.4.6/configure.ac  2008-03-06 08:38:14.000000000 +0100 
    1916 @@ -161,13 +161,14 @@ 
     2200+[LGTU550] 
     2201+address=00:E0:91:7F:46:44      ; the address of the phone 
     2202+port=4                         ; the rfcomm port number (from mobile search) 
     2203+context=incoming-mobile                ; dialplan context for incoming calls 
     2204+adapter=dlink                  ; adapter to use 
     2205+group=1                                ; this phone is in channel group 1 
     2206+;nocallsetup=yes               ; set this only if your phone reports that it supports call progress notification, but does not do it. Motorola L6 for example. 
     2207+ 
     2208+[blackberry] 
     2209+address=00:60:57:32:7E:B2 
     2210+port=2 
     2211+context=incoming-mobile 
     2212+adapter=dlink 
     2213+group=1 
     2214+;blackberry=yes                        ; set this if you are using a blackberry device 
     2215+ 
     2216+[6310i] 
     2217+address=00:60:57:32:7E:B1 
     2218+port=13 
     2219+context=incoming-mobile 
     2220+adapter=dlink 
     2221+group=1                                ; this phone is in channel group 1 also. 
     2222+ 
     2223+[headset] 
     2224+address=00:0B:9E:11:AE:C6 
     2225+port=1 
     2226+type=headset                   ; This is a headset, not a Phone ! 
     2227+adapter=blue 
     2228+ 
     2229+[headset1] 
     2230+address=00:0B:9E:11:74:A5 
     2231+port=1 
     2232+type=headset 
     2233+adapter=dlink 
     2234diff -Nru asterisk-addons-1.4.7.org/configure.ac asterisk-addons-1.4.7/configure.ac 
     2235--- asterisk-addons-1.4.7.org/configure.ac      2008-02-13 23:58:11.000000000 +0100 
     2236+++ asterisk-addons-1.4.7/configure.ac  2009-02-01 08:48:08.000000000 +0100 
     2237@@ -161,11 +161,13 @@ 
    19172238 # from here on down, library checking should be done in alphabetical order 
    19182239 # by the --with option name, to make things easier for the users :-) 
     
    19262247+AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [ba2str], [bluetooth/bluetooth.h]) 
    19272248 AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h]) 
    1928 - 
     2249  
    19292250 AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h]) 
    1930   
    1931  MYSQL_CONFIG=No 
    1932 diff -Nru asterisk-addons-1.4.6.org/doc/chan_mobile.txt asterisk-addons-1.4.6/doc/chan_mobile.txt 
    1933 --- asterisk-addons-1.4.6.org/doc/chan_mobile.txt       1970-01-01 01:00:00.000000000 +0100 
    1934 +++ asterisk-addons-1.4.6/doc/chan_mobile.txt   2008-03-06 08:38:14.000000000 +0100 
    1935 @@ -0,0 +1,262 @@ 
    1936 +chan_mobile 
    1937 + 
    1938 +Asterisk Channel Driver to allow Bluetooth Cell/Mobile Phones to be used as FXO devices, and Headsets as FXS devices. 
    1939 + 
    1940 +Features :- 
    1941 + 
    1942 +Multiple cell phones can be connected. 
    1943 +Multiple headsets can be connected. 
    1944 +Asterisk automatically connects to each configured cell phone / headset when it comes in range. 
    1945 +CLI command to discover bluetooth devices. 
    1946 +Inbound calls on the cell network to the cell phones are handled by Asterisk, just like inbound calls on a Zap channel. 
    1947 +CLI passed through on inbound calls. 
    1948 +Dial outbound on a cell phone using Dial(Mobile/device/nnnnnnn) in the dialplan. 
    1949 +Dial a headset using Dial(Mobile/device) in the dialplan. 
    1950 +Application MobileStatus can be used in the dialplan to see if a cell phone / headset is connected. 
    1951 +Supports devicestate for dialplan hinting. 
    1952 +Supports Inbound and Outbound SMS. 
    1953 + 
    1954 +Using chan_mobile :- 
    1955 + 
    1956 +In order to use chan_mobile, you must have a working bluetooth subsystem on your Asterisk box. 
    1957 +This means a working bluetooth adapter, and the BlueZ packages. 
    1958 + 
    1959 +Any bluetooth adapter supported by the Linux kernel will do, including usb bluetooth dongles. 
    1960 + 
    1961 +The BlueZ package you need is bluez-utils. If you are using a GUI then you might want to install bluez-pin also. 
    1962 +You also need libbluetooth, and libbluetooth-dev if you are compiling Asterisk from source. 
    1963 + 
    1964 +You need to get bluetooth working with your phone before attempting to use chan_mobile. 
    1965 +This means 'pairing' your phone with your Asterisk box. I dont describe how to do this here as the process 
    1966 +differs from distro to distro. You only need to pair once. 
    1967 + 
    1968 +However, the easist way to pair, is to use you cell phone to search for bluetooth devices, select your Asterisk box 
    1969 +and enter the requested PIN. 
    1970 + 
    1971 +See www.bluez.org for other details about setting up Bluetooth under Linux. 
    1972 + 
    1973 +Assuming you have bluetooth working ok:- 
    1974 + 
    1975 +Load chan_mobile.so 
    1976 + 
    1977 +Search for your bluetooth devices using the CLI command 'mobile search'. Be patient with this command as 
    1978 +it will take 8 - 10 seconds to do the discovery. 
    1979 + 
    1980 +Headsets will generally have to be put into 'pairing' mode before they will show up here. 
    1981 + 
    1982 +This will return something like the following :- 
    1983 + 
    1984 +*CLI> mobile search 
    1985 +Address           Name                           Usable Type    Port 
    1986 +00:12:56:90:6E:00 LG TU500                       Yes    Phone   4 
    1987 +00:80:C8:35:52:78 Toaster                        No     Headset 0 
    1988 +00:0B:9E:11:74:A5 Hello II Plus                  Yes    Headset 1 
    1989 +00:0F:86:0E:AE:42 Daves Blackberry               Yes    Phone   7 
    1990 + 
    1991 +This is a list of all bluetooth devices seen and whether or not they are usable with chan_cellphone. 
    1992 +The Address field contains the 'bd address' of the device. This is like an ethernet mac address. 
    1993 +The Name field is whatever is configured into the device as its name. 
    1994 +The Usable field tells you whether or not the device supports the Bluetooth Handsfree Profile or Headset profile. 
    1995 +The Type field tells you whether the device is usable as a Phone line (FXO) or a headset (FXS) 
    1996 +The Port field is the number to put in the configuration file. 
    1997 + 
    1998 +Choose which device(s) you want to use and edit /etc/asterisk/mobile.conf. There is a sample included 
    1999 +with the Asterisk source under configs/mobile.conf.sample. 
    2000 + 
    2001 +Assuming we want to use the devices above, mobile.conf needs to look like this :- 
    2002 + 
    2003 +=================================================================================== 
    2004 +; 
    2005 +; mobile.conf 
    2006 +; 
    2007 + 
    2008 +[general] 
    2009 +interval=60             ; Number of seconds between trying to connect to devices. 
    2010 + 
    2011 +; The following is a list of the devices we deal with. 
    2012 +; Every device listed below will be available for calls in and out of Asterisk. 
    2013 +; Discovered devices not in this list are not available. 
    2014 +; Use the CLI command 'mobile search' to discover devices. 
    2015 +; Use the CLI command 'mobile show devices' to see device status. 
    2016 +; 
    2017 +; To place a call use Dial(Mobile/[device]/NNN.....) in your dialplan. 
    2018 + 
    2019 +[dave] 
    2020 +address=00:12:56:90:6E:00 
    2021 +port=4 
    2022 +context=incoming-mobile 
    2023 + 
    2024 +[headset] 
    2025 +address=00:0B:9E:11:74:A5 
    2026 +port=1 
    2027 +type=headset 
    2028 +=================================================================================== 
    2029 + 
    2030 +Be sure to configure the right bd address and port number from the search. If you want inbound 
    2031 +calls on a device to go to a specific context, add a context= line, otherwise the default will 
    2032 +be used. The 'id' of the device [bitinbrackets] can be anything you like, just make the unique. 
    2033 + 
    2034 +If your are configuring a Headset be sure to include the type=headset line, if left out it defaults 
    2035 +to phone. 
    2036 + 
    2037 +Having done this, unload chan_mobile and load it again. 
    2038 + 
    2039 +The CLI command 'mobile show devices' can be used at any time to show the status of configured devices, 
    2040 +and whether or not the device is capable of sending / receiving SMS via bluetooth. 
    2041 + 
    2042 +*CLI> mobile show devices 
    2043 +ID              Address           Connected State SMS 
    2044 +blackberry      00:0F:86:0E:AE:42 Yes       Free  Yes 
    2045 +dave            00:12:56:90:6E:00 Yes       Free  No 
    2046 +headset         00:0B:9E:11:74:A5 Yes       Free  No 
    2047 +*CLI> 
    2048 + 
    2049 + 
    2050 +All being well Asterisk will now try and establish a connection to each configured device. If it cant 
    2051 +it will retry after 'interval' seconds, infinately. 
    2052 + 
    2053 +This means that as your cell phone comes into range and goes out of range, Asterisk will automatically 
    2054 +connect and disconnect from it. You dont need to worry about it. 
    2055 + 
    2056 +As each phone is connected you will see a message on the Asterisk console :- 
    2057 + 
    2058 + Loaded chan_mobile.so => (Bluetooth Mobile Device Channel Driver) 
    2059 +    -- Bluetooth Device blackberry has connected. 
    2060 +    -- Bluetooth Device dave has connected. 
    2061 + 
    2062 +If someone calls your cell phone now, Asterisk will handle the call and it will be sent into the 
    2063 +context you specified, or the default context. Mostly likely this means some SIP phone somewhere will 
    2064 +ring, pick it up and take the call. 
    2065 + 
    2066 +To make outbound calls, add something to you Dialplan like the following :- (modify to suit) 
    2067 + 
    2068 +; Calls via TU500 
    2069 +exten => _9X.,1,Dial(Mobile/dave/${EXTEN:1},45) 
    2070 +exten => _9X.,n,Hangup 
    2071 +; Calls via Blackberry 
    2072 +exten => _8X.,1,Dial(Mobile/blackberry/${EXTEN:1},45) 
    2073 +exten => _8X.,n,Hangup 
    2074 + 
    2075 +Pick up a SIP phone and dial 9<number of pizza shop> and the call vill go via the device 'dave' in 
    2076 +mobile.conf. 
    2077 + 
    2078 +To incoming calls to a headset do something like this :- 
    2079 + 
    2080 +[incoming-context] 
    2081 +exten => s,1,Dial(Mobile/headset,30) 
    2082 +exten => s,n,Hangup() 
    2083 + 
    2084 +To dial out on a headset, you need to use some other mechanism, because the headset is not likely 
    2085 +to have all the needed buttons on it. res_clioriginate is good for this :- 
    2086 + 
    2087 +*CLI> originate Mobile/headset extension NNNNN@context 
    2088 + 
    2089 +This will call your headset, once you answer Asterisk will call NNNNN at context context 
    2090 + 
    2091 +Dialplan hints :- 
    2092 + 
    2093 +chan_mobile supports 'device status' so you can do somthing like 
    2094 + 
    2095 +exten => 1234,hint,SIP/30&Mobile/dave&Mobile/blackberry 
    2096 + 
    2097 + 
    2098 +MobileStatus Application :- 
    2099 + 
    2100 +chan_mobile also registers an application named MobileStatus. You can use this in your Dialplan 
    2101 +to determine the 'state' of a device. 
    2102 + 
    2103 +For example, suppose you wanted to call dave's extension, but only if he was in the office. You could 
    2104 +test to see if his cell phone was attached to Asterisk, if it is dial his extension, otherwise dial his 
    2105 +cell phone. 
    2106 + 
    2107 +exten => 40,1,MobileStatus(dave,DAVECELL) 
    2108 +exten => 40,2,GotoIf($["${DAVECELL}" = "1"]?3:5) 
    2109 +exten => 40,3,Dial(ZAP/g1/0427466412,45,tT) 
    2110 +exten => 40,4,Hangup 
    2111 +exten => 40,5,Dial(SIP/40,45,tT) 
    2112 +exten => 40,6,Hangup 
    2113 + 
    2114 +MobileStatus sets the value of the given variable to :- 
    2115 + 
    2116 +1 = Disconnected. i.e. Device not in range of Asterisk, or turned off etc etc 
    2117 +2 = Connected and Not on a call. i.e. Free 
    2118 +3 = Connected and on a call. i.e. Busy 
    2119 + 
    2120 + 
    2121 +SMS Sending / Receiving 
    2122 + 
    2123 +If Asterisk has detected your cell phone is capable of SMS via bluetooth, you will be able to send and 
    2124 +receive SMS. 
    2125 + 
    2126 +Incoming SMS's cause Asterisk to create an inbound call to the context you defined in mobile.conf or the default 
    2127 +context if you did not define one. The call will start at extension 'sms'. Two channel variables will be available, 
    2128 +SMSSRC = the number of the originator of the SMS and SMSTXT which is the text of the SMS. 
    2129 +This is not a voice call, so grab the values of the variables and hang the call up. 
    2130 + 
    2131 +So, to handle incoming SMS's, do something like the following in your dialplan 
    2132 + 
    2133 +[incoming-mobile] 
    2134 +exten => sms,1,Verbose(Incoming SMS from ${SMSSRC} ${SMSTXT}) 
    2135 +exten => sms,n,Hangup() 
    2136 + 
    2137 +The above will just print the message on the console. 
    2138 + 
    2139 +If you use res_jabber, you could do something like this :- 
    2140 + 
    2141 +[incoming-mobile] 
    2142 +exten => sms,1,JabberSend(transport,user@jabber.somewhere.com,SMS from ${SMSRC} ${SMSTXT}) 
    2143 +exten => sms,2,Hangup() 
    2144 + 
    2145 +To send an SMS, use the application MobileSendSMS like the following :- 
    2146 + 
    2147 +exten => 99,1,MobileSendSMS(dave,0427123456,Hello World) 
    2148 + 
    2149 +This will send 'Hello World' via device 'dave' to '0427123456' 
    2150 + 
    2151 + 
    2152 +DTMF Debouncing :- 
    2153 + 
    2154 +DTMF detection varies from phone to phone. There is a configuration variable that allows you to tune 
    2155 +this to your needs. e.g. in mobile.conf 
    2156 + 
    2157 +[dave] 
    2158 +address=00:12:56:90:6E:00 
    2159 +port=4 
    2160 +context=incoming-mobile 
    2161 +dtmfskip=50 
    2162 + 
    2163 +change dtmfskip to suit your phone. The default is 200. The larger the number, the more chance of missed DTMF. 
    2164 +The smaller the number the more chance of multiple digits being detected. 
    2165 + 
    2166 + 
    2167 +Debugging :- 
    2168 + 
    2169 +Different phone manufacturers have different interpretations of the Bluetooth Handsfree Profile Spec. 
    2170 +This means that not all phones work the same way, particularly in the connection setup / initialisation 
    2171 +sequence. I've tried to make chan_cellphone as general as possible, but it may need modification to 
    2172 +support some phone i've never tested. 
    2173 + 
    2174 +The RIM Blackberry 7250 works extremely well. So does the LG TU500. 
    2175 + 
    2176 +Some phones, most notably Sony Ericsson 'T' series, dont quite conform to the Bluetooth HFP spec. 
    2177 +chan_mobile will detect these and adapt accordingly. The T-610 and T-630 have been tested and 
    2178 +work fine. 
    2179 + 
    2180 +If your phone doesnt behave has expected, turn on Asterisk debugging with 'core set debug 1'. 
    2181 + 
    2182 +This will log a bunch of debug messages indicating what the phone is doing, importantly the rfcomm 
    2183 +conversation between Asterisk and the phone. This can be used to sort out what your phone is doing 
    2184 +and make chan_mobile support it. 
    2185 + 
    2186 +Be aware also, that just about all cell phones behave differently. For example my LG TU500 wont dial unless 
    2187 +the phone is a the 'idle' screen. i.e. if the phone is showing a 'menu' on the display, when you dial via 
    2188 +Asterisk, the call will not work. chan_mobile handles this, but there may be other phones that do 
    2189 +other things too... 
    2190 + 
    2191 +Important: Watch what your cell phone is doing the first few times. Asterisk wont make random calls but 
    2192 +if chan_mobile fails to hangup for some reason and you get a huge bill from your telco, dont blame me. 
    2193 + 
    2194 + 
    2195 +Feedback, Support, Please can you make Cell Phone X work... etc :- 
    2196 + 
    2197 +email me at   david.bowerman at gmail.com   or dseeb_ on #asterisk & #asterisk-dev irc. 
    2198 diff -Nru asterisk-addons-1.4.6.org/Makefile asterisk-addons-1.4.6/Makefile 
    2199 --- asterisk-addons-1.4.6.org/Makefile  2008-02-13 23:58:11.000000000 +0100 
    2200 +++ asterisk-addons-1.4.6/Makefile      2008-03-06 08:38:14.000000000 +0100 
    2201 @@ -215,6 +215,8 @@ 
    2202   
    2203  gmenuconfig: gmenuselect 
    2204   
    2205 +menuconfig: menuselect 
    2206 + 
    2207  menuselect: menuselect/menuselect menuselect-tree 
    2208         -@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!" 
    2209   
    2210 diff -Nru asterisk-addons-1.4.6.org/makeopts.in asterisk-addons-1.4.6/makeopts.in 
    2211 --- asterisk-addons-1.4.6.org/makeopts.in       2008-02-13 23:58:11.000000000 +0100 
    2212 +++ asterisk-addons-1.4.6/makeopts.in   2008-03-06 08:38:14.000000000 +0100 
     2251diff -Nru asterisk-addons-1.4.7.org/makeopts.in asterisk-addons-1.4.7/makeopts.in 
     2252--- asterisk-addons-1.4.7.org/makeopts.in       2008-02-13 23:58:11.000000000 +0100 
     2253+++ asterisk-addons-1.4.7/makeopts.in   2009-02-01 08:49:46.000000000 +0100 
    22132254@@ -34,6 +34,9 @@ 
    22142255 sharedstatedir = @sharedstatedir@ 
Note: See TracChangeset for help on using the changeset viewer.