From 25a58d23e81211f6bc761133e380a73e93476893 Mon Sep 17 00:00:00 2001
From: Apertis CI <devel@lists.apertis.org>
Date: Sat, 6 Mar 2021 10:56:40 +0000
Subject: [PATCH] Import Upstream version 2.5.7

---
 .gitlab-ci.yml                                |  20 +-
 HACKING.md                                    |  83 +++++++
 NEWS                                          |  55 ++++
 README                                        |  14 --
 README.md                                     |  74 ++++++
 data/geoclue.5.in                             | 171 +++++++++++++
 data/geoclue.conf.in                          |   9 +-
 data/meson.build                              |   7 +
 demo/meson.build                              |   6 +-
 docs/geoclue-docs.xml                         |   8 +-
 docs/lib/libgeoclue-sections.txt              |   6 +
 docs/meson.build                              |  49 ++--
 {src => interface}/create-unified-xml.py      |   0
 {src => interface}/fi.w1.wpa_supplicant1.xml  |   0
 interface/meson.build                         |  95 +++++++
 {src => interface}/net.hadess.SensorProxy.xml |   0
 .../org.freedesktop.GeoClue2.Agent.xml        |   0
 .../org.freedesktop.GeoClue2.Client.xml       |   2 +-
 .../org.freedesktop.GeoClue2.Location.xml     |   0
 .../org.freedesktop.GeoClue2.Manager.xml      |   0
 libgeoclue/gclue-helpers.c                    | 221 ++++++++++++++--
 libgeoclue/gclue-helpers.h                    |  14 ++
 libgeoclue/gclue-simple.c                     |  13 +-
 libgeoclue/meson.build                        |  58 ++---
 meson.build                                   |  11 +-
 public-api/gclue-enums.h                      |  12 +
 src/agent/meson.build                         |  16 --
 src/gclue-client-info.c                       |   1 +
 src/gclue-config.c                            |  13 +-
 src/gclue-location-source.c                   |   5 +-
 src/gclue-locator.c                           |   5 +-
 src/gclue-min-uint.c                          |   2 +
 src/gclue-modem-manager.c                     |   2 +-
 src/gclue-mozilla.c                           | 117 +++++----
 src/gclue-nmea-source.c                       |   9 +-
 src/gclue-service-client.c                    |  16 +-
 src/gclue-service-manager.c                   |   4 +
 src/gclue-wifi.c                              | 235 +++++++++++-------
 src/meson.build                               |  87 +------
 39 files changed, 1068 insertions(+), 372 deletions(-)
 create mode 100644 HACKING.md
 delete mode 100644 README
 create mode 100644 README.md
 create mode 100644 data/geoclue.5.in
 rename {src => interface}/create-unified-xml.py (100%)
 rename {src => interface}/fi.w1.wpa_supplicant1.xml (100%)
 create mode 100644 interface/meson.build
 rename {src => interface}/net.hadess.SensorProxy.xml (100%)
 rename {src/agent => interface}/org.freedesktop.GeoClue2.Agent.xml (100%)
 rename {src => interface}/org.freedesktop.GeoClue2.Client.xml (98%)
 rename {src => interface}/org.freedesktop.GeoClue2.Location.xml (100%)
 rename {src => interface}/org.freedesktop.GeoClue2.Manager.xml (100%)
 delete mode 100644 src/agent/meson.build

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 575d294..070da72 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,10 @@
 before_script:
     -  sed -i '/^#\sdeb-src /s/^#//' '/etc/apt/sources.list'
-    - apt-get update && apt-get build-dep --yes geoclue-2.0
-    - apt-get install --yes git gobject-introspection libmm-glib-dev wget libnotify-dev xsltproc gtk-doc-tools python3-pip ninja-build gettext modemmanager-dev
-    - pip3 install meson
+    - apt-get --allow-unauthenticated update && apt-get build-dep --yes geoclue-2.0
+    - apt-get install --yes git gobject-introspection libmm-glib-dev wget
+    - apt-get install --yes libnotify-dev xsltproc gtk-doc-tools python3-pip
+    - apt-get install --yes ninja-build gettext modemmanager-dev
+    - pip3 install meson==0.53.2
 
 # Ubuntu 14.04 is not supported, see README for details
 #
@@ -17,20 +19,20 @@ ubuntu-16.04:
             - "${CI_PROJECT_DIR}/build"
     script: meson -Dgtk-doc=false build && ninja -C build && ninja -C build test && ninja -C build install
 
-ubuntu-17.10:
-    image: ubuntu:artful
+ubuntu-18.04:
+    image: ubuntu:bionic
     artifacts:
         when: always
-        name: "artful-${CI_COMMIT_REF_NAME}"
+        name: "bionic-${CI_COMMIT_REF_NAME}"
         paths:
             - "${CI_PROJECT_DIR}/build"
     script: meson build && ninja -C build && ninja -C build test && ninja -C build install
 
-ubuntu-18.04:
+ubuntu-18.04-no-backend:
     image: ubuntu:bionic
     artifacts:
         when: always
-        name: "bionic-${CI_COMMIT_REF_NAME}"
+        name: "bionic-no-backend-${CI_COMMIT_REF_NAME}"
         paths:
             - "${CI_PROJECT_DIR}/build"
