[package] xorg-kdrive: fix linker errors.
[packages.git] / net / asterisk-addons-1.4.x / patches / 011-chan_mobile.patch
1 diff -Nru asterisk-addons-1.4.8.org/build_tools/menuselect-deps.in asterisk-addons-1.4.8/build_tools/menuselect-deps.in
2 --- asterisk-addons-1.4.8.org/build_tools/menuselect-deps.in    2007-05-14 18:22:44.000000000 +0200
3 +++ asterisk-addons-1.4.8/build_tools/menuselect-deps.in        2009-06-04 22:20:03.000000000 +0200
4 @@ -1,2 +1,3 @@
5 +BLUETOOTH=@PBX_BLUETOOTH@
6  MYSQLCLIENT=@PBX_MYSQLCLIENT@
7  ASTERISK=@PBX_ASTERISK@
8 diff -Nru asterisk-addons-1.4.8.org/channels/chan_mobile.c asterisk-addons-1.4.8/channels/chan_mobile.c
9 --- asterisk-addons-1.4.8.org/channels/chan_mobile.c    1970-01-01 01:00:00.000000000 +0100
10 +++ asterisk-addons-1.4.8/channels/chan_mobile.c        2009-06-04 22:20:03.000000000 +0200
11 @@ -0,0 +1,2150 @@
12 +/*
13 + * Asterisk -- An open source telephony toolkit.
14 + *
15 + * Copyright (C) 1999 - 2006, Digium, Inc.
16 + *
17 + * Mark Spencer <markster@digium.com>
18 + *
19 + * See http://www.asterisk.org for more information about
20 + * the Asterisk project. Please do not directly contact
21 + * any of the maintainers of this project for assistance;
22 + * the project provides a web site, mailing lists and IRC
23 + * channels for your use.
24 + *
25 + * This program is free software, distributed under the terms of
26 + * the GNU General Public License Version 2. See the LICENSE file
27 + * at the top of the source tree.
28 + */
29 +
30 +/*! \file
31 + *
32 + * \brief Bluetooth Mobile Device channel driver
33 + *
34 + * \author Dave Bowerman <david.bowerman@gmail.com>
35 + *
36 + * \ingroup channel_drivers
37 + */
38 +
39 +/*** MODULEINFO
40 +       <depend>bluetooth</depend>
41 + ***/
42 +
43 +#include <asterisk.h>
44 +
45 +ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
46 +
47 +#include <stdio.h>
48 +#include <string.h>
49 +#include <sys/socket.h>
50 +#include <sys/time.h>
51 +#include <errno.h>
52 +#include <unistd.h>
53 +#include <stdlib.h>
54 +#include <arpa/inet.h>
55 +#include <fcntl.h>
56 +#include <sys/ioctl.h>
57 +#include <signal.h>
58 +
59 +#include <bluetooth/bluetooth.h>
60 +#include <bluetooth/hci.h>
61 +#include <bluetooth/hci_lib.h>
62 +#include <bluetooth/sdp.h>
63 +#include <bluetooth/sdp_lib.h>
64 +#include <bluetooth/rfcomm.h>
65 +#include <bluetooth/sco.h>
66 +#include <bluetooth/l2cap.h>
67 +
68 +#include <asterisk/lock.h>
69 +#include <asterisk/channel.h>
70 +#include <asterisk/config.h>
71 +#include <asterisk/logger.h>
72 +#include <asterisk/module.h>
73 +#include <asterisk/pbx.h>
74 +#include <asterisk/options.h>
75 +#include <asterisk/utils.h>
76 +#include <asterisk/linkedlists.h>
77 +#include <asterisk/cli.h>
78 +#include <asterisk/devicestate.h>
79 +#include <asterisk/causes.h>
80 +#include <asterisk/dsp.h>
81 +#include <asterisk/app.h>
82 +#include <asterisk/manager.h>
83 +
84 +#define MBL_CONFIG "mobile.conf"
85 +
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 */
94 +static sdp_session_t *sdp_session;
95 +
96 +enum mbl_type {
97 +       MBL_TYPE_PHONE,
98 +       MBL_TYPE_HEADSET
99 +};
100 +
101 +enum mbl_state {
102 +       MBL_STATE_INIT = 0,
103 +       MBL_STATE_INIT1,
104 +       MBL_STATE_INIT2,
105 +       MBL_STATE_INIT3,
106 +       MBL_STATE_INIT4,
107 +       MBL_STATE_INIT5,
108 +       MBL_STATE_INIT6,
109 +       MBL_STATE_INIT7,
110 +       MBL_STATE_PREIDLE,
111 +       MBL_STATE_IDLE,
112 +       MBL_STATE_DIAL,
113 +       MBL_STATE_DIAL1,
114 +       MBL_STATE_OUTGOING,
115 +       MBL_STATE_RING,
116 +       MBL_STATE_RING2,
117 +       MBL_STATE_RING3,
118 +       MBL_STATE_INCOMING,
119 +       MBL_STATE_HANGUP,
120 +       MBL_STATE_INSMS,
121 +       MBL_STATE_OUTSMS,
122 +       MBL_STATE_OUTSMS1,
123 +       MBL_STATE_OUTSMS2
124 +};
125 +
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 +
139 +struct mbl_pvt {
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 */
151 +       char rfcomm_buf[256];
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 */
161 +       int dial_timeout;
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];
178 +       struct ast_dsp *dsp;
179 +       struct ast_frame *dsp_fr;
180 +       int dtmf_skip;
181 +       int skip_frames;
182 +       char hangup_count;
183 +       AST_LIST_ENTRY(mbl_pvt) entry;
184 +};
185 +
186 +static AST_RWLIST_HEAD_STATIC(devices, mbl_pvt);
187 +
188 +/* CLI stuff */
189 +static const char show_usage[] =
190 +"Usage: mobile show devices\n" 
191 +"       Shows the state of Bluetooth Cell / Mobile devices.\n";
192 +
193 +static const char search_usage[] =
194 +"Usage: mobile search\n" 
195 +"       Searches for Bluetooth Cell / Mobile devices in range.\n";
196 +
197 +static const char rfcomm_usage[] =
198 +"Usage: mobile rfcomm command\n" 
199 +"       Send command to the rfcomm port.\n";
200 +
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);
204 +
205 +static struct ast_cli_entry mbl_cli[] = {
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},
209 +};
210 +
211 +/* App stuff */
212 +static char *app_mblstatus = "MobileStatus";
213 +static char *mblstatus_synopsis = "MobileStatus(Device,Variable)";
214 +static char *mblstatus_desc =
215 +"MobileStatus(Device,Variable)\n"
216 +"  Device - Id of mobile device from mobile.conf\n"
217 +"  Variable - Variable to store status in will be 1-3.\n" 
218 +"             In order, Disconnected, Connected & Free, Connected & Busy.\n";
219 +
220 +static char *app_mblsendsms = "MobileSendSMS";
221 +static char *mblsendsms_synopsis = "MobileSendSMS(Device,Dest,Message)";
222 +static char *mblsendsms_desc =
223 +"MobileSendSms(Device,Dest,Message)\n"
224 +"  Device - Id of device from mobile.conf\n"
225 +"  Dest - destination\n"
226 +"  Message - text of the message\n";
227 +
228 +static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num);
229 +static struct ast_channel *mbl_request(const char *type, int format, void *data, int *cause);
230 +static int mbl_call(struct ast_channel *ast, char *dest, int timeout);
231 +static int mbl_hangup(struct ast_channel *ast);
232 +static int mbl_answer(struct ast_channel *ast);
233 +static int mbl_digit_begin(struct ast_channel *ast, char digit);
234 +static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
235 +static struct ast_frame *mbl_read(struct ast_channel *ast);
236 +static int mbl_write(struct ast_channel *ast, struct ast_frame *frame);
237 +static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
238 +static int mbl_devicestate(void *data);
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);
243 +static int rfcomm_write(struct mbl_pvt *pvt, char *buf);
244 +static int rfcomm_read(struct mbl_pvt *pvt, char *buf, char flush, int timeout);
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);
251 +static int sdp_search(char *addr, int profile);
252 +
253 +static const struct ast_channel_tech mbl_tech = {
254 +       .type = "Mobile",
255 +       .description = "Bluetooth Mobile Device Channel Driver",
256 +       .capabilities = AST_FORMAT_SLINEAR,
257 +       .requester = mbl_request,
258 +       .call = mbl_call,
259 +       .hangup = mbl_hangup,
260 +       .answer = mbl_answer,
261 +       .send_digit_begin = mbl_digit_begin,
262 +       .send_digit_end = mbl_digit_end,
263 +       .read = mbl_read,
264 +       .write = mbl_write,
265 +       .fixup = mbl_fixup,
266 +       .devicestate = mbl_devicestate
267 +};
268 +
269 +/* CLI Commands implementation */
270 +
271 +static int handle_cli_mobile_show_devices(int fd, int argc, char **argv)
272 +{
273 +       struct mbl_pvt *pvt;
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
294 +
295 +       return RESULT_SUCCESS;
296 +}
297 +
298 +static int handle_cli_mobile_search(int fd, int argc, char **argv)
299 +{
300 +       struct adapter_pvt *adapter;
301 +       inquiry_info *ii = NULL;
302 +       int max_rsp, num_rsp;
303 +       int len, flags;
304 +       int i, phport, hsport;
305 +       char addr[19] = {0};
306 +       char name[31] = {0};
307 +
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 +
327 +       len  = 8;
328 +       max_rsp = 255;
329 +       flags = IREQ_CACHE_FLUSH;
330 +
331 +       ii = alloca(max_rsp * sizeof(inquiry_info));
332 +       num_rsp = hci_inquiry(adapter->dev_id, len, max_rsp, NULL, &ii, flags);
333 +       if (num_rsp > 0) {
334 +               ast_cli(fd, FORMAT1, "Address", "Name", "Usable", "Type", "Port");
335 +               for (i = 0; i < num_rsp; i++) {
336 +                       ba2str(&(ii + i)->bdaddr, addr);
337 +                       name[0] = 0x00;
338 +                       if (hci_read_remote_name(adapter->hci_socket, &(ii + i)->bdaddr, sizeof(name) - 1, name, 0) < 0)
339 +                               strcpy(name, "[unknown]");
340 +                       phport = sdp_search(addr, HANDSFREE_AGW_PROFILE_ID);
341 +                       if (!phport)
342 +                               hsport = sdp_search(addr, HEADSET_PROFILE_ID);
343 +                       else
344 +                               hsport = 0;
345 +                       ast_cli(fd, FORMAT2, addr, name, (phport > 0 || hsport > 0) ? "Yes" : "No",
346 +                               (phport > 0) ? "Phone" : "Headset", (phport > 0) ? phport : hsport);
347 +               }
348 +       } else
349 +               ast_cli(fd, "No Bluetooth Cell / Mobile devices found.\n");
350 +
351 +#undef FORMAT1
352 +#undef FORMAT2
353 +
354 +       return RESULT_SUCCESS;
355 +}
356 +
357 +static int handle_cli_mobile_rfcomm(int fd, int argc, char **argv)
358 +{
359 +       char buf[128];
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) {
367 +               if (!strcmp(pvt->id, argv[2]))
368 +                       break;
369 +       }
370 +       AST_RWLIST_UNLOCK(&devices);
371 +
372 +       if (!pvt || !pvt->connected) {
373 +               ast_cli(fd, "Device %s not found.\n", argv[2]);
374 +               return RESULT_SUCCESS;
375 +       }
376 +
377 +       snprintf(buf, sizeof(buf), "%s\r", argv[3]);
378 +       rfcomm_write(pvt, buf);
379 +
380 +       return RESULT_SUCCESS;
381 +}
382 +
383 +/*
384 +
385 +       Dialplan applications implementation
386 +
387 +*/
388 +
389 +static int mbl_status_exec(struct ast_channel *ast, void *data)
390 +{
391 +
392 +       struct mbl_pvt *pvt;
393 +       char *parse;
394 +       int stat;
395 +       char status[2];
396 +
397 +       AST_DECLARE_APP_ARGS(args,
398 +               AST_APP_ARG(device);
399 +               AST_APP_ARG(variable);
400 +       );
401 +
402 +       if (ast_strlen_zero(data))
403 +               return -1;
404 +
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))
410 +               return -1;
411 +
412 +       stat = 1;
413 +
414 +       AST_RWLIST_RDLOCK(&devices);
415 +       AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
416 +               if (!strcmp(pvt->id, args.device))
417 +                       break;
418 +       }
419 +       AST_RWLIST_UNLOCK(&devices);
420 +
421 +       if (pvt) {
422 +               if (pvt->connected)
423 +                       stat = 2;
424 +               if (pvt->owner)
425 +                       stat = 3;
426 +       }
427 +
428 +       snprintf(status, sizeof(status), "%d", stat);
429 +       pbx_builtin_setvar_helper(ast, args.variable, status);
430 +
431 +       return 0;
432 +
433 +}
434 +
435 +static int mbl_sendsms_exec(struct ast_channel *ast, void *data)
436 +{
437 +
438 +       struct mbl_pvt *pvt;
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))
448 +               return -1;
449 +
450 +       parse = ast_strdupa(data);
451 +
452 +       AST_STANDARD_APP_ARGS(args, parse);
453 +
454 +       if (ast_strlen_zero(args.device)) {
455 +               ast_log(LOG_ERROR,"NULL device for message -- SMS will not be sent.\n");
456 +               return -1;
457 +       }
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))
472 +                       break;
473 +       }
474 +       AST_RWLIST_UNLOCK(&devices);
475 +
476 +       if (!pvt) {
477 +               ast_log(LOG_ERROR,"Bluetooth device %s wasn't found in the list -- SMS will not be sent.\n", args.device);
478 +               return -1;
479 +       }
480 +
481 +       if (!pvt->connected) {
482 +               ast_log(LOG_ERROR,"Bluetooth device %s wasn't connected -- SMS will not be sent.\n", args.device);
483 +               return -1;
484 +       }
485 +
486 +       if (!pvt->has_sms) {
487 +               ast_log(LOG_ERROR,"Bluetooth device %s doesn't handle SMS -- SMS will not be sent.\n", args.device);
488 +               return -1;
489 +       }
490 +
491 +       if (pvt->state != MBL_STATE_IDLE) {
492 +               ast_log(LOG_ERROR,"Bluetooth device %s isn't IDLE -- SMS will not be sent.\n", args.device);
493 +               return -1;
494 +       }
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));
498 +       pvt->state = MBL_STATE_OUTSMS;
499 +
500 +       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;
551 +
552 +}
553 +
554 +static struct ast_channel *mbl_request(const char *type, int format, void *data, int *cause)
555 +{
556 +
557 +       struct ast_channel *chn = NULL;
558 +       struct mbl_pvt *pvt;
559 +       char *dest_dev = NULL;
560 +       char *dest_num = NULL;
561 +       int oldformat, group = -1;
562 +
563 +       if (!data) {
564 +               ast_log(LOG_WARNING, "Channel requested with no data\n");
565 +               *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
566 +               return NULL;
567 +       }
568 +
569 +       oldformat = format;
570 +       format &= (AST_FORMAT_SLINEAR);
571 +       if (!format) {
572 +               ast_log(LOG_WARNING, "Asked to get a channel of unsupported format '%d'\n", oldformat);
573 +               *cause = AST_CAUSE_FACILITY_NOT_IMPLEMENTED;
574 +               return NULL;
575 +       }
576 +
577 +       dest_dev = ast_strdupa((char *)data);
578 +
579 +       dest_num = strchr(dest_dev, '/');
580 +       if (dest_num)
581 +               *dest_num++ = 0x00;
582 +
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) {
591 +                       break;
592 +               } else if (!strcmp(pvt->id, dest_dev)) {
593 +                       break;
594 +               }
595 +       }
596 +       AST_RWLIST_UNLOCK(&devices);
597 +       if (!pvt || !pvt->connected || pvt->owner) {
598 +               ast_log(LOG_WARNING, "Request to call on device %s which is not connected / already in use.\n", dest_dev);
599 +               *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
600 +               return NULL;
601 +       }
602 +
603 +       if ((pvt->type == MBL_TYPE_PHONE) && !dest_num) {
604 +               ast_log(LOG_WARNING, "Can't determine destination number.\n");
605 +               *cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
606 +               return NULL;
607 +       }
608 +
609 +       chn = mbl_new(AST_STATE_DOWN, pvt, NULL);
610 +       if (!chn) {
611 +               ast_log(LOG_WARNING, "Unable to allocate channel structure.\n");
612 +               *cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
613 +               return NULL;
614 +       }
615 +
616 +       return chn;
617 +
618 +}
619 +
620 +static int mbl_call(struct ast_channel *ast, char *dest, int timeout)
621 +{
622 +
623 +       struct mbl_pvt *pvt;
624 +       char *dest_dev = NULL;
625 +       char *dest_num = NULL;
626 +
627 +       dest_dev = ast_strdupa((char *)dest);
628 +
629 +       pvt = ast->tech_pvt;
630 +
631 +       if (pvt->type == MBL_TYPE_PHONE) {
632 +               dest_num = strchr(dest_dev, '/');
633 +               if (!dest_num) {
634 +                       ast_log(LOG_WARNING, "Cant determine destination number.\n");
635 +                       return -1;
636 +               }
637 +               *dest_num++ = 0x00;
638 +       }
639 +
640 +       if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
641 +               ast_log(LOG_WARNING, "mbl_call called on %s, neither down nor reserved\n", ast->name);
642 +               return -1;
643 +       }
644 +
645 +       ast_log(LOG_DEBUG, "Calling %s on %s\n", dest, ast->name);
646 +
647 +       if (pvt->type == MBL_TYPE_PHONE) {
648 +               ast_copy_string(pvt->dial_number, dest_num, sizeof(pvt->dial_number));
649 +               pvt->state = MBL_STATE_DIAL;
650 +               pvt->dial_timeout = (timeout == 0) ? 30 : timeout;
651 +       } else {
652 +               pvt->state = MBL_STATE_RING;
653 +       }
654 +
655 +       return 0;
656 +
657 +}
658 +
659 +static int mbl_hangup(struct ast_channel *ast)
660 +{
661 +
662 +       struct mbl_pvt *pvt;
663 +
664 +       if (!ast->tech_pvt) {
665 +               ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
666 +               return 0;
667 +       }
668 +       pvt = ast->tech_pvt;
669 +
670 +       ast_log(LOG_DEBUG, "Hanging up device %s.\n", pvt->id);
671 +
672 +       ast->fds[0] = -1;
673 +       
674 +       close(pvt->io_pipe[0]);
675 +       close(pvt->io_pipe[1]);
676 +
677 +       if (pvt->type == MBL_TYPE_HEADSET && pvt->sco_socket != -1) {
678 +               close(pvt->sco_socket);
679 +               pvt->sco_socket = -1;
680 +       }
681 +
682 +       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) {
683 +               if (pvt->do_hangup) {
684 +                       rfcomm_write(pvt, "AT+CHUP\r");
685 +               }
686 +               pvt->state = MBL_STATE_HANGUP;
687 +               pvt->hangup_count = 0;
688 +       } else
689 +               pvt->state = MBL_STATE_IDLE;
690 +
691 +       pvt->owner = NULL;
692 +       ast->tech_pvt = NULL;
693 +       ast_setstate(ast, AST_STATE_DOWN);
694 +
695 +       return 0;
696 +
697 +}
698 +
699 +static int mbl_answer(struct ast_channel *ast)
700 +{
701 +
702 +       struct mbl_pvt *pvt;
703 +
704 +       pvt = ast->tech_pvt;
705 +
706 +       rfcomm_write(pvt, "ATA\r");
707 +
708 +       ast_setstate(ast, AST_STATE_UP);
709 +
710 +       pvt->sent_answer = 1;
711 +
712 +       return 0;
713 +
714 +}
715 +
716 +static int mbl_digit_begin(struct ast_channel *chan, char digit)
717 +{
718 +
719 +       return 0;
720 +
721 +}
722 +
723 +static int mbl_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
724 +{
725 +
726 +       struct mbl_pvt *pvt;
727 +       char buf[11];
728 +
729 +       pvt = ast->tech_pvt;
730 +
731 +       if (pvt->type == MBL_TYPE_HEADSET)
732 +               return 0;
733 +
734 +       ast_log(LOG_DEBUG, "Dialed %c\n", digit);
735 +
736 +       switch(digit) {
737 +       case '0':
738 +       case '1':
739 +       case '2':
740 +       case '3':
741 +       case '4':
742 +       case '5':
743 +       case '6':
744 +       case '7':
745 +       case '8':
746 +       case '9':
747 +       case '*':
748 +       case '#':
749 +               snprintf(buf, sizeof(buf), "AT+VTS=%c\r", digit);
750 +               rfcomm_write(pvt, buf);
751 +               break;
752 +       default:
753 +               ast_log(LOG_WARNING, "Unknown digit '%c'\n", digit);
754 +               return -1;
755 +       }
756 +
757 +       return 0;
758 +
759 +}
760 +
761 +static struct ast_frame *mbl_read(struct ast_channel *ast)
762 +{
763 +
764 +       struct mbl_pvt *pvt = ast->tech_pvt;
765 +       struct ast_frame *f;
766 +       int r;
767 +
768 +       //ast_log(LOG_DEBUG, "*** mbl_read()\n");
769 +
770 +       if (!pvt->owner) {
771 +               return &ast_null_frame;
772 +       }
773 +       memset(&pvt->fr, 0x00, sizeof(struct ast_frame));
774 +       pvt->fr.frametype = AST_FRAME_VOICE;
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;
789 +               } else {
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 +}
804 +
805 +static int mbl_write(struct ast_channel *ast, struct ast_frame *frame)
806 +{
807 +
808 +       struct mbl_pvt *pvt = ast->tech_pvt;
809 +       int i, r, io_need, num_frames;
810 +       char *pfr, buf[DEVICE_FRAME_SIZE];
811 +
812 +       //ast_log(LOG_DEBUG, "*** mbl_write\n");
813 +
814 +       if (frame->frametype != AST_FRAME_VOICE) {
815 +               return 0;
816 +       }
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 +
834 +       for (i=0; i<num_frames; i++) {
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 +
850 +       return 0;
851 +
852 +}
853 +
854 +static int mbl_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
855 +{
856 +
857 +       struct mbl_pvt *pvt = oldchan->tech_pvt;
858 +
859 +       if (pvt && pvt->owner == oldchan)
860 +               pvt->owner = newchan;
861 +
862 +       return 0;
863 +
864 +}
865 +
866 +static int mbl_devicestate(void *data)
867 +{
868 +
869 +       char *device;
870 +       int res = AST_DEVICE_INVALID;
871 +       struct mbl_pvt *pvt;
872 +
873 +       device = ast_strdupa(S_OR(data, ""));
874 +
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) {
879 +               if (!strcmp(pvt->id, device))
880 +                       break;
881 +       }
882 +       AST_RWLIST_UNLOCK(&devices);
883 +
884 +       if (pvt) {
885 +               if (pvt->connected) {
886 +                       if (pvt->owner)
887 +                               res = AST_DEVICE_INUSE;
888 +                       else
889 +                               res = AST_DEVICE_NOT_INUSE;
890 +               }
891 +       }
892 +
893 +       return res;
894 +
895 +}
896 +
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 +
971 +       struct sockaddr_rc addr;
972 +       int s;
973 +
974 +       if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
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);
986 +               return -1;
987 +       }
988 +
989 +       memset(&addr, 0, sizeof(addr));
990 +       addr.rc_family = AF_BLUETOOTH;
991 +       bacpy(&addr.rc_bdaddr, &dst);
992 +       addr.rc_channel = remote_channel;
993 +       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
994 +               ast_log(LOG_DEBUG, "connect() failed (%d).\n", errno);
995 +               close(s);
996 +               return -1;
997 +       }
998 +
999 +       return s;
1000 +
1001 +}
1002 +
1003 +static int rfcomm_write(struct mbl_pvt *pvt, char *buf)
1004 +{
1005 +
1006 +       char *p;
1007 +       ssize_t num_write;
1008 +       int len;
1009 +
1010 +       ast_log(LOG_DEBUG, "rfcomm_write() (%s) [%s]\n", pvt->id, buf);
1011 +       len = strlen(buf);
1012 +       p = buf;
1013 +       while (len > 0) {
1014 +               if ((num_write = write(pvt->rfcomm_socket, p, len)) == -1) {
1015 +                       ast_log(LOG_DEBUG, "rfcomm_write() error [%d]\n", errno);
1016 +                       return 0;
1017 +               }
1018 +               len -= num_write;
1019 +               p += num_write;
1020 +       }
1021 +
1022 +       return 1;
1023 +
1024 +}
1025 +
1026 +/*
1027 +
1028 +       Here we need to return complete '\r' terminated single responses to the devices monitor thread, or
1029 +       a timeout if nothing is available.
1030 +       The rfcomm connection to the device is asynchronous, so there is no guarantee that responses will
1031 +       be returned in a single read() call. We handle this by buffering the input and returning one response
1032 +       per call, or a timeout if nothing is available.
1033 +
1034 +*/
1035 +
1036 +static int rfcomm_read(struct mbl_pvt *pvt, char *buf, char flush, int timeout)
1037 +{
1038 +
1039 +       int sel, rlen, slen;
1040 +       fd_set rfds;
1041 +       struct timeval tv;
1042 +       char *p;
1043 +
1044 +       if (!flush) {
1045 +               if ((p = strchr(pvt->rfcomm_buf, '\r'))) {
1046 +                       *p++ = 0x00;
1047 +                       if (*p == '\n')
1048 +                               p++;
1049 +                       memmove(buf, pvt->rfcomm_buf, strlen(pvt->rfcomm_buf));
1050 +                       *(buf + strlen(pvt->rfcomm_buf)) = 0x00;
1051 +                       memmove(pvt->rfcomm_buf, p, strlen(p));
1052 +                       *(pvt->rfcomm_buf+strlen(p)) = 0x00;
1053 +                       return 1;
1054 +               }
1055 +       } else {
1056 +               pvt->rfcomm_buf[0] = 0x00;
1057 +       }
1058 +
1059 +       FD_ZERO(&rfds);
1060 +       FD_SET(pvt->rfcomm_socket, &rfds);
1061 +
1062 +       tv.tv_sec = timeout;
1063 +       tv.tv_usec = 0;
1064 +
1065 +       if ((sel = select(pvt->rfcomm_socket + 1, &rfds, NULL, NULL, &tv)) > 0) {
1066 +               if (FD_ISSET(pvt->rfcomm_socket, &rfds)) {
1067 +                       slen = strlen(pvt->rfcomm_buf);
1068 +                       rlen = read(pvt->rfcomm_socket, pvt->rfcomm_buf + slen, sizeof(pvt->rfcomm_buf) - slen - 1);
1069 +                       if (rlen > 0) {
1070 +                               pvt->rfcomm_buf[slen+rlen] = 0x00;
1071 +                               if ((p = strchr(pvt->rfcomm_buf, '\r'))) {
1072 +                                       *p++ = 0x00;
1073 +                                       if (*p == '\n')
1074 +                                               p++;
1075 +                                       memmove(buf, pvt->rfcomm_buf, strlen(pvt->rfcomm_buf));
1076 +                                       *(buf + strlen(pvt->rfcomm_buf)) = 0x00;
1077 +                                       memmove(pvt->rfcomm_buf, p, strlen(p));
1078 +                                       *(pvt->rfcomm_buf+strlen(p)) = 0x00;
1079 +                                       return 1;
1080 +                               }
1081 +                       } else
1082 +                               return rlen;
1083 +               }
1084 +       } else if (sel == 0) { /* timeout */
1085 +               return 0;
1086 +       }
1087 +
1088 +       return 1;
1089 +
1090 +}
1091 +
1092 +/*
1093 +
1094 +       sco helpers
1095 +
1096 +*/
1097 +
1098 +static int sco_connect(bdaddr_t src, bdaddr_t dst)
1099 +{
1100 +
1101 +       struct sockaddr_sco addr;
1102 +       int s;
1103 +
1104 +       if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
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);
1115 +               return -1;
1116 +       }
1117 +
1118 +       memset(&addr, 0, sizeof(addr));
1119 +       addr.sco_family = AF_BLUETOOTH;
1120 +       bacpy(&addr.sco_bdaddr, &dst);
1121 +
1122 +       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1123 +               ast_log(LOG_DEBUG, "sco connect() failed (%d).\n", errno);
1124 +               close(s);
1125 +               return -1;
1126 +       }
1127 +
1128 +       return s;
1129 +
1130 +}
1131 +
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 +
1176 +/*
1177 +
1178 +       sdp helpers
1179 +
1180 +*/
1181 +
1182 +static int sdp_search(char *addr, int profile)
1183 +{
1184 +
1185 +       sdp_session_t *session = 0;
1186 +       bdaddr_t bdaddr;
1187 +       uuid_t svc_uuid;
1188 +       uint32_t range = 0x0000ffff;
1189 +       sdp_list_t *response_list, *search_list, *attrid_list;
1190 +       int status, port;
1191 +       sdp_list_t *proto_list;
1192 +       sdp_record_t *sdprec;
1193 +
1194 +       str2ba(addr, &bdaddr);
1195 +       port = 0;
1196 +       session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
1197 +       if (!session) {
1198 +               ast_log(LOG_DEBUG, "sdp_connect() failed on device %s.\n", addr);
1199 +               return 0;
1200 +       }
1201 +
1202 +       sdp_uuid32_create(&svc_uuid, profile);
1203 +       search_list = sdp_list_append(0, &svc_uuid);
1204 +       attrid_list = sdp_list_append(0, &range);
1205 +       response_list = 0x00;
1206 +       status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
1207 +       if (status == 0) {
1208 +               if (response_list) {
1209 +                       sdprec = (sdp_record_t *) response_list->data;
1210 +                       proto_list = 0x00;
1211 +                       if (sdp_get_access_protos(sdprec, &proto_list) == 0) {
1212 +                               port = sdp_get_proto_port(proto_list, RFCOMM_UUID);
1213 +                               sdp_list_free(proto_list, 0);
1214 +                       }
1215 +                       sdp_record_free(sdprec);
1216 +                       sdp_list_free(response_list, 0);
1217 +               } else
1218 +                       ast_log(LOG_DEBUG, "No responses returned for device %s.\n", addr);
1219 +       } else
1220 +               ast_log(LOG_DEBUG, "sdp_service_search_attr_req() failed on device %s.\n", addr);
1221 +
1222 +       sdp_list_free(search_list, 0);
1223 +       sdp_list_free(attrid_list, 0);
1224 +       sdp_close(session);
1225 +
1226 +       return port;
1227 +
1228 +}
1229 +
1230 +static sdp_session_t *sdp_register(void)
1231 +{
1232 +
1233 +       uint32_t service_uuid_int[] = {0, 0, 0, GENERIC_AUDIO_SVCLASS_ID};
1234 +       uint8_t rfcomm_channel = 1;
1235 +       const char *service_name = "Asterisk PABX";
1236 +       const char *service_dsc = "Asterisk PABX";
1237 +       const char *service_prov = "Asterisk";
1238 +
1239 +       uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid, svc_class1_uuid, svc_class2_uuid;
1240 +       sdp_list_t  *l2cap_list = 0, *rfcomm_list = 0, *root_list = 0, *proto_list = 0, *access_proto_list = 0, *svc_uuid_list = 0;
1241 +       sdp_data_t *channel = 0;
1242 +
1243 +       int err = 0;
1244 +       sdp_session_t *session = 0;
1245 +
1246 +       sdp_record_t *record = sdp_record_alloc();
1247 +
1248 +       sdp_uuid128_create(&svc_uuid, &service_uuid_int);
1249 +       sdp_set_service_id(record, svc_uuid);
1250 +
1251 +       sdp_uuid32_create(&svc_class1_uuid, GENERIC_AUDIO_SVCLASS_ID);
1252 +       sdp_uuid32_create(&svc_class2_uuid, HEADSET_PROFILE_ID);
1253 +
1254 +       svc_uuid_list = sdp_list_append(0, &svc_class1_uuid);
1255 +       svc_uuid_list = sdp_list_append(svc_uuid_list, &svc_class2_uuid);
1256 +       sdp_set_service_classes(record, svc_uuid_list);
1257 +
1258 +       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1259 +       root_list = sdp_list_append(0, &root_uuid);
1260 +       sdp_set_browse_groups( record, root_list );
1261 +
1262 +       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1263 +       l2cap_list = sdp_list_append(0, &l2cap_uuid);
1264 +       proto_list = sdp_list_append(0, l2cap_list);
1265 +
1266 +       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1267 +       channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
1268 +       rfcomm_list = sdp_list_append(0, &rfcomm_uuid);
1269 +       sdp_list_append(rfcomm_list, channel);
1270 +       sdp_list_append(proto_list, rfcomm_list);
1271 +
1272 +       access_proto_list = sdp_list_append(0, proto_list);
1273 +       sdp_set_access_protos(record, access_proto_list);
1274 +
1275 +       sdp_set_info_attr(record, service_name, service_prov, service_dsc);
1276 +
1277 +       if (!(session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY)))
1278 +               ast_log(LOG_WARNING, "Failed to connect sdp and create session.\n");
1279 +       else
1280 +               err = sdp_record_register(session, record, 0);
1281 +
1282 +       sdp_data_free(channel);
1283 +       sdp_list_free(rfcomm_list, 0);
1284 +       sdp_list_free(root_list, 0);
1285 +       sdp_list_free(access_proto_list, 0);
1286 +       sdp_list_free(svc_uuid_list, 0);
1287 +
1288 +       return session;
1289 +
1290 +}
1291 +
1292 +/*
1293 +
1294 +       Thread routines
1295 +
1296 +*/
1297 +
1298 +static void *do_monitor_phone(void *data)
1299 +{
1300 +
1301 +       struct mbl_pvt *pvt = (struct mbl_pvt *)data;
1302 +       struct ast_channel *chn;
1303 +       char monitor = 1;
1304 +       char buf[256];
1305 +       char cid_num[AST_MAX_EXTENSION], *pcids, *pcide;
1306 +       int s, t, i, smsi;
1307 +       int group, group2;
1308 +       int callp = 0, callsetupp;
1309 +       char brsf, nsmode, *p, *p1;
1310 +       char sms_src[13];
1311 +       char sms_txt[160];
1312 +
1313 +       brsf = nsmode = 0;
1314 +
1315 +       if (!rfcomm_write(pvt, "AT+BRSF=4\r"))
1316 +               monitor = 0;
1317 +
1318 +       while (monitor) {
1319 +
1320 +               if (pvt->state == MBL_STATE_DIAL1)
1321 +                       t = pvt->dial_timeout;
1322 +               else if (pvt->state == MBL_STATE_HANGUP)
1323 +                       t = 2;
1324 +               else if (pvt->state == MBL_STATE_OUTSMS1)
1325 +                       t = 2;
1326 +               else if (pvt->state == MBL_STATE_OUTSMS2)
1327 +                       t = 10;
1328 +               else
1329 +                       t = 1;
1330 +
1331 +               s = rfcomm_read(pvt, buf, 0, t);
1332 +
1333 +               if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) {
1334 +                       ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf);
1335 +                       switch (pvt->state) {
1336 +                       case MBL_STATE_INIT:
1337 +                               if (strstr(buf, "+BRSF:")) {
1338 +                                       brsf = 1;
1339 +                               } else if (strstr(buf, "ERROR") && !nsmode) {   /* Hmmm, Non-Standard Phone, just continue */
1340 +                                       rfcomm_write(pvt, "AT+CIND=?\r");
1341 +                                       pvt->state++;
1342 +                                       nsmode = 1;
1343 +                               } else if (strstr(buf, "OK") && brsf) {
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 +                                       }
1351 +                               }
1352 +                               break;
1353 +                       case MBL_STATE_INIT1:
1354 +                               if (strstr(buf, "+CIND:")) {
1355 +                                       group = callp = callsetupp = 0;
1356 +                                       group2 = 1;
1357 +                                       for (i=0; i<strlen(buf); i++) {
1358 +                                               if (buf[i] == '(')
1359 +                                                       group++;
1360 +                                               if (buf[i] == ')') {
1361 +                                                       group--;
1362 +                                                       if (group == 0)
1363 +                                                               group2++;
1364 +                                               }
1365 +                                               if (strstr(buf+i, "\"call\""))
1366 +                                                       callp = group2;
1367 +                                               if (strstr(buf+i, "\"call_setup\""))
1368 +                                                       callsetupp = group2;
1369 +                                               if (strstr(buf+i, "\"callsetup\""))
1370 +                                                       callsetupp = group2;
1371 +                                       }
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);
1378 +                                       if (callsetupp == 0) /* This phone has no call setup indication!! ... */
1379 +                                               pvt->no_callsetup = 1;
1380 +                                       ast_log(LOG_DEBUG, "CIEV_CALL=%d CIEV_CALLSETUP=%d\n", callp, callsetupp);
1381 +                               }
1382 +                               if (strstr(buf, "OK")) {
1383 +                                       rfcomm_write(pvt, "AT+CIND?\r");
1384 +                                       pvt->state++;
1385 +                               }
1386 +                               break;
1387 +                       case MBL_STATE_INIT2:
1388 +                               if ((p = strstr(buf, "+CIND:"))) {
1389 +                                       p += 5;
1390 +                                       if (*(p+(callp*2)) == '1') {
1391 +                                               ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s has a call in progress - delaying connection.\n", pvt->id);
1392 +                                               monitor = 0;
1393 +                                       }
1394 +                               } else if (strstr(buf, "OK")) {
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 +                                       }
1402 +                               }
1403 +                               break;
1404 +                       case MBL_STATE_INIT3:
1405 +                               if (strstr(buf, "OK")) {
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");
1418 +                                       pvt->state++;
1419 +                               }
1420 +                               break;
1421 +                       case MBL_STATE_INIT5:
1422 +                               if (strstr(buf, "OK")) {
1423 +                                       rfcomm_write(pvt, "AT+CMGF=1\r");
1424 +                                       pvt->state++;
1425 +                               }
1426 +                               break;
1427 +                       case MBL_STATE_INIT6:
1428 +                               if (strstr(buf, "ERROR")) {     /* No SMS Support ! */
1429 +                                       pvt->state = MBL_STATE_PREIDLE;
1430 +                               } else if (strstr(buf, "OK")) {
1431 +                                       rfcomm_write(pvt, "AT+CNMI=2,1,0,1,0\r");
1432 +                                       pvt->state++;
1433 +                               }
1434 +                               break;
1435 +                       case MBL_STATE_INIT7:
1436 +                               if (strstr(buf, "OK")) {        /* We have SMS Support */
1437 +                                       pvt->has_sms = 1;
1438 +                                       pvt->state = MBL_STATE_PREIDLE;
1439 +                               } else if (strstr(buf, "ERROR")) {
1440 +                                       pvt->has_sms = 0;
1441 +                                       pvt->state = MBL_STATE_PREIDLE;
1442 +                               }
1443 +                               break;
1444 +                       case MBL_STATE_PREIDLE: /* Nothing handled here, wait for timeout, then off we go... */
1445 +                               break;
1446 +                       case MBL_STATE_IDLE:
1447 +                               ast_log(LOG_DEBUG, "Device %s [%s]\n", pvt->id, buf);
1448 +                               if (strstr(buf, "RING")) {
1449 +                                       pvt->state = MBL_STATE_RING;
1450 +                               } else if (strstr(buf, "+CIEV:")) {
1451 +                                       if (strstr(buf, pvt->ciev_callsetup_3)) {       /* User has dialed out on handset */
1452 +                                               monitor = 0;                            /* We disconnect now, as he is    */
1453 +                                       }                                               /* probably leaving BT range...   */
1454 +                               }
1455 +                               break;
1456 +                       case MBL_STATE_DIAL: /* Nothing handled here, we need to wait for a timeout */
1457 +                               break;
1458 +                       case MBL_STATE_DIAL1:
1459 +                               if (strstr(buf, "OK")) {
1460 +                                       if (pvt->no_callsetup) {
1461 +                                               ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1462 +                                       } else {
1463 +                                               ast_setstate(pvt->owner, AST_STATE_RINGING);
1464 +                                       }
1465 +                                       pvt->state = MBL_STATE_OUTGOING;
1466 +                               }
1467 +                               break;
1468 +                       case MBL_STATE_OUTGOING:
1469 +                               if (strstr(buf, "+CIEV")) {
1470 +                                       if (strstr(buf, pvt->ciev_call_0)) {                            /* call was hung up */
1471 +                                               pvt->do_hangup = 0;
1472 +                                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1473 +                                       } else if (strstr(buf, pvt->ciev_callsetup_3)) {                /* b-party ringing */
1474 +                                               ast_queue_control(pvt->owner, AST_CONTROL_RINGING);
1475 +                                       } else if (strstr(buf, pvt->ciev_call_1) && !pvt->no_callsetup) { /* b-party answer */
1476 +                                               ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1477 +                                       }
1478 +                               }
1479 +                               break;
1480 +                       case MBL_STATE_RING:
1481 +                               cid_num[0] = 0x00;
1482 +                               if ((pcids = strstr(buf, "+CLIP:"))) {
1483 +                                       if ((pcids = strchr(pcids, '"'))) {
1484 +                                               if ((pcide = strchr(pcids+1, '"'))) {
1485 +                                                       strncpy(cid_num, pcids+1, pcide - pcids - 1);
1486 +                                                       cid_num[pcide - pcids - 1] = 0x00;
1487 +                                               }
1488 +                                       }
1489 +                                       chn = mbl_new(AST_STATE_RING, pvt, cid_num);
1490 +                                       if (chn) {
1491 +                                               if (ast_pbx_start(chn)) {
1492 +                                                       ast_log(LOG_ERROR, "Unable to start pbx on incoming call.\n");
1493 +                                                       ast_hangup(chn);
1494 +                                               } else
1495 +                                                       pvt->state = MBL_STATE_RING3;
1496 +                                       } else {
1497 +                                               ast_log(LOG_ERROR, "Unable to allocate channel for incoming call.\n");
1498 +                                               rfcomm_write(pvt, "AT+CHUP\r");
1499 +                                               pvt->state = MBL_STATE_IDLE;
1500 +                                       }
1501 +                               }
1502 +                               break;
1503 +                       case MBL_STATE_RING2:
1504 +                               chn = mbl_new(AST_STATE_RING, pvt, cid_num);
1505 +                               if (chn) {
1506 +                                       if (ast_pbx_start(chn)) {
1507 +                                               ast_log(LOG_ERROR, "Unable to start pbx on incoming call.\n");
1508 +                                               ast_hangup(chn);
1509 +                                       } else
1510 +                                               pvt->state = MBL_STATE_RING3;
1511 +                               } else {
1512 +                                       ast_log(LOG_ERROR, "Unable to allocate channel for incoming call.\n");
1513 +                                       rfcomm_write(pvt, "AT+CHUP\r");
1514 +                                       pvt->state = MBL_STATE_IDLE;
1515 +                               }
1516 +                               break;
1517 +                       case MBL_STATE_RING3:
1518 +                               if (strstr(buf, "+CIEV")) {
1519 +                                       if (strstr(buf, pvt->ciev_call_1)) {
1520 +                                               if (pvt->sent_answer) { /* We answered */
1521 +                                                       pvt->state = MBL_STATE_INCOMING;
1522 +                                               } else {                /* User answered on handset!, disconnect */
1523 +                                                       pvt->state = MBL_STATE_IDLE;
1524 +                                                       if (pvt->sco_socket > -1)
1525 +                                                               close(pvt->sco_socket);
1526 +                                                       ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1527 +                                               }
1528 +                                       }
1529 +                                       if ((strstr(buf, pvt->ciev_callsetup_0) || strstr(buf, pvt->ciev_call_0))) { /* Caller disconnected */
1530 +                                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1531 +                                       }
1532 +                               } 
1533 +                               break;
1534 +                       case MBL_STATE_INCOMING:
1535 +                               if (strstr(buf, "+CIEV")) {
1536 +                                       if (strstr(buf, pvt->ciev_call_0)) {
1537 +                                               pvt->do_hangup = 0;
1538 +                                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1539 +                                       }
1540 +                               }
1541 +                               break;
1542 +                       case MBL_STATE_HANGUP:
1543 +                               if (strstr(buf, "OK") || strstr(buf, pvt->ciev_call_0)) {
1544 +                                       close(pvt->sco_socket);
1545 +                                       pvt->sco_socket = -1;
1546 +                                       pvt->state = MBL_STATE_IDLE;
1547 +                               }
1548 +                               break;
1549 +                       case MBL_STATE_INSMS:
1550 +                               if (strstr(buf, "+CMGR:")) {
1551 +                                       memset(sms_src, 0x00, sizeof(sms_src));
1552 +                                       if ((p = strchr(buf, ','))) {
1553 +                                               if (*(++p) == '"')
1554 +                                                       p++;
1555 +                                               if ((p1 = strchr(p, ','))) {
1556 +                                                       if (*(--p1) == '"')
1557 +                                                               p1--;
1558 +                                                       memset(sms_src, 0x00, sizeof(sms_src));
1559 +                                                       strncpy(sms_src, p, p1 - p + 1);
1560 +                                               }
1561 +                                       }
1562 +                               } else if (strstr(buf, "OK")) {
1563 +                                       chn = mbl_new(AST_STATE_DOWN, pvt, NULL);
1564 +                                       strcpy(chn->exten, "sms");
1565 +                                       pbx_builtin_setvar_helper(chn, "SMSSRC", sms_src);
1566 +                                       pbx_builtin_setvar_helper(chn, "SMSTXT", sms_txt);
1567 +                                       if (ast_pbx_start(chn))
1568 +                                               ast_log(LOG_ERROR, "Unable to start pbx on incoming sms.\n");
1569 +                                       pvt->state = MBL_STATE_IDLE;
1570 +                               } else {
1571 +                                       ast_copy_string(sms_txt, buf, sizeof(sms_txt));
1572 +                               }
1573 +                               break;
1574 +                       case MBL_STATE_OUTSMS:
1575 +                               break;
1576 +                       case MBL_STATE_OUTSMS1:
1577 +                               break;
1578 +                       case MBL_STATE_OUTSMS2:
1579 +                               if (strstr(buf, "OK")) {
1580 +                                       pvt->state = MBL_STATE_IDLE;
1581 +                               }
1582 +                               break;
1583 +                       }
1584 +                       /* Unsolicited responses */
1585 +
1586 +                       if (strstr(buf, "+CMTI:")) {    /* SMS Incoming... */
1587 +                               if ((p = strchr(buf, ','))) {
1588 +                                       p++;
1589 +                                       smsi = atoi(p);
1590 +                                       if (smsi > 0) {
1591 +                                               snprintf(buf, sizeof(buf), "AT+CMGR=%d\r", smsi);
1592 +                                               rfcomm_write(pvt, buf);
1593 +                                               pvt->state = MBL_STATE_INSMS;
1594 +                                       }
1595 +                               }
1596 +                       }
1597 +
1598 +               } else if (s == 0) { /* Timeouts */
1599 +                       if (pvt->state == MBL_STATE_INIT2) { /* Some devices dont respond to AT+CIND? properly. RIM Blackberry 4 example */
1600 +                               pvt->state++;
1601 +                               rfcomm_write(pvt, "AT+CMER=3,0,0,1\r");
1602 +                       } else if (pvt->state == MBL_STATE_INIT3) { /* Some devices dont respond to AT+CMER=3,0,0,1 properly. VK 2020 for example */
1603 +                               pvt->state++;
1604 +                               rfcomm_write(pvt, "AT+CLIP=1\r");
1605 +                       } else if (pvt->state == MBL_STATE_PREIDLE) {
1606 +                               pvt->connected = 1;
1607 +                               ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s initialised and ready.\n", pvt->id);
1608 +                               pvt->state = MBL_STATE_IDLE;
1609 +                       } else if (pvt->state == MBL_STATE_DIAL) {
1610 +                               snprintf(buf, sizeof(buf), "ATD%s;\r", pvt->dial_number);
1611 +                               if (!rfcomm_write(pvt, buf)) {
1612 +                                       ast_log(LOG_ERROR, "Dial failed on %s state %d\n", pvt->owner->name, pvt->state);
1613 +                                       ast_queue_control(pvt->owner, AST_CONTROL_CONGESTION);
1614 +                                       pvt->state = MBL_STATE_IDLE;
1615 +                               } else {
1616 +                                       pvt->state = MBL_STATE_DIAL1;
1617 +                               }
1618 +                       } else if (pvt->state == MBL_STATE_DIAL1) {
1619 +                               ast_log(LOG_ERROR, "Dial failed on %s state %d\n", pvt->owner->name, pvt->state);
1620 +                               ast_queue_control(pvt->owner, AST_CONTROL_CONGESTION);
1621 +                               ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1622 +                               pvt->state = MBL_STATE_IDLE;
1623 +                       } else if (pvt->state == MBL_STATE_RING) { /* No CLIP?, bump it */
1624 +                               pvt->state = MBL_STATE_RING2;
1625 +                       } else if (pvt->state == MBL_STATE_HANGUP) {
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;
1635 +                       } else if (pvt->state == MBL_STATE_OUTSMS) {
1636 +                               snprintf(buf, sizeof(buf), "AT+CMGS=\"%s\"\r", pvt->dial_number);
1637 +                               rfcomm_write(pvt, buf);
1638 +                               pvt->state = MBL_STATE_OUTSMS1;
1639 +                       } else if (pvt->state == MBL_STATE_OUTSMS1) {
1640 +                               if (pvt->rfcomm_buf[0] == '>') {
1641 +                                       snprintf(buf, sizeof(buf), "%s%c", pvt->sms_txt, 0x1a);
1642 +                                       rfcomm_write(pvt, buf);
1643 +                                       pvt->state = MBL_STATE_OUTSMS2;
1644 +                               } else {
1645 +                                       ast_log(LOG_ERROR, "Failed to send SMS to %s on device %s\n", pvt->dial_number, pvt->id);
1646 +                                       pvt->state = MBL_STATE_IDLE;
1647 +                               }
1648 +                       } else if (pvt->state == MBL_STATE_OUTSMS2) {
1649 +                               ast_log(LOG_ERROR, "Failed to send SMS to %s on device %s\n", pvt->dial_number, pvt->id);
1650 +                               pvt->state = MBL_STATE_IDLE;
1651 +                       }
1652 +               } else if (s == -1) {
1653 +                       if (option_verbose > 2)
1654 +                               ast_verbose(VERBOSE_PREFIX_3  "Bluetooth Device %s has disconnected, reason (%d).\n", pvt->id, errno); 
1655 +                       monitor = 0;
1656 +               }
1657 +
1658 +       }
1659 +
1660 +       if (pvt->rfcomm_socket > -1)
1661 +               close(pvt->rfcomm_socket);
1662 +       if (pvt->sco_socket > -1)
1663 +               close(pvt->sco_socket);
1664 +       pvt->sco_socket = -1;
1665 +       pvt->connected = 0;
1666 +       pvt->monitor_thread = AST_PTHREADT_NULL;
1667 +
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 +
1678 +       return NULL;
1679 +
1680 +}
1681 +
1682 +static void *do_monitor_headset(void *data)
1683 +{
1684 +
1685 +       struct mbl_pvt *pvt = (struct mbl_pvt *)data;
1686 +       char monitor = 1;
1687 +       char buf[256];
1688 +       int s, t;
1689 +
1690 +       pvt->state = MBL_STATE_PREIDLE;
1691 +
1692 +       while (monitor) {
1693 +
1694 +               if (pvt->state == MBL_STATE_RING2)
1695 +                       t = 2;
1696 +               else
1697 +                       t = 1;
1698 +               s = rfcomm_read(pvt, buf, 0, t);
1699 +
1700 +               if ((s > 0) && (buf[0] != 0x0) && (buf[0] != '\r')) {
1701 +                       ast_log(LOG_DEBUG, "rfcomm_read() (%s) [%s]\n", pvt->id, buf);
1702 +                       switch (pvt->state) {
1703 +                       case MBL_STATE_RING2:
1704 +                               if (strstr(buf, "AT+CKPD=")) {
1705 +                                       ast_queue_control(pvt->owner, AST_CONTROL_ANSWER);
1706 +                                       pvt->state = MBL_STATE_INCOMING;
1707 +                                       rfcomm_write(pvt, "\r\n+VGS=13\r\n");
1708 +                                       rfcomm_write(pvt, "\r\n+VGM=13\r\n");
1709 +                               }
1710 +                               break;
1711 +                       case MBL_STATE_INCOMING:
1712 +                               if (strstr(buf, "AT+CKPD=")) {
1713 +                                       ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1714 +                               }
1715 +                               break;
1716 +                       default:
1717 +                               break;
1718 +                       }
1719 +                       if (strstr(buf, "AT+VGS=")) {
1720 +                               rfcomm_write(pvt, "\r\nOK\r\n");
1721 +                       } else if (strstr(buf, "AT+VGM=")) {
1722 +                               rfcomm_write(pvt, "\r\nOK\r\n");
1723 +                       }
1724 +               } else if (s == 0) {    /* Timeouts */
1725 +                       if (pvt->state == MBL_STATE_PREIDLE) {
1726 +                               pvt->connected = 1;
1727 +                               ast_verbose(VERBOSE_PREFIX_3 "Bluetooth Device %s initialised and ready.\n", pvt->id);
1728 +                               pvt->state = MBL_STATE_IDLE;
1729 +                       } else if (pvt->state == MBL_STATE_RING) {
1730 +                               pvt->sco_socket = sco_connect(pvt->adapter->addr, pvt->addr);
1731 +                               if (pvt->sco_socket > -1) {
1732 +                                       ast_setstate(pvt->owner, AST_STATE_RINGING);
1733 +                                       ast_queue_control(pvt->owner, AST_CONTROL_RINGING);
1734 +                                       pvt->state = MBL_STATE_RING2;
1735 +                               } else {
1736 +                                       ast_queue_control(pvt->owner, AST_CONTROL_HANGUP);
1737 +                               }
1738 +                       } else if (pvt->state == MBL_STATE_RING2) {
1739 +                               rfcomm_write(pvt, "\r\nRING\r\n");
1740 +                       }
1741 +               } else if (s == -1) {
1742 +                       if (option_verbose > 2)
1743 +                               ast_verbose(VERBOSE_PREFIX_3  "Bluetooth Device %s has disconnected, reason (%d).\n", pvt->id, errno); 
1744 +                       monitor = 0;
1745 +               }
1746 +
1747 +       }
1748 +
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 +
1761 +       return NULL;
1762 +
1763 +}
1764 +
1765 +static int start_monitor(struct mbl_pvt *pvt)
1766 +{
1767 +
1768 +       if (pvt->type == MBL_TYPE_PHONE) {
1769 +               if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_phone, pvt) < 0) {
1770 +                       pvt->monitor_thread = AST_PTHREADT_NULL;
1771 +                       return 0;
1772 +               }
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 +
1778 +       } else {
1779 +               if (ast_pthread_create_background(&pvt->monitor_thread, NULL, do_monitor_headset, pvt) < 0) {
1780 +                       pvt->monitor_thread = AST_PTHREADT_NULL;
1781 +                       return 0;
1782 +               }
1783 +       }
1784 +
1785 +       return 1;
1786 +
1787 +}
1788 +
1789 +static void *do_discovery(void *data)
1790 +{
1791 +
1792 +       struct adapter_pvt *adapter;
1793 +       struct mbl_pvt *pvt;
1794 +
1795 +       for (;;) {
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 +                                               }
1812 +                                       }
1813 +                               }
1814 +                               AST_RWLIST_UNLOCK(&devices);
1815 +                       }
1816 +               }
1817 +               AST_RWLIST_UNLOCK(&adapters);
1818 +               /* Go to sleep */
1819 +               sleep(discovery_interval);
1820 +       }
1821 +
1822 +       return NULL;
1823 +}
1824 +
1825 +static void *do_sco_listen(void *data)
1826 +{
1827 +
1828 +       int ns;
1829 +       struct sockaddr_sco addr;
1830 +       char saddr[18];
1831 +       struct sco_options so;
1832 +       socklen_t len;
1833 +       int opt = 1;
1834 +       socklen_t addrlen;
1835 +       struct mbl_pvt *pvt;
1836 +       struct adapter_pvt *adapter = (struct adapter_pvt *) data;
1837 +
1838 +       if ((adapter->sco_socket = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
1839 +               ast_log(LOG_ERROR, "Unable to create sco listener socket.\n");
1840 +               return NULL;
1841 +       }
1842 +       memset(&addr, 0, sizeof(addr));
1843 +       addr.sco_family = AF_BLUETOOTH;
1844 +       bacpy(&addr.sco_bdaddr, &adapter->addr);
1845 +       if (bind(adapter->sco_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
1846 +               ast_log(LOG_ERROR, "Unable to bind sco listener socket. (%d)\n", errno);
1847 +               close(adapter->sco_socket);
1848 +               return NULL;
1849 +       }
1850 +       if (setsockopt(adapter->sco_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
1851 +               ast_log(LOG_ERROR, "Unable to setsockopt sco listener socket.\n");
1852 +               close(adapter->sco_socket);
1853 +               return NULL;
1854 +       }
1855 +       if (listen(adapter->sco_socket, 5) < 0) {
1856 +               ast_log(LOG_ERROR, "Unable to listen sco listener socket.\n");
1857 +               close(adapter->sco_socket);
1858 +               return NULL;
1859 +       }
1860 +       while (1) {
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");
1865 +                       len = sizeof(so);
1866 +                       getsockopt(ns, SOL_SCO, SCO_OPTIONS, &so, &len);
1867 +
1868 +                       ba2str(&addr.sco_bdaddr, saddr);
1869 +                       ast_log(LOG_DEBUG, "Incoming Audio Connection from device %s MTU is %d\n", saddr, so.mtu);
1870 +
1871 +                       pvt = NULL;
1872 +                       AST_RWLIST_RDLOCK(&devices);
1873 +                       AST_RWLIST_TRAVERSE(&devices, pvt, entry) {
1874 +                               if (!bacmp(&pvt->addr, &addr.sco_bdaddr)) 
1875 +                                       break;
1876 +                       }
1877 +                       AST_RWLIST_UNLOCK(&devices);
1878 +                       if (pvt) {
1879 +                               if (pvt->sco_socket != -1)
1880 +                                       close(pvt->sco_socket);
1881 +                               pvt->sco_socket = ns;
1882 +                       } else
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 +               }
1887 +       }
1888 +
1889 +       return NULL;
1890 +
1891 +}
1892 +
1893 +/*
1894 +
1895 +       Module
1896 +
1897 +*/
1898 +
1899 +static int mbl_load_config(void)
1900 +{
1901 +
1902 +       struct ast_config *cfg = NULL;
1903 +       char *cat = NULL;
1904 +       struct ast_variable *var;
1905 +       const char *id, *address, *useadapter, *port, *context, *type, *skip, *group, *master, *nocallsetup, *aligndetect, *blackberry;
1906 +       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 };
1912 +
1913 +       cfg = ast_config_load(MBL_CONFIG);
1914 +       if (!cfg)
1915 +               return 0;
1916 +
1917 +       for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
1918 +               if (!strcasecmp(var->name, "interval"))
1919 +                       discovery_interval = atoi(var->value);
1920 +       }
1921 +
1922 +       /* load adapters first */
1923 +       cat = ast_category_browse(cfg, NULL);
1924 +       while (cat) {
1925 +               if (!strcasecmp(cat, "adapter")) {
1926 +                       id = ast_variable_retrieve(cfg, cat, "id");
1927 +                       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");
1986 +                       port = ast_variable_retrieve(cfg, cat, "port");
1987 +                       context = ast_variable_retrieve(cfg, cat, "context");
1988 +                       type = ast_variable_retrieve(cfg, cat, "type");
1989 +                       skip = ast_variable_retrieve(cfg, cat, "dtmfskip");
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)))) {
2006 +                                       if (type && !strcmp(type, "headset"))
2007 +                                               pvt->type = MBL_TYPE_HEADSET;
2008 +                                       else
2009 +                                               pvt->type = MBL_TYPE_PHONE;
2010 +
2011 +                                       if (blackberry)
2012 +                                               pvt->blackberry = ast_true(blackberry);
2013 +
2014 +                                       ast_copy_string(pvt->id, cat, sizeof(pvt->id));
2015 +                                       str2ba(address, &pvt->addr);
2016 +                                       ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
2017 +                                       if (group)
2018 +                                               pvt->group = atoi(group);       /* group 0 if invalid */
2019 +                                       pvt->state = MBL_STATE_INIT;
2020 +                                       pvt->rfcomm_socket = -1;
2021 +                                       pvt->rfcomm_port = atoi(port);
2022 +                                       pvt->sco_socket = -1;
2023 +                                       pvt->monitor_thread = AST_PTHREADT_NULL;
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 +                                       }
2031 +                                       pvt->dsp = ast_dsp_new();
2032 +                                       if (skip) {
2033 +                                               if ((pvt->dtmf_skip = atoi(skip)) == 0)
2034 +                                                       pvt->dtmf_skip = 200;
2035 +                                       } else
2036 +                                               pvt->dtmf_skip = 200;
2037 +                                       ast_dsp_set_features(pvt->dsp, DSP_FEATURE_DTMF_DETECT);
2038 +                                       ast_dsp_digitmode(pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
2039 +                                       pvt->adapter = adapter;
2040 +                                       AST_RWLIST_WRLOCK(&devices);
2041 +                                       AST_RWLIST_INSERT_HEAD(&devices, pvt, entry);
2042 +                                       AST_RWLIST_UNLOCK(&devices);
2043 +                               }
2044 +                       } else {
2045 +                               ast_log(LOG_ERROR, "Device %s has no address/port/adapter configured. It won't be enabled.\n", cat);
2046 +                       }
2047 +               }
2048 +               cat = ast_category_browse(cfg, cat);
2049 +       }
2050 +
2051 +       ast_config_destroy(cfg);
2052 +
2053 +       return 1;
2054 +
2055 +}
2056 +
2057 +static int unload_module(void)
2058 +{
2059 +
2060 +       struct mbl_pvt *pvt;
2061 +       struct adapter_pvt *adapter;
2062 +
2063 +       /* First, take us out of the channel loop */
2064 +       ast_channel_unregister(&mbl_tech);
2065 +
2066 +       /* Kill the discovery thread */
2067 +       if (discovery_thread != AST_PTHREADT_NULL) {
2068 +               pthread_cancel(discovery_thread);
2069 +               pthread_join(discovery_thread, NULL);
2070 +       }
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);
2107 +
2108 +       /* Unregister the CLI & APP */
2109 +       ast_cli_unregister_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
2110 +       ast_unregister_application(app_mblstatus);
2111 +       ast_unregister_application(app_mblsendsms);
2112 +
2113 +       return 0;
2114 +
2115 +}
2116 +
2117 +static int load_module(void)
2118 +{
2119 +
2120 +       int dev_id, s;
2121 +
2122 +       /* Check if we have Bluetooth, no point loading otherwise... */
2123 +       dev_id = hci_get_route(NULL);
2124 +       s = hci_open_dev(dev_id);
2125 +       if (dev_id < 0 || s < 0) {
2126 +               ast_log(LOG_ERROR, "No Bluetooth device found. Not loading module.\n");
2127 +               return AST_MODULE_LOAD_DECLINE;
2128 +       }
2129 +
2130 +       hci_close_dev(s);
2131 +
2132 +       if (!mbl_load_config()) {
2133 +               ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", MBL_CONFIG);
2134 +               return AST_MODULE_LOAD_DECLINE;
2135 +       }
2136 +
2137 +       sdp_session = sdp_register();
2138 +
2139 +       /* Spin the discovery thread */
2140 +       if (ast_pthread_create_background(&discovery_thread, NULL, do_discovery, NULL) < 0) {
2141 +               ast_log(LOG_ERROR, "Unable to create discovery thread.\n");
2142 +               return AST_MODULE_LOAD_DECLINE;
2143 +       }
2144 +
2145 +       ast_cli_register_multiple(mbl_cli, sizeof(mbl_cli) / sizeof(mbl_cli[0]));
2146 +       ast_register_application(app_mblstatus, mbl_status_exec, mblstatus_synopsis, mblstatus_desc);
2147 +       ast_register_application(app_mblsendsms, mbl_sendsms_exec, mblsendsms_synopsis, mblsendsms_desc);
2148 +
2149 +       /* Make sure we can register our channel type */
2150 +       if (ast_channel_register(&mbl_tech)) {
2151 +               ast_log(LOG_ERROR, "Unable to register channel class %s\n", "Mobile");
2152 +               return AST_MODULE_LOAD_FAILURE;
2153 +       }
2154 +
2155 +       return 0;
2156 +}
2157 +
2158 +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Bluetooth Mobile Device Channel Driver",
2159 +               .load = load_module,
2160 +               .unload = unload_module,
2161 +);
2162 diff -Nru asterisk-addons-1.4.8.org/configs/mobile.conf.sample asterisk-addons-1.4.8/configs/mobile.conf.sample
2163 --- asterisk-addons-1.4.8.org/configs/mobile.conf.sample        1970-01-01 01:00:00.000000000 +0100
2164 +++ asterisk-addons-1.4.8/configs/mobile.conf.sample    2009-06-04 22:20:03.000000000 +0200
2165 @@ -0,0 +1,68 @@
2166 +;
2167 +; mobile.conf
2168 +; configuration file for chan_mobile
2169 +;
2170 +
2171 +[general]
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
2190 +
2191 +; The following is a list of the devices we deal with.
2192 +; Every device listed below will be available for calls in and out of Asterisk. 
2193 +; Each device needs an adapter=xxxx entry which determines which bluetooth adapter is used.
2194 +; Use the CLI command 'mobile search' to discover devices.
2195 +; Use the CLI command 'mobile show devices' to see device status.
2196 +;
2197 +; To place a call out through a mobile phone use Dial(Mobile/[device]/NNN.....) or Dial(Mobile/gn/NNN......) in your dialplan.
2198 +; To call a headset use Dial(Mobile/[device]).
2199 +
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
2234 diff -Nru asterisk-addons-1.4.8.org/configure.ac asterisk-addons-1.4.8/configure.ac
2235 --- asterisk-addons-1.4.8.org/configure.ac      2008-02-13 23:58:11.000000000 +0100
2236 +++ asterisk-addons-1.4.8/configure.ac  2009-06-04 22:20:03.000000000 +0200
2237 @@ -161,11 +161,13 @@
2238  # from here on down, library checking should be done in alphabetical order
2239  # by the --with option name, to make things easier for the users :-)
2240  
2241 +AST_EXT_LIB_SETUP([BLUETOOTH], [Bluetooth Support], [bluetooth])
2242  AST_EXT_LIB_SETUP([CURSES], [curses], [curses])
2243  AST_EXT_LIB_SETUP([NCURSES], [ncurses], [ncurses])
2244  AST_EXT_LIB_SETUP([MYSQLCLIENT], [mysqlclient], [mysqlclient])
2245  AST_EXT_LIB_SETUP([ASTERISK], [asterisk], [asterisk])
2246  
2247 +AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [ba2str], [bluetooth/bluetooth.h])
2248  AST_EXT_LIB_CHECK([CURSES], [curses], [initscr], [curses.h])
2249  
2250  AST_EXT_LIB_CHECK([NCURSES], [ncurses], [initscr], [curses.h])
2251 diff -Nru asterisk-addons-1.4.8.org/makeopts.in asterisk-addons-1.4.8/makeopts.in
2252 --- asterisk-addons-1.4.8.org/makeopts.in       2008-02-13 23:58:11.000000000 +0100
2253 +++ asterisk-addons-1.4.8/makeopts.in   2009-06-04 22:20:03.000000000 +0200
2254 @@ -34,6 +34,9 @@
2255  sharedstatedir = @sharedstatedir@
2256  sysconfdir = @sysconfdir@
2257  
2258 +BLUETOOTH_LIB=@BLUETOOTH_LIB@
2259 +BLUETOOTH_INCLUDE=@BLUETOOTH_INCLUDE@
2260 +
2261  CURSES_LIB=@CURSES_LIB@
2262  CURSES_INCLUDE=@CURSES_INCLUDE@
2263