Commit 659a5c45 authored by Matthieu Bouron's avatar Matthieu Bouron Committed by Philip Withnall

bluez: Add a Bluetooth Phonebook Access Profile backend using BlueZ 5

This pulls contacts out of a paired Bluetooth device and dumps them in
folks.

No test cases are included.

https://bugzilla.gnome.org/show_bug.cgi?id=685848

This bumps the Vala and GLib dependencies of folks, needed for the following
two fixes.
 • https://bugzilla.gnome.org/show_bug.cgi?id=710643https://bugzilla.gnome.org/show_bug.cgi?id=710726

https://bugzilla.gnome.org/show_bug.cgi?id=685848
parent 1af18e68
......@@ -2,9 +2,11 @@ Overview of changes from libfolks 0.9.5 to libfolks 0.9.6
=========================================================
Dependencies:
• GLib ≥ 2.37.6
• GLib ≥ 2.39.0
• Vala ≥ 0.22.0.28-9090
Major changes:
• Add a BlueZ backend
Bugs fixed:
• Bug 706683 — fails to build with Vala 0.20
......@@ -26,6 +28,7 @@ Bugs fixed:
• Bug 710869 — Disable some GCC warnings for generated C code
• Bug 708059 — build failure: fatal error: folks/folks.h: No such file or
directory
• Bug 685848 — Add a folks backend for bluez phonebook access
API changes:
......
......@@ -22,7 +22,12 @@ if ENABLE_OFONO
SUBDIRS += ofono
endif
if ENABLE_BLUEZ
SUBDIRS += bluez
endif
DIST_SUBDIRS = \
bluez \
eds \
key-file \
libsocialweb \
......
BACKEND_NAME = "bluez"
backenddir = $(BACKEND_DIR)/bluez
backend_LTLIBRARIES = bluez.la
bluez_la_VALAFLAGS = \
$(backend_valaflags) \
--pkg libebook-1.2 \
$(NULL)
bluez_la_SOURCES = \
$(backend_sources) \
bluez-backend.vala \
bluez-backend-factory.vala \
bluez-persona.vala \
bluez-persona-store.vala \
org-bluez-obex-client.vala \
org-bluez.vala \
$(NULL)
bluez_la_CPPFLAGS = \
$(backend_cppflags) \
$(NULL)
bluez_la_CFLAGS = \
$(backend_cflags) \
$(EBOOK_CFLAGS) \
$(NULL)
bluez_la_LIBADD = \
$(backend_libadd) \
$(EBOOK_LIBS) \
$(NULL)
bluez_la_LDFLAGS = \
-module -avoid-version \
$(backend_ldflags) \
$(NULL)
-include $(top_srcdir)/backends/backend.mk
-include $(top_srcdir)/git.mk
/*
* Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
* Copyright (C) 2009 Nokia Corporation.
* Copyright (C) 2012-2013 Collabora Ltd.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arun Raghavan <arun.raghavan@collabora.co.uk>
*
* Based on kf-backend-factory.vala by:
* Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
* Travis Reitter <travis.reitter@collabora.co.uk>
* Philip Withnall <philip.withnall@collabora.co.uk>
*/
using Folks;
using Folks.Backends.BlueZ;
private BackendFactory _backend_factory = null;
/**
* The backend module entry point.
*
* @param backend_store the {@link BackendStore} to use in this factory.
*
* @since UNRELEASED
*/
public void module_init (BackendStore backend_store)
{
_backend_factory = new BackendFactory (backend_store);
}
/**
* The backend module exit point.
*
* @param backend_store the {@link BackendStore} to use in this factory.
*
* @since UNRELEASED
*/
public void module_finalize (BackendStore backend_store)
{
_backend_factory = null;
}
/**
* A backend factory to create a single {@link Backend}.
*
* @since UNRELEASED
*/
public class Folks.Backends.BlueZ.BackendFactory : Object
{
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
public BackendFactory (BackendStore backend_store)
{
backend_store.add_backend (new Backend ());
}
}
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2010-2013 Collabora Ltd.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arun Raghavan <arun.raghavan@collabora.co.uk>
* Jeremy Whiting <jeremy.whiting@collabora.com>
* Simon McVittie <simon.mcvittie@collabora.co.uk>
* Matthieu Bouron <matthieu.bouron@collabora.com>
*
* Based on kf-persona.vala by:
* Philip Withnall <philip.withnall@collabora.co.uk>
*/
using GLib;
using Gee;
using Folks;
using Folks.Backends.BlueZ;
/**
* A persona subclass which represents a single persona from a simple key file.
*
* @since UNRELEASED
*/
public class Folks.Backends.BlueZ.Persona : Folks.Persona,
AvatarDetails,
EmailDetails,
NameDetails,
PhoneDetails,
UrlDetails
{
private StructuredName? _structured_name = null;
private string _full_name = "";
private string _nickname = "";
private Set<UrlFieldDetails>? _urls = null;
private Set<UrlFieldDetails>? _urls_ro = null;
private LoadableIcon? _avatar = null;
private HashSet<PhoneFieldDetails> _phone_numbers;
private Set<PhoneFieldDetails> _phone_numbers_ro;
private HashSet<EmailFieldDetails> _email_addresses;
private Set<EmailFieldDetails> _email_addresses_ro;
private const string[] _linkable_properties =
{
"phone-numbers",
"email-addresses"
};
private static string[] _writeable_properties = { };
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
public override string[] linkable_properties
{
get { return BlueZ.Persona._linkable_properties; }
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public Set<UrlFieldDetails> urls
{
get { return this._urls_ro; }
set { this.change_urls.begin (value); } /* not writeable */
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public LoadableIcon? avatar
{
get { return this._avatar; }
set { this.change_avatar.begin (value); }
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
public override string[] writeable_properties
{
get { return BlueZ.Persona._writeable_properties; }
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public Set<PhoneFieldDetails> phone_numbers
{
get { return this._phone_numbers_ro; }
set { this.change_phone_numbers.begin (value); } /* not writeable */
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public StructuredName? structured_name
{
get { return this._structured_name; }
set { this.change_structured_name.begin (value); } /* not writeable */
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public string full_name
{
get { return this._full_name; }
set { this.change_full_name.begin (value); } /* not writeable */
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public string nickname
{
get { return this._nickname; }
set { this.change_nickname.begin (value); } /* not writeable */
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
[CCode (notify = false)]
public Set<EmailFieldDetails> email_addresses
{
get { return this._email_addresses_ro; }
set { this.change_email_addresses.begin (value); } /* not writeable */
}
/**
* Create a new persona.
*
* Create a new persona for the {@link PersonaStore} ``store``, representing
* the Persona given by the group ``uid`` in the key file ``key_file``.
*
* @param vcf the VCard filename reference. For example: 0.vcf.
* @param name the Persona the contact name or alias.
* @param vcard the Vcard stored as a string.
* @param store the store to which the Persona belongs.
* @param is_user whether the Persona is the user itself or not.
*
* @since UNRELEASED
*/
public Persona (string vcf, string name, string vcard,
Folks.PersonaStore store, bool is_user)
{
var iid = Checksum.compute_for_string (ChecksumType.SHA1, vcard);
var uid = Folks.Persona.build_uid ("bluez", store.id, iid);
Object (display_id: name,
iid: iid,
uid: uid,
store: store,
is_user: is_user);
this._set_vcard (vcard);
}
construct
{
debug ("Adding BlueZ Persona '%s' (IID '%s', group '%s')", this.uid,
this.iid, this.display_id);
this._phone_numbers = new HashSet<PhoneFieldDetails> ();
this._phone_numbers_ro = this._phone_numbers.read_only_view;
this._email_addresses = new HashSet<EmailFieldDetails> ();
this._email_addresses_ro = this._email_addresses.read_only_view;
this._urls = new HashSet<UrlFieldDetails> ();
this._urls_ro = this._urls.read_only_view;
}
private void _set_vcard (string vcard)
{
E.VCard card = new E.VCard.from_string (vcard);
E.VCardAttribute? attribute = card.get_attribute ("TEL");
if (attribute != null)
{
this._phone_numbers.add (
new PhoneFieldDetails (attribute.get_value_decoded ().str));
}
attribute = card.get_attribute ("FN");
if (attribute != null)
{
this._full_name = attribute.get_value_decoded ().str;
}
attribute = card.get_attribute ("NICKNAME");
if (attribute != null)
{
this._nickname = attribute.get_value_decoded ().str;
}
attribute = card.get_attribute ("URL");
if (attribute != null)
{
var url = attribute.get_value_decoded ().str;
this._urls.add (new UrlFieldDetails (url));
}
attribute = card.get_attribute ("PHOTO");
if (attribute != null)
{
var encoded_data = (string) attribute.get_value ().data;
var bytes = new Bytes (Base64.decode (encoded_data));
this._avatar = new BytesIcon (bytes);
}
attribute = card.get_attribute ("N");
if (attribute != null)
{
string[] components = {"", "", "", "", ""};
uint components_size = 5;
unowned GLib.List<StringBuilder> values =
attribute.get_values_decoded ();
if (values.length () < components_size)
components_size = values.length ();
for (int i = 0; i < components_size; i++)
{
components[i] = values.nth_data (i).str;
}
this._structured_name = new StructuredName (components[0],
components[1], components[2], components[3], components[4]);
if (values.length () != 5)
{
debug ("Expected 5 components to N value of vcard, got %u",
values.length ());
}
}
attribute = card.get_attribute ("EMAIL");
if (attribute != null)
{
this._email_addresses.add (
new EmailFieldDetails (attribute.get_value_decoded ().str));
}
}
/**
* {@inheritDoc}
*
* @since UNRELEASED
*/
public override void linkable_property_to_links (string prop_name,
Folks.Persona.LinkablePropertyCallback callback)
{
if (prop_name == "phone-numbers")
{
foreach (var phone_number in this._phone_numbers)
{
if (phone_number.value != null)
callback (phone_number.value);
}
}
else if (prop_name == "email-addresses")
{
foreach (var email_address in this._email_addresses)
{
if (email_address.value != null)
callback (email_address.value);
}
}
else
{
/* Chain up */
base.linkable_property_to_links (prop_name, callback);
}
}
}
/*
* Copyright (C) 2012-2013 Collabora Ltd.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arun Raghavan <arun.raghavan@collabora.co.uk>
* Gustavo Padovan <gustavo.padovan@collabora.co.uk>
* Matthieu Bouron <matthieu.bouron@collabora.com>
*/
using GLib;
namespace org
{
namespace bluez
{
namespace obex
{
[DBus (name = "org.bluez.obex.Client1")]
public interface Client : Object
{
[DBus (name = "CreateSession")]
public async abstract ObjectPath create_session (string address,
HashTable<string, Variant> args) throws DBusError, IOError;
[DBus (name = "RemoveSession")]
public async abstract void remove_session (ObjectPath session)
throws DBusError, IOError;
}
[DBus (name = "org.bluez.obex.PhonebookAccess1")]
public interface PhonebookAccess : Object
{
/* Returned by List () */
public struct PhonebookEntry
{
public string vcard;
public string name;
}
public struct PhonebookPull
{
public ObjectPath path;
public HashTable<string, Variant> props;
}
[DBus (name = "Select")]
public abstract void select (string location, string phonebook)
throws DBusError, IOError;
[DBus (name = "List")]
public abstract PhonebookEntry[] list (
HashTable<string, Variant> filters)
throws DBusError, IOError;
[DBus (name = "ListFilterFields")]
public abstract string[] list_filter_fields ()
throws DBusError, IOError;
[DBus (name = "PullAll")]
public abstract void pull_all (string target,
HashTable<string, Variant> filters, out string path,
out HashTable<string, Variant> props)
throws DBusError, IOError;
}
[DBus (name = "org.bluez.obex.Transfer1")]
public interface Transfer : Object
{
[Dbus (name = "Cancel")]
public abstract void cancel () throws DBusError;
[Dbus (name = "Status")]
public abstract string status { owned get; }
[Dbus (name = "Session")]
public abstract ObjectPath session { owned get; }
[Dbus (name = "Name")]
public abstract string name { owned get; }
[Dbus (name = "Type")]
public abstract string transfer_type { owned get; }
[Dbus (name = "Time")]
public abstract int64 time { get; }
[Dbus (name = "Size")]
public abstract uint64 size { get; }
[Dbus (name = "Transferred")]
public abstract uint64 transferred { get; }
[Dbus (name = "Filename")]
public abstract string filename { owned get; }
}
}
}
}
/*
* Copyright (C) 2012-2013 Collabora Ltd.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arun Raghavan <arun.raghavan@collabora.co.uk>
* Gustavo Padovan <gustavo.padovan@collabora.co.uk>
* Matthieu Bouron <matthieu.bouron@collabora.com>
*/
using GLib;
/* Reference:
* http://git.kernel.org/cgit/bluetooth/bluez.git/tree/doc/device-api.txt */
namespace org
{
namespace bluez
{
[DBus (name = "org.bluez.Error")]
public errordomain Error
{
NOT_READY,
FAILED,
IN_PROGRESS,
ALREADY_CONNECTED,
NOT_CONNECTED,
DOES_NOT_EXIST,
CONNECT_FAILED,
NOT_SUPPORTED,
INVALID_ARGUMENTS,
AUTHENTICATION_CANCELED,
AUTHENTICATION_FAILED,
AUTHENTICATION_REJECTED,
AUTHENTICATION_TIMEOUT,
CONNECTION_ATTEMPT_FAILED
}
[DBus (name = "org.bluez.Device1")]
public interface Device : Object
{
/* Methods. */
[DBus (name = "Connect")]
public abstract void connect () throws org.bluez.Error;
[DBus (name = "Disconnect")]
public abstract void disconnect () throws org.bluez.Error;
[DBus (name = "DisconnectProfile")]
public abstract void disconnect_profile (string uuid) throws org.bluez.Error;
[DBus (name = "Pair")]
public abstract void pair () throws org.bluez.Error;
[DBus (name = "CancelPairing")]
public abstract void cancel_pairing () throws org.bluez.Error;
/* Properties. */
[DBus (name = "Address")]
public abstract string address { owned get; }
[DBus (name = "Name")]
public abstract string name { owned get; }
[DBus (name = "Icon")]
public abstract string icon { owned get; }
[DBus (name = "Class")]
public abstract uint32 bluetooth_class { owned get; }
[DBus (name = "Appearance")]
public abstract uint16 appearance { owned get; }
[DBus (name = "UUIDs")]
public abstract string[] uuids { owned get; }
[DBus (name = "Paired")]
public abstract bool paired { owned get; }
[DBus (name = "Connected")]
public abstract bool connected { owned get; }
[DBus (name = "Trusted")]
public abstract bool trusted { owned get; set; }
[DBus (name = "Blocked")]
public abstract bool blocked { owned get; set; }
[DBus (name = "Alias")]
public abstract string alias { owned get; set; }
[DBus (name = "Adapter")]
public abstract ObjectPath adapter { owned get; }
[DBus (name = "LegacyPairing")]
public abstract bool legacy_pairing { owned get; }
[DBus (name = "Modalias")]
public abstract string mod_alias { owned get; }
[DBus (name = "RSSI")]
public abstract int16 rssi { owned get; }
}
}
}
......@@ -119,6 +119,20 @@ AS_IF([test "x$enable_ofono_backend" = "xyes"], [
AM_CONDITIONAL([ENABLE_OFONO], [test "x$enable_ofono_backend" = "xyes"])
AC_ARG_ENABLE(bluez-backend,
AC_HELP_STRING([--enable-bluez-backend],
[ build the bluez backend]),
enable_bluez_backend=$enableval,
enable_bluez_backend=yes )
AS_IF([test "x$enable_bluez_backend" = "xyes"], [
AC_DEFINE(HAVE_BLUEZ, [1], [Define as 1 if you have the BlueZ backend])
], [
AC_DEFINE(HAVE_BLUEZ, [0], [Define as 1 if you have the BlueZ backend])
])
AM_CONDITIONAL([ENABLE_BLUEZ], [test "x$enable_bluez_backend" = "xyes"])
AC_ARG_ENABLE(telepathy-backend,
AC_HELP_STRING([--enable-telepathy-backend],
[ build the Telepathy backend]),
......@@ -183,8 +197,8 @@ AM_CONDITIONAL([ENABLE_LIBSOCIALWEB],
# Dependencies
# -----------------------------------------------------------
GLIB_REQUIRED=2.37.6
VALA_REQUIRED=0.17.6
GLIB_REQUIRED=2.39.0
VALA_REQUIRED=0.22.0.28-9090
VALADOC_REQUIRED=0.3.1
TRACKER_SPARQL_MAJOR=0.16
TRACKER_SPARQL_REQUIRED=0.15.2
......@@ -259,6 +273,10 @@ AS_IF([test x$enable_ofono_backend = xyes], [
PKG_CHECK_MODULES([EBOOK], [libebook-1.2 >= $EBOOK_REQUIRED])
])
AS_IF([test x$enable_bluez_backend = xyes], [
PKG_CHECK_MODULES([EBOOK], [libebook-1.2 >= $EBOOK_REQUIRED])
])
#
# Vala building options -- allows tarball builds without installing Vala
#
......@@ -354,6 +372,10 @@ AS_IF([test "x$enable_vala" = "xyes"], [
AS_IF([test x$enable_ofono_backend = xyes], [
VALA_CHECK_PACKAGES([libebook-1.2])
])
AS_IF([test x$enable_bluez_backend = xyes], [
VALA_CHECK_PACKAGES([libebook-1.2])
])
])
# this will set HAVE_INTROSPECTION
......@@ -657,6 +679,7 @@ AC_CONFIG_FILES([
backends/eds/Makefile
backends/eds/lib/Makefile
backends/ofono/Makefile
backends/bluez/Makefile