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