-    script: meson build && ninja -C build && ninja -C build test && ninja -C build install
+    script: meson -Denable-backend=false build && ninja -C build && ninja -C build test && ninja -C build install
diff --git a/HACKING.md b/HACKING.md
new file mode 100644
index 0000000..ef63ca0
--- /dev/null
+++ b/HACKING.md
@@ -0,0 +1,83 @@
+# Building Geoclue
+
+- The following are the dependencies needed to build Geoclue2. But If Geoclue2
+  is already included in your distro/OS, you should be able to use the
+  package manager's command to install all build depedndancies.
+
+  * gio (>= 2.44.0)
+  * gobject-introspection
+  * json-glib
+  * libsoup2.4 (>= 2.42)
+  * pkg-config
+
+  Fedora:
+
+  ```shell
+  sudo dnf builddep geoclue2
+  ```
+
+  Debian and Ubuntu:
+
+  ```shell
+  sudo apt build-dep geoclue-2.0
+  ```
+
+- For a full-fledged build, you also want ModemManager (mm-glib), 
+  avahi-client and avahi-glib. You want the latter two if you want to use the 
+  [geoclue-share app](https://wiki.gnome.org/Apps/GeoclueShare). You also need 
+  libnotify if you want to build the demo agent.
+
+  Fedora:
+
+  ```shell
+  sudo dnf install ModemManager-devel
+  sudo dnf install avahi-devel
+  sudo dnf install avahi-glib-devel
+  sudo dnf install libnotify-devel
+  ```
+
+  Debian and Ubuntu:
+
+  ```shell
+  sudo apt install modemmanager-dev
+  sudo apt install libavahi-client-dev
+  sudo apt install libavahi-glib-dev
+  sudo apt install libnotify-dev
+  ```
+
+- [Install meson](https://mesonbuild.com/Getting-meson.html).
+
+- Ensure you have a `geoclue` user on your system. If it already exists, you may
+  need to modify `/etc/passwd` file to make it a login user account by replacing
+  `/sbin/nologin` with `/bin/bash` (or the path to your preferred shell).
+
+- Build and install geoclue.
+
+  ```shell
+  meson --prefix=/usr --sysconfdir /etc -Ddbus-srv-user=geoclue build
+  # you may need to pass --libdir=/usr/lib64 on some systems (eg. Fedora)
+  ninja -C build
+  sudo ninja -C build install
+  ```
+
+- Then you can run it as:
+
+  ```shell
+  sudo su geoclue # Starts a new shell as `geoclue` user
+  G_MESSAGES_DEBUG=Geoclue /usr/libexec/geoclue
+  ```
+
+  If you get the following error, make sure `geoclue` process is not already
+  running:
+
+  ```
+  > Failed to acquire name 'org.freedesktop.GeoClue2' on system bus or lost it
+  ```
+
+- Now you can test if Geoclue is running and working:
+
+  ```shell
+  /usr/libexec/geoclue-2.0/demos/where-am-i
+  ```
+
+  It will give your current location.
diff --git a/NEWS b/NEWS
index db99b75..6b2856d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,58 @@
+2.5.7
+=====
+
+Many fixes. Can't bother to list them. You can get the list of changes from git.
+
+
+2.5.6
+=====
+
+- Fix crashes in WiFi handling code.
+- Plug a leak.
+
+Contributors:
+
+Amaury Pouly <amaury.pouly@gmail.com>
+Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+Will Thompson <will@willthompson.co.uk>
+Zeeshan Ali <zeeshanak@gnome.org>
+
+2.5.5
+=====
+
+- Plug another leak.
+- Fix another buffer overflow.
+- Fix WiFi-geolocation that got broken in 2.5.4.
+- Put freequently used small strings on the stack to avoid excessive memory
+  usage.
+
+2.5.4
+=====
+
+- Plug a leak that becomes pretty huge after a while of running Geoclue.
+- Fix a buffer-overflow.
+
+2.5.3
+=====
+
+- Fix a crash.
+- Support for GGA messages from more NMEA sources.
+- New API to allow automatic server side deletion of client.
+- Automatically delete client on server when using GClueSimple.
+- Avoid linking to system-installed library.
+- Fix library-only build.
+- Add manpage for geoclue.conf file.
+- Document usage and building of the project.
+- Other fixes and improvements.
+
+Contributors:
+
+Benjamin Berg <bberg@redhat.com>
+Inzamam <inzamam.15@cse.mrt.ac.lk>
+Sachin Chand <schand1997@gmail.com>
+Sumera Priyadarsini <sylphrenadin@gmail.com>
+Zeeshan Ali <zeeshanak@gnome.org>
+
 2.5.2
 =====
 
diff --git a/README b/README
deleted file mode 100644
index b7bb155..0000000
--- a/README
+++ /dev/null
@@ -1,14 +0,0 @@
-GeoClue: The Geoinformation Service
-===================================
-
-GeoClue is a D-Bus geoinformation service. The goal of the Geoclue project is to
-make creating location-aware applications as simple as possible.
-
-Geoclue is Free Software, licensed under GNU GPLv2+.
-
-# Troubleshooting and known limitations
-
-  * GeoClue requires Glib >= 2.44.0 which should make it hard to build to Ubuntu
-14.04. It's currently not supported, but all maintained Ubuntu versions >= 16.04
-are.
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0ea9657
--- /dev/null
+++ b/README.md
@@ -0,0 +1,74 @@
+Geoclue: The Geoinformation Service
+===================================
+
+Geoclue is a D-Bus geoinformation service. The goal of the Geoclue project
+is to make creating location-aware applications as simple as possible.
+
+Geoclue is Free Software, licensed under GNU GPLv2+.
+
+Geoclue comprises the following functionalities : 
+- WiFi-based geolocation (accuracy: in meters)
+- GPS(A) receivers (accuracy: in centimeters)
+- GPS of other devices on the local network, e.g smartphones (accuracy: 
+  in centimeters)
+- 3G modems (accuracy: in kilometers, unless modem has GPS)
+- GeoIP (accuracy: city-level)
+
+WiFi-based geolocation makes use of 
+[Mozilla Location Service](https://wiki.mozilla.org/CloudServices/Location). 
+
+If geoclue is unable to find you, you can easily fix that by installing 
+and running a 
+[simple app](https://wiki.mozilla.org/CloudServices/Location#Contributing) on 
+your phone. For using phone GPS, you'll need to install the latest version of 
+[GeoclueShare app](https://github.com/ankitstarski/GeoclueShare/releases)
+on your phone (currently, this is supported only on Android devices).
+
+Geoclue was also used for (reverse-)geocoding but that functionality has 
+been dropped in favour of the 
+[geocode-glib library](http://ftp.gnome.org/pub/GNOME/sources/geocode-glib/).
+
+# History
+Geoclue was started during the GNOME Summit 2006 in Boston. At least 
+Keith Preston and Tuomas Kuosmanen can be blamed. There was a total rewrite 
+after version 0.9. 
+
+Use tag "0.9" (as in git checkout 0.9) if you need the old code.
+
+There was yet another rewrite that we call geoclue2. The first version to 
+introduce the re-write was version 1.99.
+
+# Communication and Contribution
+
+- Discussions take place on the 
+[GNOME Discourse](https://discourse.gnome.org/c/platform).
+- The IRC chat for geoclue is on __#gnome-maps__ at irc.gimp.org .
+- Issues are tracked on 
+[Gitlab](https://gitlab.freedesktop.org/geoclue/geoclue/issues).
+
+# Get Source Code
+The source code is available as a tar-ball and in a Git repository.
+
+For latest release tarballs, use the `Download` option of Gitlab on the 
+[tag of your choice](https://gitlab.freedesktop.org/geoclue/geoclue/tags/).
+
+Older (than 2.4.13) releases are available 
+[here](http://www.freedesktop.org/software/geoclue/releases/2.4/).
+
+Git repository for Geoclue: https://gitlab.freedesktop.org/geoclue/geoclue
+  
+# Building Geoclue
+
+The guidelines for building geoclue have been documented 
+[here](https://gitlab.freedesktop.org/geoclue/geoclue/blob/master/HACKING.md). 
+
+# Using Geoclue in an application
+ 
+- __D-Bus API__: The documentation for using geoclue with D-Bus API is 
+[here](http://www.freedesktop.org/software/geoclue/docs/).
+- __Libgeoclue API documentation__:  The documentation is available 
+[here](https://www.freedesktop.org/software/geoclue/docs/libgeoclue/).
+- __C user application__: 
+[Here](https://gitlab.freedesktop.org/geoclue/geoclue/blob/master/demo/where-am-i.c)
+is an example showing a C application that uses 
+geoclue to locate its user. 
diff --git a/data/geoclue.5.in b/data/geoclue.5.in
new file mode 100644
index 0000000..b6a5795
--- /dev/null
+++ b/data/geoclue.5.in
@@ -0,0 +1,171 @@
+.TH "GEOCLUE CONFIGURATION" 5 
+.SH NAME
+geoclue.conf
+\-
+geoclue configuration parameters
+.SH SYNOPSIS
+.B @sysconfdir@/geoclue/geoclue.conf
+.SH DESCRIPTION
+.ad
+.fi
+The geoclue geoclue.conf configuration file specifies parameters that
+control the operation of geoclue.
+.PP
+All configurations settings below are mandatory and the defaults are
+what you see before you edit them in geoclue.conf. If you want to keep the default
+values around, copy and comment out the appropriate line(s) before
+changing them.
+.SH AGENT CONFIGURATION OPTIONS
+.B \fI[agent]
+is used to begin the agent configuration.
+.IP \fBwhitelist 
+.br
+Whitelist of desktop IDs (without .desktop part) of all agents we recognise,
+separated by a ';'.
+.IP 
+.B whitelist=geoclue-demo-agent;gnome-shell;io.elementary.desktop.agent-geoclue2
+.br
+.IP \fB[network-nmea]
+.br
+Network NMEA source configuration options
+.IP
+.B \fBenable=true 
+.br
+Fetch location from NMEA sources on local network?
+.br
+.IP \fB[3G]
+.br
+3G source configuration options
+.IP
+.B \fBenable=true 
+.br
+Enable 3G source
+.br
+.IP \fB[cdma]
+.br
+CDMA source configuration options
+.IP
+.B \fBenable=true 
+.br
+Enable CDMA source
+.br
+.IP \fB[modem-gps]
+.br
+Modem GPS source configuration options
+.IP
+.B \fBenable=true 
+.br
+Enable Modem-GPS source
+.br
+.IP \fB[wifi]
+.br
+WiFi source configuration options
+.IP
+.B \fBenable=true 
+.br
+Enable WiFi source
+.IP
+.B url=\fIhttps://location.services.mozilla.com/v1/geolocate?key=geoclue
+.br
+URL to the wifi geolocation service. The key can currenty be anything, just
+needs to be present but that is likely going to change in future.
+.IP
+.B submit-data=false
+Submit data to Mozilla Location Service
+.br
+If set to true, geoclue will automatically submit network data to Mozilla
+each time it gets a GPS lock.
+.IP
+.B submission-url=\fIhttps://location.services.mozilla.com/v1/submit?key=geoclue
+.br
+URL to submission API of Mozilla Location Service
+.IP
+.B submission-nick=geoclue
+.br
+A nickname to submit network data with. A nickname must be 2-32 characters long.
+.br
+.SH APPLICATION CONFIGURATION OPTIONS
+Having an entry here for an application with 
+.B allowed=true
+means that geoclue will not ask agent to authorize the application. This is to
+ensure that applications with built-in authorization mechanism (e.g web
+browsers) do not have to be bound to agents.
+.PP
+If your application is denied access to location information and your
+operating system doesn't provide any mechanism to change that, it is
+likely a bug in your operation system (or geoclue). The solution is to
+report the issue with all details, rather than adding your application
+to this list.
+.IP Format:
+.RS
+.B [random-app]
+.br
+Desktop ID of application without .desktop part
+.PP
+.B allowed=true|false
+.br
+Allowed access to location information?
+.PP
+.B system=true|false
+.br
+Is application a system component?
+.PP
+.B users=
+.br
+List of UIDs of all users for which this application is allowed location
+info access, separate by ';'. Keep it empty for allowing it for all users.
+.RE
+.IP Examples:
+.RS
+.B [gnome-datetime-panel]
+.br
+allowed=true
+.br
+system=true
+.br
+users=
+.PP
+.B [gnome-color-panel]
+.br
+allowed=true
+.br
+system=true
+.br
+users=
+.PP
+.B [org.gnome.Shell]
+.br
+allowed=true
+.br
+system=true
+.br
+users=
+.PP
+.B [io.elementary.desktop.agent-geoclue2]
+.br
+allowed=true
+.br
+system=true
+.br
+users=
+.PP
+.B [epiphany]
+.br
+allowed=true
+.br
+system=false
+.br
+users=
+.PP
+.B [firefox]
+.br
+allowed=true
+.br
+system=false
+.br
+users=
+.br
+.SH AUTHOR
+.na
+.nf
+Sachin Chand
diff --git a/data/geoclue.conf.in b/data/geoclue.conf.in
index 4b5b972..fb111de 100644
--- a/data/geoclue.conf.in
+++ b/data/geoclue.conf.in
@@ -66,18 +66,15 @@ submit-data=false
 # URL to submission API of Mozilla Location Service
 submission-url=https://location.services.mozilla.com/v1/submit?key=geoclue
 
-# A nickname to submit network data with. This is currently used for leaderboard:
-# https://location.services.mozilla.com/leaders
-# A nickname must be 2-32 characters long.
+# A nickname to submit network data with. A nickname must be 2-32 characters long.
 submission-nick=geoclue
 
 # Application configuration options
 #
 # NOTE: Having an entry here for an application with allowed=true means that
 #       geoclue will not ask agent to authorize the application. This is to
-#       ensure that system components and applications with built-in
-#       authorization mechanism (e.g web browsers) do not have to be bound to
-#       agents.
+#       ensure that applications with built-in authorization mechanism (e.g web
+#       browsers) do not have to be bound to agents.
 #
 #       If your application is denied access to location information and your
 #       operating system doesn't provide any mechanism to change that, it is
diff --git a/data/meson.build b/data/meson.build
index f826864..c189753 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -16,6 +16,7 @@ if get_option('enable-backend')
     conf = configuration_data()
     conf.set('libexecdir', libexecdir)
     conf.set('dbus_srv_user', get_option('dbus-srv-user'))
+    conf.set('sysconfdir', sysconfdir)
 
     service_dir = join_paths(datadir, 'dbus-1', 'system-services')
     configure_file(output: 'org.freedesktop.GeoClue2.service',
@@ -23,6 +24,12 @@ if get_option('enable-backend')
                    configuration: conf,
                    install_dir: service_dir)
 
+    man_file = configure_file(output: 'geoclue.5',
+                              input: 'geoclue.5.in',
+                              configuration: conf)
+
+    install_man(man_file)
+
     # DBus Service policy file
     dbus_service_dir = get_option('dbus-sys-dir')
     if dbus_service_dir == ''
diff --git a/demo/meson.build b/demo/meson.build
index 99c094f..1427fbe 100644
--- a/demo/meson.build
+++ b/demo/meson.build
@@ -29,18 +29,16 @@ endif
 
 if get_option('demo-agent')
     include_dirs = [ configinc,
-                     libgeoclue_public_api_inc,
-                     libgeoclue_agent_inc ]
+                     libgeoclue_public_api_inc ]
 
     sources = [ 'gclue-service-agent.h',
                 'gclue-service-agent.c',
                 'agent.c',
-                libgeoclue_agent_sources[1] ]
+                 geoclue_agent_sources ]
     deps = base_deps + [ dependency('libnotify') ]
     executable('agent',
                sources,
                include_directories: include_dirs,
-               link_whole: [ libgeoclue_agent ],
                dependencies: deps,
                install: true,
                install_dir: demo_dir)
diff --git a/docs/geoclue-docs.xml b/docs/geoclue-docs.xml
index bb720e6..c1c2268 100644
--- a/docs/geoclue-docs.xml
+++ b/docs/geoclue-docs.xml
@@ -63,9 +63,9 @@
 	Geoclue service.
       </para>
     </partintro>
-    <xi:include href="../src/docs-org.freedesktop.GeoClue2.Manager.xml"/>
-    <xi:include href="../src/docs-org.freedesktop.GeoClue2.Client.xml"/>
-    <xi:include href="../src/docs-org.freedesktop.GeoClue2.Location.xml"/>
+    <xi:include href="../interface/docs-org.freedesktop.GeoClue2.Manager.xml"/>
+    <xi:include href="../interface/docs-org.freedesktop.GeoClue2.Client.xml"/>
+    <xi:include href="../interface/docs-org.freedesktop.GeoClue2.Location.xml"/>
     <xi:include href="xml/gclue-enums.xml"/>
   </reference>
 
@@ -77,7 +77,7 @@
 	agents must implement.
       </para>
     </partintro>
-    <xi:include href="../src/agent/docs-org.freedesktop.GeoClue2.Agent.xml"/>
+    <xi:include href="../interface/docs-org.freedesktop.GeoClue2.Agent.xml"/>
   </reference>
 
   <index>
diff --git a/docs/lib/libgeoclue-sections.txt b/docs/lib/libgeoclue-sections.txt
index 83add2c..8352198 100644
--- a/docs/lib/libgeoclue-sections.txt
+++ b/docs/lib/libgeoclue-sections.txt
@@ -58,6 +58,9 @@ gclue_client_complete_stop
 gclue_client_proxy_create
 gclue_client_proxy_create_finish
 gclue_client_proxy_create_sync
+gclue_client_proxy_create_full
+gclue_client_proxy_create_full_finish
+gclue_client_proxy_create_full_sync
 gclue_client_proxy_new
 gclue_client_proxy_new_finish
 gclue_client_proxy_new_sync
@@ -85,6 +88,9 @@ GClueClientProxyPrivate
 GClueAccuracyLevel
 GCLUE_TYPE_ACCURACY_LEVEL
 gclue_accuracy_level_get_type
+GClueClientProxyCreateFlags
+GCLUE_TYPE_CLIENT_PROXY_CREATE_FLAGS
+gclue_client_proxy_create_flags_get_type
 <SUBSECTION Private>
 gclue_accuracy_level_build_string_from_mask
 gclue_accuracy_level_get_string
diff --git a/docs/meson.build b/docs/meson.build
index ebd49ea..8b44041 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -1,27 +1,28 @@
-if get_option('libgeoclue')
-    subdir('lib')
-endif
+if get_option('enable-backend')
+  conf = configuration_data()
+  conf.set_quoted('VERSION', gclue_version)
+  version_file = configure_file(output: 'version.xml',
+                                input: 'version.xml.in',
+                                configuration: conf)
 
-conf = configuration_data()
-conf.set_quoted('VERSION', gclue_version)
-version_file = configure_file(output: 'version.xml',
-                              input: 'version.xml.in',
-                              configuration: conf)
+  content_files = [ '../COPYING',
+                    geoclue_iface_sources ]
+  scan_options = [ '--ignore-headers=config.h',
+                   '--rebuild-sections',
+                   '--rebuild-types' ]
+  # Extra options to supply to gtkdoc-mkdb
+  mkdb_options = [ '--output-format=xml' ]
 
-content_files = [ '../COPYING',
-                  dbus_gen_src,
-                  libgeoclue_agent_sources ]
-scan_options = [ '--ignore-headers=config.h',
-                 '--rebuild-sections',
-                 '--rebuild-types' ]
-# Extra options to supply to gtkdoc-mkdb
-mkdb_options = [ '--output-format=xml' ]
+  gnome.gtkdoc('geoclue',
+               main_xml: 'geoclue-docs.xml',
+               content_files: content_files,
+               scan_args: scan_options,
+               src_dir: libgeoclue_public_api_inc,
+               mkdb_args: mkdb_options,
+               dependencies: libgeoclue_dep,
+               install: true)
+endif
 
-gnome.gtkdoc('geoclue',
-             main_xml: 'geoclue-docs.xml',
-             content_files: content_files,
-             scan_args: scan_options,
-             src_dir: libgeoclue_public_api_inc,
-             mkdb_args: mkdb_options,
-             dependencies: libgeoclue_dep,
-             install: true)
+if get_option('libgeoclue')
+    subdir('lib')
+endif
diff --git a/src/create-unified-xml.py b/interface/create-unified-xml.py
similarity index 100%
rename from src/create-unified-xml.py
rename to interface/create-unified-xml.py
diff --git a/src/fi.w1.wpa_supplicant1.xml b/interface/fi.w1.wpa_supplicant1.xml
similarity index 100%
rename from src/fi.w1.wpa_supplicant1.xml
rename to interface/fi.w1.wpa_supplicant1.xml
diff --git a/interface/meson.build b/interface/meson.build
new file mode 100644
index 0000000..9e230a7
--- /dev/null
+++ b/interface/meson.build
@@ -0,0 +1,95 @@
+dbus_interface_dir = join_paths(datadir, 'dbus-1', 'interfaces')
+
+geoclue_iface_sources = []
+
+# Client interface
+client_interface_xml = 'org.freedesktop.GeoClue2.Client.xml'
+geoclue_iface_sources += gnome.gdbus_codegen(
+    'gclue-client-interface',
+    client_interface_xml,
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClueDBus',
+    docbook: 'docs')
+# Location interface
+location_interface_xml = 'org.freedesktop.GeoClue2.Location.xml'
+geoclue_iface_sources += gnome.gdbus_codegen(
+    'gclue-location-interface',
+    location_interface_xml,
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClueDBus',
+    docbook: 'docs')
+# Manager interface
+manager_interface_xml = 'org.freedesktop.GeoClue2.Manager.xml'
+geoclue_iface_sources += gnome.gdbus_codegen(
+    'gclue-manager-interface',
+    manager_interface_xml,
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClueDBus',
+    docbook: 'docs')
+
+annotations = [[ 'fi.w1.wpa_supplicant1',
+                 'org.gtk.GDBus.C.Name',
+                 'WPA_Supplicant' ],
+               [ 'fi.w1.wpa_supplicant1.Interface',
+                 'org.gtk.GDBus.C.Name',
+                 'WPA_Interface' ],
+               [ 'fi.w1.wpa_supplicant1.BSS',
+                 'org.gtk.GDBus.C.Name',
+                 'WPA_BSS' ],
+               [ 'fi.w1.wpa_supplicant1.BSS:SSID',
+                 'org.gtk.GDBus.C.ForceGVariant',
+                 'whatever' ],
+               [ 'fi.w1.wpa_supplicant1.BSS:BSSID',
+                 'org.gtk.GDBus.C.ForceGVariant',
+                 'whatever' ],
+               [ 'fi.w1.wpa_supplicant1.Interface::BSSAdded',
+                 'org.gtk.GDBus.C.Name',
+                 'BSS_Added' ],
+               [ 'fi.w1.wpa_supplicant1.Interface::BSSRemoved',
+                 'org.gtk.GDBus.C.Name',
+                 'BSS_Removed' ]]
+
+geoclue_agent_sources = gnome.gdbus_codegen(
+    'geoclue-agent-interface',
+    'org.freedesktop.GeoClue2.Agent.xml',
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClue',
+    docbook: 'docs')
+geoclue_iface_sources += geoclue_agent_sources
+
+#libgeoclue_iface_inc = include_directories('.', '../..')
+
+if get_option('enable-backend')
+  wpa_supplicant_sources = gnome.gdbus_codegen(
+      'wpa_supplicant-interface',
+      'fi.w1.wpa_supplicant1.xml',
+      interface_prefix: 'fi.w1.wpa_supplicant1.',
+      annotations: annotations)
+
+  compass_iface_sources = gnome.gdbus_codegen(
+      'compass-interface',
+      'net.hadess.SensorProxy.xml',
+      interface_prefix: 'net.hadess.SensorProxy')
+endif
+
+install_data('org.freedesktop.GeoClue2.Agent.xml',
+             install_dir: dbus_interface_dir)
+
+interface_files = [ location_interface_xml,
+                    client_interface_xml,
+                    manager_interface_xml ]
+# Provide a single interface file too for backwards compatiblity.
+# At least gnome-settings-daemon currently relies on that.
+unified_interface_xml = 'org.freedesktop.GeoClue2.xml'
+python = find_program('python3')
+create_interface = find_program('create-unified-xml.py')
+cmd = [python, create_interface, '@OUTPUT@', '@INPUT@' ]
+
+custom_target('gclue-xml-interface',
+              input: interface_files,
+              output: unified_interface_xml,
+              install: true,
+              install_dir: dbus_interface_dir,
+              command: cmd)
+install_data(interface_files,
+             install_dir: dbus_interface_dir)
diff --git a/src/net.hadess.SensorProxy.xml b/interface/net.hadess.SensorProxy.xml
similarity index 100%
rename from src/net.hadess.SensorProxy.xml
rename to interface/net.hadess.SensorProxy.xml
diff --git a/src/agent/org.freedesktop.GeoClue2.Agent.xml b/interface/org.freedesktop.GeoClue2.Agent.xml
similarity index 100%
rename from src/agent/org.freedesktop.GeoClue2.Agent.xml
rename to interface/org.freedesktop.GeoClue2.Agent.xml
diff --git a/src/org.freedesktop.GeoClue2.Client.xml b/interface/org.freedesktop.GeoClue2.Client.xml
similarity index 98%
rename from src/org.freedesktop.GeoClue2.Client.xml
rename to interface/org.freedesktop.GeoClue2.Client.xml
index aae1d43..ff9ba33 100644
--- a/src/org.freedesktop.GeoClue2.Client.xml
+++ b/interface/org.freedesktop.GeoClue2.Client.xml
@@ -39,7 +39,7 @@
         Contains the current distance threshold in meters. This value is used
         by the service when it gets new location info. If the distance moved is
         below the threshold, it won't emit the LocationUpdated signal.
-        The default value is 0. When TimeThreshold is zero, it always emits
+        The default value is 0. When DistanceThreshold is zero, it always emits
         the signal.
     -->
     <property name="DistanceThreshold" type="u" access="readwrite">
diff --git a/src/org.freedesktop.GeoClue2.Location.xml b/interface/org.freedesktop.GeoClue2.Location.xml
similarity index 100%
rename from src/org.freedesktop.GeoClue2.Location.xml
rename to interface/org.freedesktop.GeoClue2.Location.xml
diff --git a/src/org.freedesktop.GeoClue2.Manager.xml b/interface/org.freedesktop.GeoClue2.Manager.xml
similarity index 100%
rename from src/org.freedesktop.GeoClue2.Manager.xml
rename to interface/org.freedesktop.GeoClue2.Manager.xml
diff --git a/libgeoclue/gclue-helpers.c b/libgeoclue/gclue-helpers.c
index 15ccc5b..bbb3809 100644
--- a/libgeoclue/gclue-helpers.c
+++ b/libgeoclue/gclue-helpers.c
@@ -35,20 +35,29 @@
  */
 
 typedef struct {
-        char              *desktop_id;
-        GClueAccuracyLevel accuracy_level;
+        char                        *desktop_id;
+        GClueAccuracyLevel           accuracy_level;
+        GClueClientProxyCreateFlags  flags;
 
+        GClueManager *manager;
         gulong notify_id;
 } ClientCreateData;
 
+typedef struct {
+        GClueManager  *manager;
+        char          *client_path;
+} ClientDestroyData;
+
 static ClientCreateData *
-client_create_data_new (const char        *desktop_id,
-                        GClueAccuracyLevel accuracy_level)
+client_create_data_new (const char                  *desktop_id,
+                        GClueAccuracyLevel           accuracy_level,
+                        GClueClientProxyCreateFlags  flags)
 {
         ClientCreateData *data = g_slice_new0 (ClientCreateData);
 
         data->desktop_id = g_strdup (desktop_id);
         data->accuracy_level = accuracy_level;
+        data->flags = flags;
 
         return data;
 }
@@ -56,10 +65,58 @@ client_create_data_new (const char        *desktop_id,
 static void
 client_create_data_free (ClientCreateData *data)
 {
+        g_clear_object (&data->manager);
         g_free (data->desktop_id);
         g_slice_free (ClientCreateData, data);
 }
 
+static ClientDestroyData *
+client_destroy_data_new (GClueManager *manager,
+                         const char   *client_path)
+{
+        ClientDestroyData *data = g_slice_new0 (ClientDestroyData);
+
+        if (manager)
+                data->manager = g_object_ref (manager);
+        data->client_path = g_strdup (client_path);
+
+        return data;
+}
+
+static void
+on_delete_client_finished (GObject      *source_object,
+                           GAsyncResult *res,
+                           gpointer      user_data)
+{
+        g_autoptr(GError) error = NULL;
+        ClientDestroyData *data = user_data;
+
+        if (!gclue_manager_call_delete_client_finish (
+                     GCLUE_MANAGER (source_object),
+                     res,
+                     &error)) {
+                g_warning ("GClue: Failed to automatically delete client: %s",
+                           error->message);
+        }
+
+        g_clear_object (&data->manager);
+        g_clear_pointer (&data->client_path, g_free);
+        g_slice_free (ClientDestroyData, data);
+}
+
+static void
+on_client_destroyed (gpointer data,
+                     GObject *where_the_object_was)
+{
+        ClientDestroyData *destroy_data = data;
+
+        gclue_manager_call_delete_client (destroy_data->manager,
+                                          destroy_data->client_path,
+                                          NULL,
+                                          on_delete_client_finished,
+                                          destroy_data);
+}
+
 static void
 on_client_proxy_ready (GObject      *source_object,
                        GAsyncResult *res,
@@ -67,6 +124,7 @@ on_client_proxy_ready (GObject      *source_object,
 {
         GTask *task = G_TASK (user_data);
         ClientCreateData *data;
+        ClientDestroyData *destroy;
         GClueClient *client;
         GError *error = NULL;
 
@@ -82,6 +140,16 @@ on_client_proxy_ready (GObject      *source_object,
         gclue_client_set_desktop_id (client, data->desktop_id);
         gclue_client_set_requested_accuracy_level (client, data->accuracy_level);
 
+        if (data->flags & GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE) {
+                destroy = client_destroy_data_new (
+                                  data->manager,
+                                  g_dbus_proxy_get_object_path (
+                                          G_DBUS_PROXY (client)));
+                g_object_weak_ref (G_OBJECT (client),
+                                   on_client_destroyed,
+                                   destroy);
+       }
+
         g_task_return_pointer (task, client, g_object_unref);
         g_object_unref (task);
 }
@@ -124,6 +192,7 @@ on_manager_proxy_ready (GObject      *source_object,
                         gpointer      user_data)
 {
         GTask *task = G_TASK (user_data);
+        ClientCreateData *data;
         GClueManager *manager;
         GError *error = NULL;
 
@@ -135,12 +204,30 @@ on_manager_proxy_ready (GObject      *source_object,
                 return;
         }
 
+        data = g_task_get_task_data (task);
+        data->manager = g_object_ref (manager);
         gclue_manager_call_get_client (manager,
                                        g_task_get_cancellable (task),
                                        on_get_client_ready,
                                        task);
 }
 
+static void
+on_client_proxy_full_finished (GObject      *source_object,
+                               GAsyncResult *res,
+                               gpointer      user_data)
+{
+        g_autoptr(GTask) task = user_data;
+        GClueClient *client;
+        GError *error = NULL;
+
+        client = gclue_client_proxy_create_finish (res, &error);
+        if (!client)
+                g_task_return_error (task, error);
+        else
+                g_task_return_pointer (task, client, g_object_unref);
+}
+
 /**
  * gclue_client_proxy_create:
  * @desktop_id: The desktop file id (the basename of the desktop file).
@@ -150,7 +237,11 @@ on_manager_proxy_ready (GObject      *source_object,
  * @user_data: User data to pass to @callback.
  *
  * A utility function to create a #GClueClientProxy without having to deal with
- * a #GClueManager.
+ * a #GClueManager. See also gclue_client_proxy_create_full() which improves
+ * resource management.
+ *
+ * This is identitcal to calling gclue_client_proxy_create_full() without any
+ * flags set.
  *
  * See #gclue_client_proxy_create_sync() for the synchronous, blocking version
  * of this function.
@@ -163,11 +254,102 @@ gclue_client_proxy_create (const char         *desktop_id,
                            gpointer            user_data)
 {
         GTask *task;
+
+        task = g_task_new (NULL, cancellable, callback, user_data);
+
+        gclue_client_proxy_create_full (desktop_id,
+                                        accuracy_level,
+                                        GCLUE_CLIENT_PROXY_CREATE_NONE,
+                                        cancellable,
+                                        on_client_proxy_full_finished,
+                                        task);
+}
+
+/**
+ * gclue_client_proxy_create_finish:
+ * @result: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
+ *          gclue_client_proxy_create().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with gclue_client_proxy_create().
+ *
+ * Returns: (transfer full) (type GClueClientProxy): The constructed proxy
+ * object or %NULL if @error is set.
+ */
+GClueClient *
+gclue_client_proxy_create_finish (GAsyncResult *result,
+                                  GError      **error)
+{
+        g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
+
+        return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+/**
+ * gclue_client_proxy_create_sync:
+ * @desktop_id: The desktop file id (the basename of the desktop file).
+ * @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * The synchronous and blocking version of #gclue_client_proxy_create().
+ * See also gclue_client_proxy_create_full_sync() which improves resource
+ * management.
+ *
+ * This function is identical to calling gclue_client_proxy_create_full_sync()
+ * without any flags set.
+ *
+ * Returns: (transfer full) (type GClueClientProxy): The constructed proxy
+ * object or %NULL if @error is set.
+ */
+GClueClient *
+gclue_client_proxy_create_sync (const char        *desktop_id,
+                                GClueAccuracyLevel accuracy_level,
+                                GCancellable      *cancellable,
+                                GError           **error)
+{
+        return gclue_client_proxy_create_full_sync (
+                       desktop_id,
+                       accuracy_level,
+                       GCLUE_CLIENT_PROXY_CREATE_NONE,
+                       cancellable,
+                       error);
+}
+
+/**
+ * gclue_client_proxy_create_full:
+ * @desktop_id: The desktop file id (the basename of the desktop file).
+ * @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
+ * @flags: #GClueClientProxyCreateFlags to modify the creation.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the results are ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * A utility function to create a #GClueClientProxy without having to deal with
+ * a #GClueManager.
+ *
+ * By setting the #GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE flag you can ensure
+ * that the client will be deleted again from the geoclue service when
+ * it is destroyed. This flag should be used unless you are doing explicit
+ * resource management.
+ *
+ * See #gclue_client_proxy_create_full_sync() for the synchronous, blocking
+ * version of this function.
+ */
+void
+gclue_client_proxy_create_full (const char                  *desktop_id,
+                                GClueAccuracyLevel           accuracy_level,
+                                GClueClientProxyCreateFlags  flags,
+                                GCancellable                *cancellable,
+                                GAsyncReadyCallback          callback,
+                                gpointer                     user_data)
+{
+        GTask *task;
         ClientCreateData *data;
 
         task = g_task_new (NULL, cancellable, callback, user_data);
 
-        data = client_create_data_new (desktop_id, accuracy_level);
+        data = client_create_data_new (desktop_id, accuracy_level, flags);
         g_task_set_task_data (task,
                               data,
                               (GDestroyNotify) client_create_data_free);
@@ -182,19 +364,19 @@ gclue_client_proxy_create (const char         *desktop_id,
 }
 
 /**
- * gclue_client_proxy_create_finish:
+ * gclue_client_proxy_create_full_finish:
  * @result: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
  *          gclue_client_proxy_create().
  * @error: Return location for error or %NULL.
  *
- * Finishes an operation started with gclue_client_proxy_create().
+ * Finishes an operation started with gclue_client_proxy_create_full().
  *
  * Returns: (transfer full) (type GClueClientProxy): The constructed proxy
  * object or %NULL if @error is set.
  */
 GClueClient *
-gclue_client_proxy_create_finish (GAsyncResult *result,
-                                  GError      **error)
+gclue_client_proxy_create_full_finish (GAsyncResult *result,
+                                       GError      **error)
 {
         g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
 
@@ -221,22 +403,29 @@ on_client_proxy_created (GObject      *source_object,
 }
 
 /**
- * gclue_client_proxy_create_sync:
+ * gclue_client_proxy_create_full_sync:
  * @desktop_id: The desktop file id (the basename of the desktop file).
  * @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
+ * @flags: #GClueClientProxyCreateFlags to modify the creation.
  * @cancellable: (allow-none): A #GCancellable or %NULL.
  * @error: Return location for error or %NULL.
  *
- * The synchronous and blocking version of #gclue_client_proxy_create().
+ * The synchronous and blocking version of #gclue_client_proxy_create_full().
+ *
+ * By setting the #GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE flag you can ensure
+ * that the client will be deleted again from the geoclue service when
+ * it is destroyed. This flag should be used unless you are doing explicit
+ * resource management.
  *
  * Returns: (transfer full) (type GClueClientProxy): The constructed proxy
  * object or %NULL if @error is set.
  */
 GClueClient *
-gclue_client_proxy_create_sync (const char        *desktop_id,
-                                GClueAccuracyLevel accuracy_level,
-                                GCancellable      *cancellable,
-                                GError           **error)
+gclue_client_proxy_create_full_sync (const char                 *desktop_id,
+                                     GClueAccuracyLevel          accuracy_level,
+                                     GClueClientProxyCreateFlags flags,
+                                     GCancellable               *cancellable,
+                                     GError                    **error)
 {
         GClueClient *client;
         ClientCreateSyncData *data = g_slice_new0 (ClientCreateSyncData);
diff --git a/libgeoclue/gclue-helpers.h b/libgeoclue/gclue-helpers.h
index 37997b0..f43b447 100644
--- a/libgeoclue/gclue-helpers.h
+++ b/libgeoclue/gclue-helpers.h
@@ -42,6 +42,20 @@ GClueClient *   gclue_client_proxy_create_sync   (const char         *desktop_id
                                                   GCancellable       *cancellable,
                                                   GError            **error);
 
+void            gclue_client_proxy_create_full        (const char                   *desktop_id,
+                                                       GClueAccuracyLevel            accuracy_level,
+                                                       GClueClientProxyCreateFlags   flags,
+                                                       GCancellable                 *cancellable,
+                                                       GAsyncReadyCallback           callback,
+                                                       gpointer                      user_data);
+GClueClient *   gclue_client_proxy_create_full_finish (GAsyncResult                 *result,
+                                                       GError                      **error);
+GClueClient *   gclue_client_proxy_create_full_sync   (const char                   *desktop_id,
+                                                       GClueAccuracyLevel            accuracy_level,
+                                                       GClueClientProxyCreateFlags  flags,
+                                                       GCancellable                 *cancellable,
+                                                       GError                      **error);
+
 G_END_DECLS
 
 #endif /* #ifndef __GCLUE_HELPERS_H__*/
diff --git a/libgeoclue/gclue-simple.c b/libgeoclue/gclue-simple.c
index 8facc7e..33958e0 100644
--- a/libgeoclue/gclue-simple.c
+++ b/libgeoclue/gclue-simple.c
@@ -308,7 +308,7 @@ on_client_created (GObject      *source_object,
         GClueSimplePrivate *priv = simple->priv;
         GError *error = NULL;
 
-        priv->client = gclue_client_proxy_create_finish (res, &error);
+        priv->client = gclue_client_proxy_create_full_finish (res, &error);
         if (error != NULL) {
                 g_task_return_error (task, error);
                 g_clear_object (&priv->task);
@@ -341,11 +341,12 @@ gclue_simple_init_async (GAsyncInitable     *initable,
 
         task = g_task_new (initable, cancellable, callback, user_data);
 
-        gclue_client_proxy_create (simple->priv->desktop_id,
-                                   simple->priv->accuracy_level,
-                                   cancellable,
-                                   on_client_created,
-                                   task);
+        gclue_client_proxy_create_full (simple->priv->desktop_id,
+                                        simple->priv->accuracy_level,
+                                        GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE,
+                                        cancellable,
+                                        on_client_created,
+                                        task);
 }
 
 static gboolean
diff --git a/libgeoclue/meson.build b/libgeoclue/meson.build
index ef2761f..e228ec3 100644
--- a/libgeoclue/meson.build
+++ b/libgeoclue/meson.build
@@ -1,29 +1,29 @@
-# FIXME: meson 0.46 doesn't seem to be actually installing the headers
-# generated by gnome.gdbus_codegen:
-#
-# https://github.com/mesonbuild/meson/pull/3487
-
 # Client interface
-gclue_client = gnome.gdbus_codegen('gclue-client',
-                               '../src/org.freedesktop.GeoClue2.Client.xml',
-                               interface_prefix: 'org.freedesktop.GeoClue2.',
-                               namespace: 'GClue',
-                               install_header: true,
-                               install_dir: include_subdir)
+gclue_client = gnome.gdbus_codegen(
+    'gclue-client',
+    '../interface/org.freedesktop.GeoClue2.Client.xml',
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClue',
+    install_header: true,
+    install_dir: include_subdir)
+
 # Location interface
-gclue_location = gnome.gdbus_codegen('gclue-location',
-                               '../src/org.freedesktop.GeoClue2.Location.xml',
-                               interface_prefix: 'org.freedesktop.GeoClue2.',
-                               namespace: 'GClue',
-                               install_header: true,
-                               install_dir: include_subdir)
+gclue_location = gnome.gdbus_codegen(
+    'gclue-location',
+    '../interface/org.freedesktop.GeoClue2.Location.xml',
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClue',
+    install_header: true,
+    install_dir: include_subdir)
+
 # Manager interface
-gclue_manager = gnome.gdbus_codegen('gclue-manager',
-                               '../src/org.freedesktop.GeoClue2.Manager.xml',
-                               interface_prefix: 'org.freedesktop.GeoClue2.',
-                               namespace: 'GClue',
-                               install_header: true,
-                               install_dir: include_subdir)
+gclue_manager = gnome.gdbus_codegen(
+    'gclue-manager',
+    '../interface/org.freedesktop.GeoClue2.Manager.xml',
+    interface_prefix: 'org.freedesktop.GeoClue2.',
+    namespace: 'GClue',
+    install_header: true,
+    install_dir: include_subdir)
 
 libgeoclue_sources = files('gclue-helpers.c', 'gclue-simple.c')
 libgeoclue_sources += gclue_client[0]
@@ -52,6 +52,11 @@ libgeoclue = library('geoclue-2',
                      version: '0.0.0',
                      install: true)
 
+libgeoclue_dep = declare_dependency(link_with: libgeoclue,
+                                    include_directories: include_dirs,
+                                    dependencies: base_deps,
+                                    sources: [ libgeoclue_sources, libgeoclue_headers ])
+
 gir = find_program('g-ir-scanner', required: false)
 vapigen = find_program('vapigen', required: false)
 enable_gir = get_option('introspection')
@@ -68,9 +73,8 @@ if gir.found() and enable_gir
                                identifier_prefix: 'GClue',
                                symbol_prefix: 'gclue',
                                export_packages: 'libgeoclue-' + gclue_api_version,
-                               dependencies: base_deps,
+                               dependencies: [libgeoclue_dep] + base_deps,
                                includes: [ 'GObject-2.0', 'Gio-2.0' ],
-                               include_directories: include_dirs,
                                install: true,
                                header: 'geoclue.h',
                                extra_args: [ '--quiet' ])
@@ -92,7 +96,3 @@ pkgconf.generate(version: gclue_version,
                  subdirs: [ header_dir ],
                  requires: pkg_requirements)
 
-libgeoclue_dep = declare_dependency(link_with: libgeoclue,
-                                    include_directories: include_dirs,
-                                    dependencies: base_deps,
-                                    sources: [ libgeoclue_sources, libgeoclue_headers ])
diff --git a/meson.build b/meson.build
index d738ef6..f0ffe8b 100644
--- a/meson.build
+++ b/meson.build
@@ -1,4 +1,4 @@
-project('geoclue', 'c', version: '2.5.2', meson_version : '>= 0.47.2')
+project('geoclue', 'c', version: '2.5.7', meson_version : '>= 0.47.2')
 
 gclue_version = meson.project_version()
 ver_arr = gclue_version.split('.')
@@ -25,8 +25,8 @@ conf.set_quoted('PACKAGE_NAME', 'geoclue')
 conf.set_quoted('GETTEXT_PACKAGE', 'geoclue')
 conf.set_quoted('PACKAGE_TARNAME', 'geoclue')
 conf.set_quoted('PACKAGE_STRING', 'geoclue ' + gclue_version)
-conf.set_quoted('PACKAGE_URL', 'http://www.freedesktop.org/wiki/Software/GeoClue')
-conf.set_quoted('PACKAGE_BUGREPORT', 'http://bugs.freedesktop.org/enter_bug.cgi?product=GeoClue')
+conf.set_quoted('PACKAGE_URL', 'https://gitlab.freedesktop.org/geoclue/geoclue/wikis/home')
+conf.set_quoted('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/geoclue/geoclue/issues/new')
 conf.set_quoted('TEST_SRCDIR', meson.source_root() + '/data/')
 conf.set_quoted('LOCALEDIR', localedir)
 conf.set_quoted('SYSCONFDIR', sysconfdir)
@@ -50,6 +50,7 @@ if libm.found()
 endif
 
 subdir('public-api')
+subdir('interface')
 if get_option('enable-backend')
     subdir('src')
 endif
@@ -72,9 +73,11 @@ if get_option('gtk-doc') and get_option('libgeoclue')
   subdir('docs')
 endif
 
+systemd_unit_dir = 'N/A'
+
 # FIXME: Remove this once meson does it itself: https://github.com/mesonbuild/meson/issues/757
 summary = '''
-        GeoClue @0@
+        Geoclue @0@
         =================
 
         prefix:                   @1@
diff --git a/public-api/gclue-enums.h b/public-api/gclue-enums.h
index d1a9881..33e499b 100644
--- a/public-api/gclue-enums.h
+++ b/public-api/gclue-enums.h
@@ -49,6 +49,18 @@ typedef enum {/*< underscore_name=gclue_accuracy_level>*/
 
 const char *gclue_accuracy_level_get_string (GClueAccuracyLevel val);
 
+/**
+ * GClueClientProxyCreateFlags:
+ * @GCLUE_CLIENT_PROXY_CREATE_NONE: Empty set of create flags
+ * @GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE:
+ *      Automatically delete the client from the server when the #GClueClient is
+ *      destroyed. This flag should usually be set.
+ **/
+typedef enum {/*< underscore_name=gclue_client_proxy_create_flags>*/
+        GCLUE_CLIENT_PROXY_CREATE_NONE        = 0,
+        GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE = 1 << 0,
+} GClueClientProxyCreateFlags;
+
 G_END_DECLS
 
 #endif /* GCLUE_ENUMS_H */
diff --git a/src/agent/meson.build b/src/agent/meson.build
deleted file mode 100644
index 781fefe..0000000
--- a/src/agent/meson.build
+++ /dev/null
@@ -1,16 +0,0 @@
-libgeoclue_agent_sources = gnome.gdbus_codegen(
-    'geoclue-agent-interface',
-    'org.freedesktop.GeoClue2.Agent.xml',
-    interface_prefix: 'org.freedesktop.GeoClue2.',
-    namespace: 'GClue',
-    docbook: 'docs')
-
-libgeoclue_agent_inc = include_directories('.', '../..')
-libgeoclue_agent = static_library('geoclue-agent',
-                                  libgeoclue_agent_sources,
-                                  dependencies: base_deps,
-                                  include_directories: libgeoclue_agent_inc,
-                                  install: false)
-
-install_data('org.freedesktop.GeoClue2.Agent.xml',
-             install_dir: dbus_interface_dir)
diff --git a/src/gclue-client-info.c b/src/gclue-client-info.c
index 4aab453..d609b34 100644
--- a/src/gclue-client-info.c
+++ b/src/gclue-client-info.c
@@ -74,6 +74,7 @@ gclue_client_info_finalize (GObject *object)
                 priv->watch_id = 0;
         }
 
+        g_clear_object (&priv->dbus_proxy);
         g_clear_pointer (&priv->bus_name, g_free);
         g_clear_pointer (&priv->xdg_id, g_free);
         g_clear_object (&priv->connection);
diff --git a/src/gclue-config.c b/src/gclue-config.c
index d259c71..0714d01 100644
--- a/src/gclue-config.c
+++ b/src/gclue-config.c
@@ -232,7 +232,8 @@ load_wifi_config (GClueConfig *config)
                                                 "url",
                                                 &error);
         if (error != NULL) {
-                g_warning ("%s", error->message);
+                g_debug ("Failed to get config \"wifi/url\": %s",
+                         error->message);
                 g_clear_error (&error);
                 priv->wifi_url = g_strdup (DEFAULT_WIFI_URL);
         }
@@ -242,7 +243,7 @@ load_wifi_config (GClueConfig *config)
                                                     "submit-data",
                                                     &error);
         if (error != NULL) {
-                g_debug ("Failed to get config wifi/submit-data: %s",
+                g_debug ("Failed to get config \"wifi/submit-data\": %s",
                          error->message);
                 g_error_free (error);
 
@@ -254,8 +255,9 @@ load_wifi_config (GClueConfig *config)
                                                        "submission-url",
                                                        &error);
         if (error != NULL) {
-                g_debug ("No wifi submission URL: %s", error->message);
-                g_error_free (error);
+                g_debug ("Failed to get config \"wifi/submission-url\": %s",
+                         error->message);
+                g_clear_error (&error);
                 priv->wifi_submit_url = g_strdup (DEFAULT_WIFI_SUBMIT_URL);
         }
 
@@ -264,7 +266,8 @@ load_wifi_config (GClueConfig *config)
                                                         "submission-nick",
                                                         &error);
         if (error != NULL) {
-                g_debug ("No wifi submission nick: %s", error->message);
+                g_debug ("Failed to get config \"wifi/submission-nick\": %s",
+                         error->message);
                 g_error_free (error);
         }
 }
diff --git a/src/gclue-location-source.c b/src/gclue-location-source.c
index 79c78b7..4ae4c57 100644
--- a/src/gclue-location-source.c
+++ b/src/gclue-location-source.c
@@ -192,6 +192,7 @@ gclue_location_source_finalize (GObject *object)
 
         gclue_location_source_stop (GCLUE_LOCATION_SOURCE (object));
         g_clear_object (&priv->location);
+        g_clear_object (&priv->time_threshold);
 
         G_OBJECT_CLASS (gclue_location_source_parent_class)->finalize (object);
 }
@@ -290,7 +291,7 @@ start_source (GClueLocationSource *source)
         if (source->priv->active_counter > 1) {
                 g_debug ("%s already active, not starting.",
                          G_OBJECT_TYPE_NAME (source));
-                return FALSE;
+                return TRUE;
         }
 
         if (source->priv->compute_movement) {
@@ -313,7 +314,7 @@ stop_source (GClueLocationSource *source)
         if (source->priv->active_counter == 0) {
                 g_debug ("%s already inactive, not stopping.",
                          G_OBJECT_TYPE_NAME (source));
-                return FALSE;
+                return TRUE;
         }
 
         source->priv->active_counter--;
diff --git a/src/gclue-locator.c b/src/gclue-locator.c
index a049fe5..650be43 100644
--- a/src/gclue-locator.c
+++ b/src/gclue-locator.c
@@ -301,8 +301,6 @@ gclue_locator_finalize (GObject *gsource)
         GList *node;
         GClueMinUINT *threshold;
 
-        G_OBJECT_CLASS (gclue_locator_parent_class)->finalize (gsource);
-
         threshold = gclue_location_source_get_time_threshold
                         (GCLUE_LOCATION_SOURCE (locator));
         g_signal_handlers_disconnect_by_func
@@ -325,7 +323,10 @@ gclue_locator_finalize (GObject *gsource)
         }
         g_list_free_full (priv->sources, g_object_unref);
         priv->sources = NULL;
+        g_list_free (priv->active_sources);
         priv->active_sources = NULL;
+
+        G_OBJECT_CLASS (gclue_locator_parent_class)->finalize (gsource);
 }
 
 static void
diff --git a/src/gclue-min-uint.c b/src/gclue-min-uint.c
index bc75e9a..3d88f89 100644
--- a/src/gclue-min-uint.c
+++ b/src/gclue-min-uint.c
@@ -181,6 +181,8 @@ gclue_min_uint_get_value (GClueMinUINT *muint)
                 }
         }
 
+        g_list_free (values);
+
         return value;
 }
 
diff --git a/src/gclue-modem-manager.c b/src/gclue-modem-manager.c
index 66f883a..411492f 100644
--- a/src/gclue-modem-manager.c
+++ b/src/gclue-modem-manager.c
@@ -523,7 +523,7 @@ clear_caps (GClueModemManager    *manager,
 
         return mm_modem_location_setup_sync (priv->modem_location,
                                              priv->caps,
-                                             FALSE,
+                                             TRUE,
                                              cancellable,
                                              error);
 }
diff --git a/src/gclue-mozilla.c b/src/gclue-mozilla.c
index 6d644a4..ffdb77c 100644
--- a/src/gclue-mozilla.c
+++ b/src/gclue-mozilla.c
@@ -40,58 +40,66 @@
  * its easy to switch to Google's API.
  **/
 
-static char *
-variant_to_string (GVariant *variant, guint *len)
+#define BSSID_LEN 7
+#define BSSID_STR_LEN 18
+#define MAX_SSID_LEN 32
+
+static guint
+variant_to_string (GVariant *variant, guint max_len, char *ret)
 {
-        guint n_bytes, i;
-        char *ret;
+        guint i;
+        guint len;
 
-        n_bytes = g_variant_n_children (variant);
-        if (len != NULL)
-                *len = n_bytes;
-        if (n_bytes <= 0)
-                return NULL;
-        ret = g_malloc (n_bytes + 1);
-        ret[n_bytes] = '\0';
+        len = g_variant_n_children (variant);
+        if (len == 0)
+                return 0;
+        g_return_val_if_fail(len < max_len, 0);
+        ret[len] = '\0';
 
-        for (i = 0; i < n_bytes; i++)
+        for (i = 0; i < len; i++)
                 g_variant_get_child (variant,
                                      i,
                                      "y",
                                      &ret[i]);
 
-        return ret;
+        return len;
 }
 
-static char *
-get_ssid_from_bss (WPABSS *bss)
+static guint
+get_ssid_from_bss (WPABSS *bss, char *ssid)
 {
         GVariant *variant = wpa_bss_get_ssid (bss);
+        if (variant == NULL)
+                return 0;
 
-        return variant_to_string (variant, NULL);
+        return variant_to_string (variant, MAX_SSID_LEN, ssid);
 }
 
-static char *
-get_bssid_from_bss (WPABSS *bss)
+static gboolean
+get_bssid_from_bss (WPABSS *bss, char *bssid)
 {
         GVariant *variant;
-        char *raw_bssid;
-        char *bssid;
-        guint raw_len, len, i, j;
+        char raw_bssid[BSSID_LEN] = { 0 };
+        guint raw_len, i;
 
         variant = wpa_bss_get_bssid (bss);
+        if (variant == NULL)
+                return FALSE;
+
+        raw_len = variant_to_string (variant, BSSID_LEN, raw_bssid);
+        g_return_val_if_fail (raw_len == BSSID_LEN - 1, FALSE);
 
-        raw_bssid = variant_to_string (variant, &raw_len);
-        len = raw_len * 2 + raw_len;
-        bssid = g_malloc (len);
-        for (i = 0, j = 0; i < len; i = i + 3, j++)
-                g_snprintf (bssid + i,
-                            4,
-                           "%02x:",
-                           (unsigned char) raw_bssid[j]);
-        bssid[len - 1] = '\0';
-
-        return bssid;
+        for (i = 0; i < BSSID_LEN - 1; i++) {
+                unsigned char c = (unsigned char) raw_bssid[i];
+
+                if (i == BSSID_LEN - 2) {
+                        g_snprintf (bssid + (i * 3), 3, "%02x", c);
+                } else {
+                        g_snprintf (bssid + (i * 3), 4, "%02x:", c);
+                }
+        }
+
+        return TRUE;
 }
 
 static const char *
@@ -116,13 +124,28 @@ gclue_mozilla_create_query (GList        *bss_list, /* As in Access Points */
         char *data;
         gsize data_len;
         const char *uri;
+        guint n_non_ignored_bsss;
+        GList *iter;
 
         builder = json_builder_new ();
         json_builder_begin_object (builder);
 
         /* We send pure geoip query using empty object if both bss_list and
          * tower are NULL.
+         *
+         * If the list of non-ignored BSSs is <2, don’t bother submitting the
+         * BSS list as MLS will only do a geoip lookup anyway.
+         * See https://ichnaea.readthedocs.io/en/latest/api/geolocate.html#field-definition
          */
+        n_non_ignored_bsss = 0;
+        for (iter = bss_list; iter != NULL; iter = iter->next) {
+                WPABSS *bss = WPA_BSS (iter->data);
+
+                if (gclue_mozilla_should_ignore_bss (bss))
+                        continue;
+
+                n_non_ignored_bsss++;
+        }
 
         if (tower != NULL) {
                 json_builder_set_member_name (builder, "radioType");
@@ -147,15 +170,13 @@ gclue_mozilla_create_query (GList        *bss_list, /* As in Access Points */
                 json_builder_end_array (builder);
         }
 
-        if (bss_list != NULL) {
-                GList *iter;
-
+        if (n_non_ignored_bsss >= 2) {
                 json_builder_set_member_name (builder, "wifiAccessPoints");
                 json_builder_begin_array (builder);
 
                 for (iter = bss_list; iter != NULL; iter = iter->next) {
                         WPABSS *bss = WPA_BSS (iter->data);
-                        char *mac;
+                        char mac[BSSID_STR_LEN] = { 0 };
                         gint16 strength_dbm;
 
                         if (gclue_mozilla_should_ignore_bss (bss))
@@ -163,9 +184,8 @@ gclue_mozilla_create_query (GList        *bss_list, /* As in Access Points */
 
                         json_builder_begin_object (builder);
                         json_builder_set_member_name (builder, "macAddress");
-                        mac = get_bssid_from_bss (bss);
+                        get_bssid_from_bss (bss, mac);
                         json_builder_add_string_value (builder, mac);
-                        g_free (mac);
 
                         json_builder_set_member_name (builder, "signalStrength");
                         strength_dbm = wpa_bss_get_signal (bss);
@@ -329,7 +349,7 @@ gclue_mozilla_create_submit_query (GClueLocation   *location,
 
                 for (iter = bss_list; iter != NULL; iter = iter->next) {
                         WPABSS *bss = WPA_BSS (iter->data);
-                        char *mac;
+                        char mac[BSSID_STR_LEN] = { 0 };
                         gint16 strength_dbm;
                         guint16 frequency;
 
@@ -338,9 +358,8 @@ gclue_mozilla_create_submit_query (GClueLocation   *location,
 
                         json_builder_begin_object (builder);
                         json_builder_set_member_name (builder, "key");
-                        mac = get_bssid_from_bss (bss);
+                        get_bssid_from_bss (bss, mac);
                         json_builder_add_string_value (builder, mac);
-                        g_free (mac);
 
                         json_builder_set_member_name (builder, "signal");
                         strength_dbm = wpa_bss_get_signal (bss);
@@ -409,18 +428,22 @@ out:
 gboolean
 gclue_mozilla_should_ignore_bss (WPABSS *bss)
 {
-        char *ssid, *bssid;
+        char ssid[MAX_SSID_LEN] = { 0 };
+        char bssid[BSSID_STR_LEN] = { 0 };
+        guint len;
+
+        if (!get_bssid_from_bss (bss, bssid)) {
+                g_debug ("Ignoring WiFi AP with unknown BSSID..");
+                return TRUE;
+        }
 
-        ssid = get_ssid_from_bss (bss);
-        bssid = get_bssid_from_bss (bss);
-        if (ssid == NULL || g_str_has_suffix (ssid, "_nomap")) {
+        len = get_ssid_from_bss (bss, ssid);
+        if (len == 0 || g_str_has_suffix (ssid, "_nomap")) {
                 g_debug ("SSID for WiFi AP '%s' missing or has '_nomap' suffix."
                          ", Ignoring..",
                          bssid);
                 return TRUE;
         }
-        g_free (ssid);
-        g_free (bssid);
 
         return FALSE;
 }
diff --git a/src/gclue-nmea-source.c b/src/gclue-nmea-source.c
index c3a211b..c57da68 100644
--- a/src/gclue-nmea-source.c
+++ b/src/gclue-nmea-source.c
@@ -482,8 +482,13 @@ on_read_gga_sentence (GObject      *object,
         }
         g_debug ("Network source sent: \"%s\"", message);
 
-        if (!g_str_has_prefix (message, "$GPGGA")) {
-                /* FIXME: Handle other useful NMEA sentences too */
+        if (!g_str_has_prefix (message, "$GAGGA") &&  /* Galieo */
+            !g_str_has_prefix (message, "$GBGGA") &&  /* BeiDou */
+            !g_str_has_prefix (message, "$BDGGA") &&  /* BeiDou */
+            !g_str_has_prefix (message, "$GLGGA") &&  /* GLONASS */
+            !g_str_has_prefix (message, "$GNGGA") &&  /* GNSS (combined) */
+            !g_str_has_prefix (message, "$GPGGA") &&  /* GPS, SBAS, QZSS */
+            !g_str_has_prefix (message, "$QZGGA")) {  /* QZSS */
                 g_debug ("Ignoring non-GGA sentence from NMEA source");
 
                 goto READ_NEXT_LINE;
diff --git a/src/gclue-service-client.c b/src/gclue-service-client.c
index 247fdb6..62ea932 100644
--- a/src/gclue-service-client.c
+++ b/src/gclue-service-client.c
@@ -447,6 +447,7 @@ handle_post_agent_check_auth (StartData *data)
         GClueConfig *config;
         GClueAppPerm app_perm;
         guint32 uid;
+        gboolean system_app;
 
         uid = gclue_client_info_get_user_id (priv->client_info);
         max_accuracy = gclue_agent_get_max_accuracy_level (priv->agent_proxy);
@@ -471,8 +472,11 @@ handle_post_agent_check_auth (StartData *data)
         app_perm = gclue_config_get_app_perm (config,
                                               data->desktop_id,
                                               priv->client_info);
+        system_app = (gclue_client_info_get_xdg_id (priv->client_info) == NULL);
 
-        if (app_perm == GCLUE_APP_PERM_ALLOWED) {
+        if (app_perm == GCLUE_APP_PERM_ALLOWED || system_app) {
+                /* Since we have no reliable way to identify system apps, no
+                 * need for auth for them. */
                 complete_start (data);
                 return;
         }
@@ -556,7 +560,6 @@ gclue_service_client_handle_start (GClueDBusClient       *client,
         const char *desktop_id;
         GClueAppPerm app_perm;
         guint32 uid;
-        gboolean system_app = FALSE;
 
         if (priv->locator != NULL) {
                 /* Already started */
@@ -569,7 +572,6 @@ gclue_service_client_handle_start (GClueDBusClient       *client,
         if (desktop_id == NULL) {
                 /* Non-xdg app */
                 desktop_id = gclue_dbus_client_get_desktop_id (client);
-                system_app = TRUE;
         }
 
         if (desktop_id == NULL) {
@@ -605,14 +607,6 @@ gclue_service_client_handle_start (GClueDBusClient       *client,
         data->accuracy_level = ensure_valid_accuracy_level
                 (data->accuracy_level, GCLUE_ACCURACY_LEVEL_EXACT);
 
-        if (system_app) {
-                /* Since we have no reliable way to identify system apps, no
-                 * need for auth for them. */
-                complete_start (data);
-
-                return TRUE;
-        }
-
         /* No agent == No authorization */
         if (priv->agent_proxy == NULL) {
                 /* Already a pending Start()? Denied! */
diff --git a/src/gclue-service-manager.c b/src/gclue-service-manager.c
index 1d66ec4..d7f5e55 100644
--- a/src/gclue-service-manager.c
+++ b/src/gclue-service-manager.c
@@ -258,6 +258,7 @@ on_client_info_new_ready (GObject      *source_object,
         GError *error = NULL;
         guint32 user_id;
         gint64 now;
+        gboolean system_app;
 
         info = gclue_client_info_new_finish (res, &error);
         if (info == NULL) {
@@ -277,7 +278,10 @@ on_client_info_new_ready (GObject      *source_object,
         agent_proxy = g_hash_table_lookup (priv->agents,
                                            GINT_TO_POINTER (user_id));
         now = g_get_monotonic_time ();
+
+        system_app = (gclue_client_info_get_xdg_id (info) == NULL);
         if (agent_proxy == NULL &&
+            !system_app &&
             now < (priv->init_time + AGENT_WAIT_TIMEOUT_USEC)) {
                 /* Its possible that geoclue was just launched on GetClient
                  * call, in which case agents need some time to register
diff --git a/src/gclue-wifi.c b/src/gclue-wifi.c
index 4dbfc7c..b06737d 100644
--- a/src/gclue-wifi.c
+++ b/src/gclue-wifi.c
@@ -29,11 +29,15 @@
 #include "gclue-mozilla.h"
 
 #define WIFI_SCAN_TIMEOUT_HIGH_ACCURACY 10
-/* Since this is only used for city-level accuracy, 5 minutes betweeen each
+/* Since this is only used for city-level accuracy, 5 minutes between each
  * scan is more than enough.
  */
 #define WIFI_SCAN_TIMEOUT_LOW_ACCURACY  300
 
+#define BSSID_LEN 7
+#define BSSID_STR_LEN 18
+#define MAX_SSID_LEN 32
+
 /**
  * SECTION:gclue-wifi
  * @short_description: WiFi-based geolocation
@@ -192,58 +196,60 @@ on_bss_added (WPAInterface *object,
               GVariant     *properties,
               gpointer      user_data);
 
-static char *
-variant_to_string (GVariant *variant, guint *len)
+static guint
+variant_to_string (GVariant *variant, guint max_len, char *ret)
 {
-        guint n_bytes, i;
-        char *ret;
+        guint i;
+        guint len;
 
-        n_bytes = g_variant_n_children (variant);
-        if (len != NULL)
-                *len = n_bytes;
-        if (n_bytes <= 0)
-                return NULL;
-        ret = g_malloc (n_bytes + 1);
-        ret[n_bytes] = '\0';
+        len = g_variant_n_children (variant);
+        if (len == 0)
+                return 0;
+        g_return_val_if_fail(len < max_len, 0);
+        ret[len] = '\0';
 
-        for (i = 0; i < n_bytes; i++)
+        for (i = 0; i < len; i++)
                 g_variant_get_child (variant,
                                      i,
                                      "y",
                                      &ret[i]);
 
-        return ret;
+        return len;
 }
 
-static char *
-get_ssid_from_bss (WPABSS *bss)
+static guint
+get_ssid_from_bss (WPABSS *bss, char *ssid)
 {
         GVariant *variant = wpa_bss_get_ssid (bss);
 
-        return variant_to_string (variant, NULL);
+        return variant_to_string (variant, MAX_SSID_LEN, ssid);
 }
 
-static char *
-get_bssid_from_bss (WPABSS *bss)
+static gboolean
+get_bssid_from_bss (WPABSS *bss, char *bssid)
 {
         GVariant *variant;
-        char *raw_bssid;
-        char *bssid;
-        guint raw_len, len, i, j;
+        char raw_bssid[BSSID_LEN] = { 0 };
+        guint raw_len, i;
 
         variant = wpa_bss_get_bssid (bss);
+        if (variant == NULL)
+                return FALSE;
+
+        raw_len = variant_to_string (variant, BSSID_LEN, raw_bssid);
+        g_return_val_if_fail (raw_len == BSSID_LEN - 1, FALSE);
 
-        raw_bssid = variant_to_string (variant, &raw_len);
-        len = raw_len * 2 + raw_len;
-        bssid = g_malloc (len);
-        for (i = 0, j = 0; i < len; i = i + 3, j++)
-                g_snprintf (bssid + i,
-                            4,
-                           "%02x:",
-                           (unsigned char) raw_bssid[j]);
-        bssid[len - 1] = '\0';
+        for (i = 0; i < BSSID_LEN - 1; i++) {
+                unsigned char c = (unsigned char) raw_bssid[i];
 
-        return bssid;
+                if (i == BSSID_LEN - 2) {
+                        g_snprintf (bssid + (i * 3), 3, "%02x", c);
+                } else {
+                        g_snprintf (bssid + (i * 3), 4, "%02x:", c);
+                }
+        }
+
+        return TRUE;
 }
 
 static void
@@ -256,12 +262,11 @@ add_bss_proxy (GClueWifi *wifi,
         if (g_hash_table_replace (wifi->priv->bss_proxies,
                                   g_strdup (path),
                                   bss)) {
-                char *ssid;
+                char ssid[MAX_SSID_LEN] = { 0 };
 
                 wifi->priv->bss_list_changed = TRUE;
-                ssid = get_ssid_from_bss (bss);
+                get_ssid_from_bss (bss, ssid);
                 g_debug ("WiFi AP '%s' added.", ssid);
-                g_free (ssid);
         }
 }
 
@@ -275,12 +280,13 @@ on_bss_signal_notify (GObject    *gobject,
         const char *path;
 
         if (wpa_bss_get_signal (bss) <= -90) {
-                char *bssid = get_bssid_from_bss (bss);
+                char bssid[BSSID_STR_LEN] = { 0 };
+
+                get_bssid_from_bss (bss, bssid);
                 g_debug ("WiFi AP '%s' still has very low strength (%u dBm)"
-                         ", ignoring again..",
+                         ", ignoring again…",
                          bssid,
                          wpa_bss_get_signal (bss));
-                g_free (bssid);
                 return;
         }
 
@@ -300,7 +306,7 @@ on_bss_proxy_ready (GObject      *source_object,
         GClueWifi *wifi = GCLUE_WIFI (user_data);
         WPABSS *bss;
         GError *error = NULL;
-        char *ssid;
+        char ssid[MAX_SSID_LEN] = { 0 };
 
         bss = wpa_bss_proxy_new_for_bus_finish (res, &error);
         if (bss == NULL) {
@@ -316,18 +322,18 @@ on_bss_proxy_ready (GObject      *source_object,
                 return;
         }
 
-        ssid = get_ssid_from_bss (bss);
+        get_ssid_from_bss (bss, ssid);
         g_debug ("WiFi AP '%s' added.", ssid);
-        g_free (ssid);
 
         if (wpa_bss_get_signal (bss) <= -90) {
                 const char *path;
-                char *bssid = get_bssid_from_bss (bss);
+                char bssid[BSSID_STR_LEN] = { 0 };
+
+                get_bssid_from_bss (bss, bssid);
                 g_debug ("WiFi AP '%s' has very low strength (%u dBm)"
-                         ", ignoring for now..",
+                         ", ignoring for now…",
                          bssid,
                          wpa_bss_get_signal (bss));
-                g_free (bssid);
                 g_signal_connect (G_OBJECT (bss),
                                   "notify::signal",
                                   G_CALLBACK (on_bss_signal_notify),
@@ -360,16 +366,15 @@ on_bss_added (WPAInterface *object,
 static gboolean
 remove_bss_from_hashtable (const gchar *path, GHashTable *hash_table)
 {
-        char *ssid;
+        char ssid[MAX_SSID_LEN] = { 0 };
         WPABSS *bss = NULL;
 
         bss = g_hash_table_lookup (hash_table, path);
         if (bss == NULL)
                 return FALSE;
 
-        ssid = get_ssid_from_bss (bss);
+        get_ssid_from_bss (bss, ssid);
         g_debug ("WiFi AP '%s' removed.", ssid);
-        g_free (ssid);
 
         g_hash_table_remove (hash_table, path);
 
@@ -388,6 +393,35 @@ on_bss_removed (WPAInterface *object,
         remove_bss_from_hashtable (path, priv->ignored_bss_proxies);
 }
 
+static void
+start_wifi_scan (GClueWifi *wifi)
+{
+        GClueWifiPrivate *priv = wifi->priv;
+        GVariantBuilder builder;
+        GVariant *args;
+
+        g_debug ("Starting WiFi scan…");
+
+        if (priv->scan_done_id == 0)
+                priv->scan_done_id = g_signal_connect
+                                        (priv->interface,
+                                         "scan-done",
+                                         G_CALLBACK (on_scan_done),
+                                         wifi);
+
+        g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+        g_variant_builder_add (&builder,
+                               "{sv}",
+                               "Type", g_variant_new ("s", "passive"));
+        args = g_variant_builder_end (&builder);
+
+        wpa_interface_call_scan (WPA_INTERFACE (priv->interface),
+                                 args,
+                                 NULL,
+                                 on_scan_call_done,
+                                 wifi);
+}
+
 static void
 cancel_wifi_scan (GClueWifi *wifi)
 {
@@ -410,33 +444,14 @@ on_scan_timeout (gpointer user_data)
 {
         GClueWifi *wifi = GCLUE_WIFI (user_data);
         GClueWifiPrivate *priv = wifi->priv;
-        GVariantBuilder builder;
-        GVariant *args;
 
-        if (priv->interface == NULL)
-                return FALSE;
-
-        g_debug ("WiFi scan timeout. Restarting-scan..");
+        g_debug ("WiFi scan timeout.");
         priv->scan_timeout = 0;
 
-        if (priv->scan_done_id == 0)
-                priv->scan_done_id = g_signal_connect
-                                        (priv->interface,
-                                         "scan-done",
-                                         G_CALLBACK (on_scan_done),
-                                         wifi);
-
-        g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
-        g_variant_builder_add (&builder,
-                               "{sv}",
-                               "Type", g_variant_new ("s", "passive"));
-        args = g_variant_builder_end (&builder);
+        if (priv->interface == NULL)
+                return G_SOURCE_REMOVE;
 
-        wpa_interface_call_scan (WPA_INTERFACE (priv->interface),
-                                 args,
-                                 NULL,
-                                 on_scan_call_done,
-                                 wifi);
+        start_wifi_scan (wifi);
 
         return FALSE;
 }
@@ -462,10 +477,19 @@ on_scan_done (WPAInterface *object,
 
         if (priv->bss_list_changed) {
                 priv->bss_list_changed = FALSE;
-                g_debug ("Refreshing location..");
+                g_debug ("Refreshing location…");
                 gclue_web_source_refresh (GCLUE_WEB_SOURCE (wifi));
         }
 
+        /* If there was another scan already scheduled, cancel that and
+         * re-schedule. Regardless of our internal book-keeping, this can happen
+         * if wpa_supplicant emits the `ScanDone` signal due to a scan being
+         * initiated by another client. */
+        if (priv->scan_timeout != 0) {
+                g_source_remove (priv->scan_timeout);
+                priv->scan_timeout = 0;
+        }
+
         /* With high-enough accuracy requests, we need to scan more often since
          * user's location can change quickly. With low accuracy, we don't since
          * we wouldn't want to drain power unnecessarily.
@@ -517,7 +541,7 @@ connect_bss_signals (GClueWifi *wifi)
                 return;
         }
 
-        on_scan_timeout (wifi);
+        start_wifi_scan (wifi);
 
         priv->bss_list_changed = TRUE;
         priv->bss_added_id = g_signal_connect (priv->interface,
@@ -545,14 +569,18 @@ disconnect_bss_signals (GClueWifi *wifi)
 {
         GClueWifiPrivate *priv = wifi->priv;
 
-        if (priv->bss_added_id == 0 || priv->interface == NULL)
-                return;
-
         cancel_wifi_scan (wifi);
-        g_signal_handler_disconnect (priv->interface, priv->bss_added_id);
-        priv->bss_added_id = 0;
-        g_signal_handler_disconnect (priv->interface, priv->bss_removed_id);
-        priv->bss_removed_id = 0;
+
+        if (priv->bss_added_id != 0) {
+                g_signal_handler_disconnect (priv->interface,
+                                             priv->bss_added_id);
+                priv->bss_added_id = 0;
+        }
+        if (priv->bss_removed_id != 0) {
+                g_signal_handler_disconnect (priv->interface,
+                                             priv->bss_removed_id);
+                priv->bss_removed_id = 0;
+        }
 
         g_hash_table_remove_all (priv->bss_proxies);
         g_hash_table_remove_all (priv->ignored_bss_proxies);
@@ -809,6 +837,7 @@ gclue_wifi_get_accuracy_level (GClueWifi *wifi)
         return wifi->priv->accuracy_level;
 }
 
+/* Can return NULL without setting @error, signifying an empty BSS list. */
 static GList *
 get_bss_list (GClueWifi *wifi,
               GError   **error)
@@ -829,10 +858,27 @@ gclue_wifi_create_query (GClueWebSource *source,
                          GError        **error)
 {
         GList *bss_list; /* As in Access Points */
+        SoupMessage *msg;
+        g_autoptr(GError) local_error = NULL;
 
-        bss_list = get_bss_list (GCLUE_WIFI (source), NULL);
+        bss_list = get_bss_list (GCLUE_WIFI (source), &local_error);
+        if (local_error != NULL) {
+                g_propagate_error (error, g_steal_pointer (&local_error));
+                return NULL;
+        }
+
+        /* Empty list? */
+        if (bss_list == NULL) {
+                g_set_error_literal (error,
+                                     G_IO_ERROR,
+                                     G_IO_ERROR_FAILED,
+                                     "No WiFi networks found");
+                return NULL;
+        }
 
-        return gclue_mozilla_create_query (bss_list, NULL, error);
+        msg = gclue_mozilla_create_query (bss_list, NULL, error);
+        g_list_free (bss_list);
+        return msg;
 }
 
 static GClueLocation *
@@ -849,13 +895,28 @@ gclue_wifi_create_submit_query (GClueWebSource  *source,
                                 GError         **error)
 {
         GList *bss_list; /* As in Access Points */
+        SoupMessage * msg;
+        g_autoptr(GError) local_error = NULL;
 
-        bss_list = get_bss_list (GCLUE_WIFI (source), error);
-        if (bss_list == NULL)
+        bss_list = get_bss_list (GCLUE_WIFI (source), &local_error);
+        if (local_error != NULL) {
+                g_propagate_error (error, g_steal_pointer (&local_error));
                 return NULL;
+        }
+
+        /* Empty list? */
+        if (bss_list == NULL) {
+                g_set_error_literal (error,
+                                     G_IO_ERROR,
+                                     G_IO_ERROR_FAILED,
+                                     "No WiFi networks found");
+                return NULL;
+        }
 
-        return gclue_mozilla_create_submit_query (location,
-                                                  bss_list,
-                                                  NULL,
-                                                  error);
+        msg = gclue_mozilla_create_submit_query (location,
+                                                 bss_list,
+                                                 NULL,
+                                                 error);
+        g_list_free (bss_list);
+        return msg;
 }
diff --git a/src/meson.build b/src/meson.build
index c0955de..e82245f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,74 +1,16 @@
-dbus_interface_dir = join_paths(datadir, 'dbus-1', 'interfaces')
-
-subdir('agent')
-
 geoclue_deps = base_deps + [ dependency('json-glib-1.0', version: '>= 0.14.0'),
                              dependency('libsoup-2.4', version: '>= 2.42.0') ]
 
-dbus_gen_src = []
-
-# Client interface
-client_interface_xml = 'org.freedesktop.GeoClue2.Client.xml'
-dbus_gen_src += gnome.gdbus_codegen(
-    'gclue-client-interface',
-    client_interface_xml,
-    interface_prefix: 'org.freedesktop.GeoClue2.',
-    namespace: 'GClueDBus',
-    docbook: 'docs')
-# Location interface
-location_interface_xml = 'org.freedesktop.GeoClue2.Location.xml'
-dbus_gen_src += gnome.gdbus_codegen(
-    'gclue-location-interface',
-    location_interface_xml,
-    interface_prefix: 'org.freedesktop.GeoClue2.',
-    namespace: 'GClueDBus',
-    docbook: 'docs')
-# Manager interface
-manager_interface_xml = 'org.freedesktop.GeoClue2.Manager.xml'
-dbus_gen_src += gnome.gdbus_codegen(
-    'gclue-manager-interface',
-    manager_interface_xml,
-    interface_prefix: 'org.freedesktop.GeoClue2.',
-    namespace: 'GClueDBus',
-    docbook: 'docs')
-sources = [ dbus_gen_src, libgeoclue_public_api_gen_sources[1] ]
-
-annotations = [[ 'fi.w1.wpa_supplicant1',
-                 'org.gtk.GDBus.C.Name',
-                 'WPA_Supplicant' ],
-               [ 'fi.w1.wpa_supplicant1.Interface',
-                 'org.gtk.GDBus.C.Name',
-                 'WPA_Interface' ],
-               [ 'fi.w1.wpa_supplicant1.BSS',
-                 'org.gtk.GDBus.C.Name',
-                 'WPA_BSS' ],
-               [ 'fi.w1.wpa_supplicant1.BSS:SSID',
-                 'org.gtk.GDBus.C.ForceGVariant',
-                 'whatever' ],
-               [ 'fi.w1.wpa_supplicant1.BSS:BSSID',
-                 'org.gtk.GDBus.C.ForceGVariant',
-                 'whatever' ],
-               [ 'fi.w1.wpa_supplicant1.Interface::BSSAdded',
-                 'org.gtk.GDBus.C.Name',
-                 'BSS_Added' ],
-               [ 'fi.w1.wpa_supplicant1.Interface::BSSRemoved',
-                 'org.gtk.GDBus.C.Name',
-                 'BSS_Removed' ]]
-sources += gnome.gdbus_codegen('wpa_supplicant-interface',
-                               'fi.w1.wpa_supplicant1.xml',
-                               interface_prefix: 'fi.w1.wpa_supplicant1.',
-                               annotations: annotations)
-
-sources += gnome.gdbus_codegen('compass-interface',
-                               'net.hadess.SensorProxy.xml',
-                               interface_prefix: 'net.hadess.SensorProxy')
+sources = [ libgeoclue_public_api_gen_sources[1],
+            geoclue_iface_sources,
+            wpa_supplicant_sources,
+            compass_iface_sources ]
 
 sources += gnome.genmarshal('gclue-marshal',
                             prefix: 'gclue_marshal',
                             sources: ['gclue-marshal.list'])
 
 include_dirs = [ configinc,
-                 libgeoclue_agent_inc,
                  libgeoclue_public_api_inc,
                  include_directories('..') ]
 
@@ -116,7 +58,7 @@ if get_option('nmea-source')
 endif
 
 c_args = [ '-DG_LOG_DOMAIN="Geoclue"' ]
-link_with = [ libgeoclue_public_api, libgeoclue_agent ]
+link_with = [ libgeoclue_public_api ]
 executable('geoclue',
            sources,
            link_with: link_with,
@@ -136,22 +78,3 @@ pkgconf.generate(version: gclue_version,
                  variables: [ 'apiversion=' + gclue_api_version,
                               'dbus_interface=' + dbus_interface,
                               'agent_dbus_interface=' + agent_dbus_interface ])
-
-interface_files = [ location_interface_xml,
-                    client_interface_xml,
-                    manager_interface_xml ]
-# Provide a single interface file too for backwards compatiblity.
-# At least gnome-settings-daemon currently relies on that.
-unified_interface_xml = 'org.freedesktop.GeoClue2.xml'
-python = find_program('python3')
-create_interface = find_program('create-unified-xml.py')
-cmd = [python, create_interface, '@OUTPUT@', '@INPUT@' ]
-
-custom_target('gclue-xml-interface',
-              input: interface_files,
-              output: unified_interface_xml,
-              install: true,
-              install_dir: dbus_interface_dir,
-              command: cmd)
-install_data(interface_files,
-             install_dir: dbus_interface_dir)
-- 
GitLab