]> git.itanic.dy.fi Git - maemo-mapper/blob - src/gpsbt.c
2a6e69c1cdc468e416d444f273b40be1c3e7183d
[maemo-mapper] / src / gpsbt.c
1 /*
2  * Copyright (C) 2006, 2007 John Costigan.
3  *
4  * POI and GPS-Info code originally written by Cezary Jackiewicz.
5  *
6  * Default map data provided by http://www.openstreetmap.org/
7  *
8  * This file is part of Maemo Mapper.
9  *
10  * Maemo Mapper is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Maemo Mapper is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 /*
25 GPS BT management API. The API is used by those applications that
26 wish to use services provided by gps daemon i.e., they wish to receive
27 GPS data from the daemon. See README file for more details.
28
29 Copyright (C) 2006 Nokia Corporation. All rights reserved.
30
31 Author: Jukka Rissanen <jukka.rissanen@nokia.com>
32
33 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
34
35 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
36 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
37 The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
38
39 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
41 */
42
43 /* $Id:$ */
44
45 #ifdef HAVE_CONFIG_H
46 #    include "config.h"
47 #endif
48
49 #define _GNU_SOURCE
50
51 #include <errno.h>
52 #include <unistd.h>
53 #include <fcntl.h>
54 #include <string.h>
55 #include <signal.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/wait.h>
59 #include <sys/time.h>
60 #include <time.h>
61
62 #define DBUS_API_SUBJECT_TO_CHANGE
63 #include <dbus/dbus-glib.h>
64
65 #include "gpsbt.h"
66
67 #ifdef LEGACY
68
69 /* Set following #if to 1 if you want to use automatic bt dev disconnect.
70  * This does not seem to work correctly currently (disconnects too fast)
71  */
72 #if 0
73 #define USE_AUTOMATIC_DISCONNECT
74 #else
75 #undef USE_AUTOMATIC_DISCONNECT
76 #endif
77
78 /* default control socket (not used by default) */
79 #define CTRL_SOCK "/tmp/.gpsd_ctrl_sock"
80
81 /* Note that 10 second timeout should not be lowered, because
82  * then there might be GPS device connection errors if there
83  * are multiple GPS devices that the user is using.
84  * E.g., if the timeout is set to 5 secs and there are three
85  * GPS devices that the user is using, it is possible that
86  * if the 1st device fails, the other devices might also fail
87  * if the timeout is lower than 10 secs.
88  */
89 #if 0
90 #define DEFAULT_TIMEOUT (1000*10) /* 10 second timeout (in ms) */
91 #else
92 #define DEFAULT_TIMEOUT (1000*60) /* 60 second timeout (in ms) */
93 #endif
94
95 /* BT dbus service location */
96 #define BASE_PATH                "/org/bluez"
97 #define BASE_INTERFACE           "org.bluez"
98 #define ADAPTER_PATH             BASE_PATH
99 #define ADAPTER_INTERFACE        BASE_INTERFACE ".Adapter"
100 #define MANAGER_PATH             BASE_PATH
101 #define MANAGER_INTERFACE        BASE_INTERFACE ".Manager"
102 #define ERROR_INTERFACE          BASE_INTERFACE ".Error"
103 #define SECURITY_INTERFACE       BASE_INTERFACE ".Security"
104 #define RFCOMM_INTERFACE         BASE_INTERFACE ".RFCOMM"
105 #define BLUEZ_DBUS               BASE_INTERFACE
106
107 #define LIST_ADAPTERS            "ListAdapters"
108 #define LIST_BONDINGS            "ListBondings"
109 #define CREATE_BONDING           "CreateBonding"
110 #define GET_REMOTE_NAME          "GetRemoteName"
111 #define GET_REMOTE_SERVICE_CLASSES "GetRemoteServiceClasses"
112
113 #define BTCOND_PATH              "/com/nokia/btcond/request"
114 #define BTCOND_BASE              "com.nokia.btcond"
115 #define BTCOND_INTERFACE         BTCOND_BASE ".request"
116 #define BTCOND_REQUEST           BTCOND_INTERFACE
117 #define BTCOND_CONNECT           "rfcomm_connect"
118 #define BTCOND_DISCONNECT        "rfcomm_disconnect"
119 #define BTCOND_DBUS              BTCOND_BASE
120
121 #define GPS_SERVICE_CLASS_STR "positioning"
122
123 typedef struct {
124   char *adapter;  /* do not free this, it is freed somewhere else */
125   char *bonding;  /* allocated from heap, you must free this */
126 } bonding_t;
127
128
129 /* Not all gps bt devices set the positioning bit in service class to 1,
130  * so we need a way to figure out whether the device supports positioning
131  * or not. The array contains sub-string for devices that we know to
132  * support positioning. The sub-string will be matched against device
133  * remote name that we get using dbus GetRemoteName call. The name is
134  * fetched only if we have no BT device in the system that has the
135  * positioning bit activated. Note that the listed string is case
136  * sensitive.
137  */
138 static const char const *gps_device_names[] = {
139   "HOLUX GR-",   /* like Holux GR-231 or similar */
140   "Nokia LD-",   /* for Nokia LD-1W, note that LD-3W has positioning bit set */
141   "GPS",         /* Insmat BT-GPS-3244C8 or TomTom Wireless GPS MkII */
142   "i-Blue",      /* i-Blue line of GPS receivers. */
143   0  /* must be at the end */
144 };
145
146
147 /* ----------------------------------------------------------------------- */
148 static int debug_level;
149
150 #ifdef DEBUG
151 #if (__GNUC__ > 2) && ((__GNUC__ > 3) || (__GNUC_MINOR__ > 2))
152 #define PDEBUG(fmt...) do {                                                \
153     if (debug_level) {                                                     \
154       struct timeval tv;                                                   \
155       gettimeofday(&tv, 0);                                                \
156       printf("DEBUG[%d]:%ld.%ld:%s:%s():%d: ",                             \
157              getpid(),                                                     \
158              tv.tv_sec, tv.tv_usec,                                        \
159              __FILE__, __FUNCTION__, __LINE__);                            \
160       printf(fmt);                                                         \
161       fflush(stdout);                                                      \
162     }                                                                      \
163   }while(0)
164 #else
165 #define PDEBUG(fmt...) do {                                                \
166     if (debug_level) {                                                     \
167       struct timeval tv;                                                   \
168       gettimeofday(&tv, 0);                                                \
169       printf("DEBUG[%d]:%ld.%ld:%s:%s():%d: ",                             \
170              getpid(),                                                     \
171              tv.tv_sec, tv.tv_usec,                                        \
172              __FILE__, __FUNCTION__, __LINE__);                            \
173       printf(##fmt);                                                       \
174       fflush(stdout);                                                      \
175     }                                                                      \
176   }while(0)
177 #endif
178 #else
179 #define PDEBUG(fmt...)
180 #endif
181
182
183 /* ----------------------------------------------------------------------- */
184 static int check_device_name(char *name)
185 {
186   int i=0, st=0;
187
188   while (gps_device_names[i]) {
189     if (strstr(name, gps_device_names[i])) {
190       st = 1;
191       break;
192     }
193     i++;
194   }
195
196   return st;
197 }
198
199
200 /* ----------------------------------------------------------------------- */
201 static inline DBusGConnection *get_dbus_gconn(GError **error)
202 {
203   DBusGConnection *conn;
204
205   conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, error);
206   return conn;
207 }
208
209
210 /* ----------------------------------------------------------------------- */
211 static int set_error_msg(char *errbuf,
212                          int errbuf_max_len,
213                          char *msg,
214                          ...)
215 {
216   int st, len;
217   va_list args;
218
219   if (!errbuf) {
220     errno = EINVAL;
221     return -1;
222   }
223
224   va_start(args, msg);
225   st = vsnprintf(errbuf, errbuf_max_len, msg, args);
226   va_end(args);
227
228   /* Remove \n if it is at the end of the line (so that caller can
229    * print the string as it wishes)
230    */
231   len = strlen(errbuf);
232   if (len>0 && errbuf[len-1]=='\n')
233     errbuf[len-1]='\0';
234
235   return st;
236 }
237
238
239 /* ----------------------------------------------------------------------- */
240 extern int gpsbt_start(char *bda,
241                        int our_debug_level,
242                        int gpsd_debug_level,
243                        short port,
244                        char *error_buf,
245                        int error_buf_max_len,
246                        int timeout_ms,
247                        gpsbt_t *ctx)
248 {
249   int i, j, k, st, num_bondings = 0,
250     bonding_cnt = 0, num_classes = 0, num_rfcomms = 0,
251     num_posdev = 0;
252   GError *error = NULL;
253   DBusGConnection *bus = NULL;
254   DBusGProxy *proxy = NULL;
255   char **str_iter = NULL;
256   char **tmp_bondings = 0, **tmp_classes = 0;
257   char **adapters = 0;
258   char **rfcomms = 0;
259   bonding_t *bondings = 0; /* points to array of bonding_t */
260   bonding_t *posdev = 0; /* bondings with positioning bit on */
261   char *tmp;
262   char *onoff;
263   const char const *spp="SPP";
264   int timeout;
265   char *gpsd_prog;
266   char *gpsd_ctrl_sock;
267
268
269 #if (__GNUC__ > 2) && ((__GNUC__ > 3) || (__GNUC_MINOR__ > 2))
270 #define ERRSTR(fmt, args...)                                     \
271   if (error_buf && error_buf_max_len>0) {                        \
272     set_error_msg(error_buf, error_buf_max_len, fmt, args);      \
273   } else {                                                       \
274     PDEBUG(fmt, args);                                           \
275   }
276 #else
277 #define ERRSTR(fmt, args...)                                     \
278   if (error_buf && error_buf_max_len>0) {                        \
279     set_error_msg(error_buf, error_buf_max_len, fmt, ##args);    \
280   } else {                                                       \
281     PDEBUG(fmt, ##args);                                         \
282   }
283 #endif  
284
285   if (!ctx) {
286     errno = EINVAL;
287     return -1;
288   }
289
290   debug_level = our_debug_level;
291
292   /* context & error needs to be clean */
293   memset(ctx, 0, sizeof(gpsmgr_t));
294
295   if (timeout_ms==0)
296     timeout = DEFAULT_TIMEOUT;
297   else if (timeout_ms < 0)
298     timeout = -1;
299   else
300     timeout = timeout_ms;
301
302   ctx->timeout = timeout;
303
304   /* Caller can override the name of the gpsd program and
305    * the used control socket.
306    */
307   gpsd_prog = getenv("GPSD_PROG");
308   gpsd_ctrl_sock = getenv("GPSD_CTRL_SOCK");
309
310   if (!gpsd_prog)
311     gpsd_prog = "gpsd";
312
313   if (!gpsd_ctrl_sock)
314     gpsd_ctrl_sock = CTRL_SOCK;
315
316   /* First find out what BT devices are paired with us, then figure out
317    * which one of those are GPS devices (positioning bit in class is
318    * set). If found, create a rfcommX device for GPS BT and pass that
319    * as a parameter when starting gpsd.
320    */
321
322   /* But first things first, if gpsd is already running then it is
323    * no point trying to find out the GPS BT devices because some program
324    * has already figured it out.
325    */
326   st = gpsmgr_is_gpsd_running(&ctx->mgr, NULL, GPSMGR_MODE_LOCK_IF_POSSIBLE);
327   if (st) {
328
329     if (st!=2) { /* gpsd is running, value 2 would mean that gpsd is not
330                   * running but we have a lock acquired
331                   */
332
333       st = gpsmgr_start(gpsd_prog, NULL, gpsd_ctrl_sock,
334                         gpsd_debug_level, port, &ctx->mgr);
335       if (!st) {
336         /* everything is ok */
337         PDEBUG("%s already running, doing nothing\n",gpsd_prog);
338         goto OUT;
339       }
340
341       PDEBUG("gpsmgr_start() returned %d [%s, %d]\n",st,strerror(errno),errno);
342       /* Note, no exit or return here, let the API do its magic */
343     }
344   }
345
346
347   /* Use the dbus interface to get the BT information */
348
349   error = NULL;
350   bus = get_dbus_gconn(&error);
351   if (error) {
352     st = -1;
353     errno = ECONNREFUSED; /* close enough :) */
354     ERRSTR("%s", error->message);
355     PDEBUG("Cannot get reply message [%s]\n", error->message);
356     goto OUT;
357   }
358
359 #define CHECK_ERROR(s,o,i,m,t)                                             \
360   if (st<0) {                                                              \
361     ERRSTR("Cannot send msg (service=%s, object=%s, interface=%s, "        \
362            "method=%s) [%s]\n", s, o, i, m,                                \
363            error.message ? error.message : "<no error msg>");              \
364     goto OUT;                                                              \
365   }
366
367
368   /* We need BT information only if the caller does not specify
369    * the BT address. If address is defined, it is assumed that
370    * it is already bonded and we just create RFCOMM connection
371    * to it.
372    */
373   if (!bda) {
374     proxy = dbus_g_proxy_new_for_name(bus,
375         BLUEZ_DBUS, MANAGER_PATH, MANAGER_INTERFACE);
376
377     error = NULL;
378     if(!dbus_g_proxy_call(proxy, LIST_ADAPTERS, &error, G_TYPE_INVALID,
379           G_TYPE_STRV, &adapters, G_TYPE_INVALID)
380         || error || !adapters || !*adapters || !**adapters) {
381       PDEBUG("No adapters found.\n");
382       st = -1;
383       goto OUT;
384     }
385     g_object_unref(proxy);
386
387     /* For each adapter, get bondings */
388     i = 0;
389     while (adapters[i]) {
390       proxy = dbus_g_proxy_new_for_name(bus,
391           BLUEZ_DBUS, adapters[i], ADAPTER_INTERFACE);
392
393       error = NULL;
394       if(!dbus_g_proxy_call(proxy, LIST_BONDINGS, &error, G_TYPE_INVALID,
395             G_TYPE_STRV, &tmp_bondings, G_TYPE_INVALID)
396           || error || !tmp_bondings || !*tmp_bondings || !**tmp_bondings) {
397         PDEBUG("Call to LIST_BONDINGS failed (error=%s, tmp_bondings[0]=%s\n",
398             error ? error->message : "<null>",
399             tmp_bondings ? tmp_bondings[0] : "<null>");
400       } else {
401         /* Count the bondings. */
402         for(num_bondings = 0, str_iter = tmp_bondings; *str_iter;
403             str_iter++, num_bondings++);
404
405         /* Allocate bondings array, note that we DO allocate one extra array
406          * element for marking end of array.
407          */
408         bondings = (bonding_t *)realloc(bondings,
409                 (bonding_cnt+num_bondings+1)*sizeof(bonding_t));
410         if (!bondings) {
411           st = -1;
412           errno = ENOMEM;
413           goto OUT;
414         }
415         bondings[bonding_cnt+num_bondings].bonding=
416           bondings[bonding_cnt+num_bondings].adapter=NULL; /* just in case */
417
418
419         j = 0;
420         while (j<num_bondings && tmp_bondings[j]) {
421           bondings[bonding_cnt].bonding = strdup(tmp_bondings[j]);
422           free(tmp_bondings[j]);
423
424           bondings[bonding_cnt].adapter = adapters[i]; /* no allocation! */
425           
426           PDEBUG("Bondings[%d]=%s (adapter=%s)\n", bonding_cnt,
427                  bondings[bonding_cnt].bonding, bondings[bonding_cnt].adapter);
428
429           /* Get all remote service classes for this bonding. */
430           error = NULL;
431           if(dbus_g_proxy_call(proxy, GET_REMOTE_SERVICE_CLASSES, &error,
432                 G_TYPE_STRING, bondings[bonding_cnt].bonding, G_TYPE_INVALID,
433                 G_TYPE_STRV, &tmp_classes, G_TYPE_INVALID)
434               && !error && tmp_classes && *tmp_classes && **tmp_classes) {
435
436             k = 0;
437             while (tmp_classes[k]) {
438               if (!strcasecmp(tmp_classes[k], GPS_SERVICE_CLASS_STR)) {
439                 /* match found, this device claims to be able to provide
440                  * positioning data
441                  */
442                 posdev = (bonding_t *)realloc(posdev,
443                     (num_posdev+1)*sizeof(bonding_t));
444                 if (!posdev) {
445                   st = -1;
446                   errno = ENOMEM;
447                   goto OUT;
448                 }
449               
450                 posdev[num_posdev].bonding=strdup(
451                     bondings[bonding_cnt].bonding);
452                 posdev[num_posdev].adapter=bondings[bonding_cnt].adapter;
453                 num_posdev++;
454                 onoff = "ON";
455               } else {
456                 onoff = "OFF";
457               }
458               PDEBUG("Addr=%s, Class[%d]=%s (adapter=%s), "
459                       "positioning bit %s\n",
460                      bondings[bonding_cnt].bonding, k, tmp_classes[k],
461                      bondings[bonding_cnt].adapter, onoff);
462               free(tmp_classes[k]);
463               
464               k++;
465             }
466
467             free(tmp_classes);
468             tmp_classes=0;
469           }
470
471           num_classes = 0;
472           bonding_cnt++;
473           j++;
474         }
475       }
476
477       free(tmp_bondings);
478       tmp_bondings=0;
479       g_object_unref(proxy);
480       i++;
481     }
482
483 #if 0
484 #ifdef DEBUG
485     if (debug_level) {
486       int i=0;
487       if (bonding_cnt) {
488         PDEBUG("Bondings [%d]:\n", bonding_cnt);
489         while (bondings[i].bonding && i<bonding_cnt) {
490           PDEBUG("\t%s\n", bondings[i].bonding);
491           i++;
492         }
493       } else {
494         PDEBUG("No bondings exists.\n");
495       }
496     }
497 #endif
498 #endif
499
500     /* We have bonded devices but none has positioning bit set. Try
501      * to find out if any of the devices is known to be a BT device.
502      */
503     if (bonding_cnt>0 && num_posdev == 0) {
504
505       /* For each bonded device, get its name */
506       i = 0;
507       while (i<bonding_cnt && bondings[i].bonding) {
508         proxy = dbus_g_proxy_new_for_name(bus,
509             BLUEZ_DBUS, bondings[i].adapter, ADAPTER_INTERFACE);
510
511         tmp = NULL;
512         error = NULL;
513         if(dbus_g_proxy_call(proxy, GET_REMOTE_NAME, &error,
514               G_TYPE_STRING, bondings[i].bonding, G_TYPE_INVALID,
515               G_TYPE_STRING, &tmp, G_TYPE_INVALID)
516             && !error && tmp && *tmp) {
517           PDEBUG("Checking device name: %s\n", tmp);
518           if (check_device_name(tmp)) {
519
520             /* Found a GPS device */
521             posdev = (bonding_t *)realloc(posdev,
522                     (num_posdev+1)*sizeof(bonding_t));
523             if (!posdev) {
524               st = -1;
525               errno = ENOMEM;
526               goto OUT;
527             }
528         
529             posdev[num_posdev].bonding=strdup(bondings[i].bonding);
530             posdev[num_posdev].adapter=bondings[i].adapter;
531             num_posdev++;
532
533             PDEBUG("Addr=%s, (adapter=%s), Name=\"%s\"\n",
534                    bondings[i].bonding, bondings[i].adapter, tmp);
535           }
536         }
537         g_object_unref(proxy);
538         i++;
539       }
540     }
541
542
543   } else {  /* if (!bda) */
544
545     /* Caller supplied BT address so use it */
546     num_posdev = 1;
547     posdev = calloc(1, sizeof(bonding_t *));
548     if (!posdev) {
549       st = -1;
550       errno = ENOMEM;
551       goto OUT;
552     }
553     posdev[0].bonding = strdup(bda);
554
555     /* Adapter information is not needed */
556     posdev[0].adapter = "<not avail>";
557   }
558
559
560   /* For each bondend BT GPS device, try to create rfcomm */
561   for (i=0; i<num_posdev; i++) {
562     /* Note that bluez does not provide this interface (its defined but not
563      * yet implemented) so we use btcond for creating rfcomm device(s)
564      */
565     proxy = dbus_g_proxy_new_for_name(bus,
566         BTCOND_DBUS, BTCOND_PATH, BTCOND_INTERFACE);
567
568     error = NULL;
569     tmp = NULL;
570     if(!dbus_g_proxy_call(proxy, BTCOND_CONNECT, &error,
571           G_TYPE_STRING, posdev[i].bonding,
572           G_TYPE_STRING, spp,
573 #ifdef USE_AUTOMATIC_DISCONNECT
574                        G_TYPE_BOOLEAN, TRUE,
575 #else
576                        G_TYPE_BOOLEAN, FALSE,
577 #endif
578           G_TYPE_INVALID,
579           G_TYPE_STRING, &tmp,
580           G_TYPE_INVALID)
581         || error || !tmp || !*tmp) {
582       PDEBUG("dbus_g_proxy_call returned an error: (error=(%d,%s), tmp=%s\n",
583           error ? error->code : -1,
584           error ? error->message : "<null>",
585           tmp ? tmp : "<null>");
586
587       /* No error if already connected */
588       if (error && !strstr(error->message,
589             "com.nokia.btcond.error.connected")) {
590
591       ERROR:
592         ERRSTR("Cannot send msg (service=%s, object=%s, interface=%s, "
593                "method=%s) [%s]\n",
594                BTCOND_DBUS,
595                BTCOND_PATH,
596                BTCOND_INTERFACE,
597                BTCOND_CONNECT,
598                error->message ? error->message : "<no error msg>");
599         continue;
600
601       } else if(!tmp || !*tmp) {
602
603         /* hack: rfcommX device name is at the end of error message */
604         char *last_space = strstr(error->message, " rfcomm");
605         if (!last_space) {
606           goto ERROR;
607         }
608
609         g_free(tmp);
610         tmp = g_strdup_printf("/dev/%s", last_space+1);
611       }
612     }
613     g_object_unref(proxy);
614
615     if (tmp && tmp[0]) {
616       rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
617       if (!rfcomms) {
618         st = -1;
619         errno = ENOMEM;
620         goto OUT;
621       }
622       rfcomms[num_rfcomms] = tmp;
623       num_rfcomms++;
624
625       PDEBUG("BT addr=%s, RFCOMM %s now exists (adapter=%s)\n",
626               posdev[i].bonding, tmp, posdev[i].adapter);
627
628       tmp = NULL;
629     }
630     else {
631       g_free(tmp);
632     }
633   }
634
635   if (num_rfcomms==0) {
636     /* serial device creation failed */
637     ERRSTR("No rfcomm %s\n", "created");
638     st = -1;
639     errno = EINVAL;
640
641   } else {
642
643     /* Add null at the end */
644     rfcomms = (char **)realloc(rfcomms, (num_rfcomms+1)*sizeof(char *));
645     if (!rfcomms) {
646       st = -1;
647       errno = ENOMEM;
648
649     } else {
650
651       rfcomms[num_rfcomms] = NULL;
652
653 #ifndef USE_AUTOMATIC_DISCONNECT
654       ctx->rfcomms = rfcomms; /* freed in gpsbt_stop() */
655 #endif
656
657       /* Just start the beast (to be done if everything is ok) */
658       st = gpsmgr_start(gpsd_prog, rfcomms, gpsd_ctrl_sock,
659               gpsd_debug_level, port, &ctx->mgr);
660       if (!st) {
661         /* everything is ok */
662         goto OUT;
663       }
664     }
665   }
666
667  OUT:
668   if (adapters) {
669     g_strfreev(adapters);
670   }
671
672   if (posdev) {
673     for (i=0; i<num_posdev; i++) {
674       if (posdev[i].bonding) {
675         free(posdev[i].bonding);
676         memset(&posdev[i], 0, sizeof(bonding_t)); /* just in case */
677       }
678     }
679     free(posdev);
680     posdev = 0;
681   }
682
683   if (bondings) {
684     for (i=0; i<num_bondings; i++) {
685       if (bondings[i].bonding) {
686         free(bondings[i].bonding);
687         memset(&bondings[i], 0, sizeof(bonding_t)); /* just in case */
688       }
689     }
690     free(bondings);
691     bondings = 0;
692   }
693
694 #ifdef USE_AUTOMATIC_DISCONNECT
695   if (rfcomms) {
696     for (i=0; i<num_rfcomms; i++) {
697       if (rfcomms[i]) {
698         free(rfcomms[i]);
699         rfcomms[i]=0;
700       }
701     }
702     free(rfcomms);
703     rfcomms = 0;
704   }
705 #endif
706
707   if (bus) {
708     dbus_g_connection_unref(bus);
709   }
710
711   return st;
712 }
713
714
715 /* ----------------------------------------------------------------------- */
716 extern int gpsbt_stop(gpsbt_t *ctx)
717 {
718   int st;
719
720   if (!ctx) {
721     errno = EINVAL;
722     return -1;
723   }
724
725   st = gpsmgr_stop(&ctx->mgr);
726
727
728 #ifndef USE_AUTOMATIC_DISCONNECT
729   /* We need to disconnect from rfcomm device */
730   if (ctx->rfcomms) {
731     int i = 0;
732     int skip_dbus = 0;
733     DBusGConnection *bus = NULL;
734     DBusGProxy *proxy = NULL;
735     GError *error = NULL;
736
737     bus = get_dbus_gconn(&error);
738     if (!bus) {
739       errno = ECONNREFUSED; /* close enough :) */
740       PDEBUG("Cannot get reply message [%s]\n", error->message);
741       skip_dbus = 1;
742     }
743
744     if (!skip_dbus) {
745       /* Make sure there is no other user for gpsd, if there is then
746        * we must not delete rfcomm devices. The st==0 would mean that
747        * we are the only one using the dev.
748        */
749       if (st>0) {
750         skip_dbus = 1;
751         PDEBUG("Skipping rfcomm device deletion as we are "
752                 "not the only location user\n");
753       }
754     }
755
756     while (ctx->rfcomms[i]) {
757
758       if (!skip_dbus) {
759         /* Disconnect the device */
760         proxy = dbus_g_proxy_new_for_name(bus,
761             BTCOND_DBUS, BTCOND_PATH, BTCOND_INTERFACE);
762         error = NULL;
763         if(!dbus_g_proxy_call(proxy, BTCOND_DISCONNECT, &error,
764               G_TYPE_STRING, ctx->rfcomms[i], G_TYPE_INVALID, G_TYPE_INVALID)
765             || error){
766           PDEBUG("Cannot send msg (service=%s, object=%s, interface=%s, "
767            "method=%s) [%s]\n",
768                  BTCOND_DBUS,
769                  BTCOND_PATH,
770                  BTCOND_INTERFACE,
771                  BTCOND_DISCONNECT,
772                  error->message ? error->message : "<no error msg>");
773         }
774         g_object_unref(proxy);
775       }
776
777       free(ctx->rfcomms[i]);
778       ctx->rfcomms[i]=0;
779       i++;
780     }
781
782     if (bus) {
783       dbus_g_connection_unref(bus);
784     }
785
786     free(ctx->rfcomms);
787     ctx->rfcomms = 0;
788   }
789 #endif /* automatic disconnect */
790
791   return st;
792 }
793
794 #endif